Weather routing: Difference between revisions

m
→‎{{header|Wren}}: Changed to Wren S/H
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(10 intermediate revisions by 3 users not shown)
Line 15:
{{trans|Julia}}
This runs in only 37 seconds which is surprisingly quick compared to Julia. However, I've just noticed that I'm using an out of date version of Julia (1.0.4) so hopefully the latest version will be able to close the gap.
<langsyntaxhighlight lang="go">package main
 
import (
Line 467:
fmt.Println("The route taking the least time found was:\n", tp.path, "\nwhich has duration",
int(tp.duration/60), "hours,", int(math.Round(math.Mod(tp.duration, 60))), "minutes.")
}</langsyntaxhighlight>
 
{{out}}
Line 478:
=={{header|Julia}}==
Brute force optimization search, practical for shorter path lengths, but would require a better algorithm for paths over twice this size.
<langsyntaxhighlight lang="julia">module SailingPolars
 
using DelimitedFiles
Line 861:
println("The route taking the least time found was:\n ", tp.path,
"\nwhich has duration $(div(tp.duration, 60)) hours, $(rem(tp.duration, 60)) minutes.")
</syntaxhighlight>
</lang>
The polar CSV file used for this solution, named polar.csv, is as follows. Note that this is a very detailed
polar, chosen to stress the testing of the code. Most polar files are far smaller,
Line 917:
</pre>
 
=={{header|PhixNim}}==
{{trans|Go}}
<lang Phix>-- demo/rosetta/Weather_Routing.exw
The Go version runs in about 44 seconds on my computer. This Nim version, compiled in release mode (which includes runtime checks), runs in 22 seconds (18 seconds if link time optimization is activated). When compiled without checks (“danger” mode), it runs in 15.5 seconds.
function to_numbers(sequence s)
for i=1 to length(s) do
s[i] = to_number(s[i])
end for
return s
end function
 
<syntaxhighlight lang="nim">import hashes, math, parsecsv, sequtils, sets, strutils, sugar
function getpolardata(string s)
--
-- A sailing polar file is a CSV file, with ';' used as the comma separator instead of a comma.
-- The first line of the file contains labels for the wind velocities that make up columns, and
-- the first entry of each row makes up a column of angle of sailing direction from wind in degrees
--
sequence lines = split_any(s,"\r\n",no_empty:=true),
winds = to_numbers(split(lines[1],";")[2..$]),
degrees = {}, speeds = {}
for i=2 to length(lines) do
sequence l = to_numbers(split(lines[i],";"))
if length(l)!=length(winds)+1 then ?9/0 end if
degrees = append(degrees,l[1])
speeds = append(speeds,l[2..$])
end for
return {winds, degrees, speeds}
end function
 
type
--
MatrixF = seq[seq[float]]
-- winds is a list of wind speeds
Pred = float -> bool
-- degrees is a list of angles in degrees of direction relative to the wind
-- (note 0 degrees is directly into the wind, 180 degrees is directly downwind)
-- each speeds[i] is an array of length(winds) for each degrees[i]
--
constant {winds, degrees, speeds} = getpolardata(get_text("polar.csv"))
-- (note the distributed version uses a literal string constant instead)
constant R = 6372800 -- Earth's approximate radius in meters
constant timeinterval = 10 -- the minutes duration for each TimeSlice
 
# Structure that represents a polar CSV file's data.
function deg2rad(atom deg) return remainder(deg*PI/180+2*PI,2*PI) end function
# Note 0 degrees is directly into the wind, 180 degrees is directly downwind.
function rad2deg(atom rad) return remainder (rad*(180/PI)+360,360) end function
SailingPolar = object
function sind(atom deg) return sin(deg2rad(deg)) end function
winds: seq[float] # Vector of windspeeds.
function cosd(atom deg) return cos(deg2rad(deg)) end function
degrees: seq[float] # Vector of angles in degrees of direction relative to the wind.
function asind(atom deg) return rad2deg(arcsin(deg)) end function
speeds: MatrixF # Matrix of sailing speeds indexed by wind velocity and angle of boat to wind.
function atand(atom x,y) return rad2deg(atan2(x,y)) end function
 
# Structure that represents wind and surface current direction and velocity for a given position.
function haversine(atom lat1, lon1, lat2, lon2)
# Angles in degrees, velocities in knots.
--
SurfaceParameters = tuple[windDeg, windKts, currentDeg, currentKts: float]
-- Calculate the haversine function for two points on the Earth's surface.
--
-- Given two latitude, longitude pairs in degrees for a point on the Earth,
-- get distance in meters and the initial direction of travel in degrees for
-- movement from point 1 to point 2.
--
atom dlat = lat2 - lat1,
dlon = lon2 - lon1,
a = power(sind(dlat/2),2) + cosd(lat1)*cosd(lat2)*power(sind(dlon/2),2),
c = 2.0 * asind(sqrt(a)),
theta = atand(sind(dlon)*cosd(lat2),
cosd(lat1)*sind(lat2) - sind(lat1)*cosd(lat2)*cosd(dlon))
theta = remainder(theta+360, 360)
return {R*c*0.5399565, theta}
end function
 
function findfirst(atom v, sequence s)
-- Returns the index of the first element of s >= v
for i=1 to length(s) do
if s[i]>=v then return i end if
end for
return -1
end function
 
proc getPolarData(filename: string): SailingPolar =
function findlast(atom v, sequence s)
## Reads a sailing polar CSV file and returns a SailingPolar struct containing the file data.
-- Returns the index of the last element of s <= v
## A sailing polar file is a CSV file, with ';' used as the comma separator instead of a comma.
for i=length(s) to 1 by -1 do
## The first line of file contains labels for the wind velocities that make up columns, and
if s[i]<=v then return i end if
## the first entry of each row makes up a column of angle of sailing direction from wind in degrees.
end for
var parser: CsvParser
return -1
parser.open(filename, separator = ';')
end function
parser.readHeaderRow()
for col in 1..parser.headers.high:
function boatspeed(atom pointofsail, windspeed)
result.winds.add parser.headers[col].parseFloat()
--
while parser.readRow():
-- Calculate the expected sailing speed in a specified direction in knots,
if parser.row.len == 0: break # Ignore final blank line if there is one.
-- given a desired point of sail in degrees, and wind speed in knots (for
result.degrees.add parser.row[0].parseFloat()
-- the previously loaded sailing polar data)
result.speeds.add @[]
--
for col in 1..parser.row.high:
integer udeg = findlast(pointofsail, degrees),
result.speeds[^1].add parser.row[col].parseFloat()
odeg = findfirst(pointofsail, degrees),
uvel = findlast(windspeed, winds),
ovel = findfirst(windspeed, winds)
if find(-1,{udeg, odeg, uvel, ovel}) then return -1 end if
atom wu = winds[uvel],
wh = winds[ovel],
du = degrees[udeg],
dh = degrees[odeg],
f
if odeg==udeg then
f = iff(uvel==ovel?1:(windspeed-wu)/(wh-wu))
elsif uvel==ovel then
f = (pointofsail-du)/(dh-du)
else
f = ((pointofsail-du)/(dh-du)+(windspeed-wu)/(wh-wu))/2
end if
atom su = speeds[udeg,uvel],
sh = speeds[odeg,ovel],
res = su + f*(sh-su)
return res
end function
 
function sailingspeed(atom azimuth, pointofsail, ws)
--
-- Calculate the expected net boat speed in a desired direction versus the wind (azimuth).
-- This is generally different from the actual boat speed in its actual direction.
-- Directions are in degrees (pointofsail is the ship direction from wind),
-- and velocity of wind (ws) is in knots.
--
return boatspeed(pointofsail, ws) * cosd(abs(pointofsail-azimuth))
end function
 
const R = 6372800.0 # Earth's approximate radius in meters.
struct SurfaceParameters
--
-- wind and surface current, direction and velocity, for a given position
-- directions are in degrees from north, and velocities are in knots.
--
public atom winddirection,
windvelocity,
currentdirection,
currentvelocity
end struct
 
template sind(d: float): float = sin(degToRad(d))
function bestvectorspeed(atom dirtravel, SurfaceParameters p)
template cosd(d: float): float = cos(degToRad(d))
--
template asind(x: float): float = radToDeg(arcsin(x))
-- Calculate the net direction and velocity of a sailing ship.
template atand(x, y: float): float = radToDeg(arctan2(x, y))
--
atom wd = p.winddirection,
wv = p.windvelocity,
cd = p.currentdirection,
cv = p.currentvelocity,
azimuth = remainder(dirtravel-wd,360)
if azimuth<0 then azimuth += 360 end if
if azimuth>180 then azimuth = 360-azimuth end if
atom vmg = boatspeed(azimuth, wv),
other = -1
integer idx = -1
for i=1 to length(degrees) do
atom ss = sailingspeed(azimuth, degrees[i], wv)
if ss>other then {other,idx} = {ss,i} end if
end for
if other>vmg then
azimuth = degrees[idx]
vmg = other
end if
atom dirchosen = deg2rad(wd + azimuth),
dircurrent = deg2rad(cd),
wx = vmg * sin(dirchosen),
wy = vmg * cos(dirchosen),
curx = cv * sin(dircurrent),
cury = cv * cos(dircurrent)
return sqrt(power(wx+curx,2) + power(wy+cury,2))
end function
 
function sailsegmenttime(SurfaceParameters p, atom lat1, lon1, lat2, lon2)
--
-- Calculate the trip time in minutes from (lat1, lon1) to the destination (lat2, lon2).
-- Uses the data in SurfaceParameters p for wind and current velocity and direction.
--
atom {distance, direction} = haversine(lat1, lon1, lat2, lon2),
velocity = bestvectorspeed(direction, p)
-- minutes/s * m / (knots * (m/s / knot)) = minutes
atom res = (1/60) * distance / (velocity * 1.94384)
return res
end function
 
func haversine(lat1, long1, lat2, long2: float): (float, float) =
--
## Calculates the Haversine function for two points on the Earth's surface.
-- The data is selected so the best time path is slightly longer than the
## Given two latitude, longitude pairs in degrees for a point on the Earth,
-- shortest length path. The forbidden regions are x, representing land or reef.
## get distance in meters and the initial direction of travel in degrees for
-- The allowed sailing points are . and start and finish are S and F.
## movement from point 1 to point 2.
--
let dlat = lat2 - lat1
constant chart = split("""
let dlong = long2 - long1
...S.....
let a = sind(dlat/2)^2 + cosd(lat1) * cosd(lat2) * sind(dlong/2)^2
x......x.
let c = 2 * asind(sqrt(a))
....x..x.
var theta = atand(sind(dlong) * cosd(lat2),
x...xx.x.
cosd(lat1) * sind(lat2) - sind(lat1) * cosd(lat2) * cosd(dlong))
x...xx.x.
theta = (theta + 360) mod 360
..xxxx.xx
result = (R * c * 0.5399565, theta)
x..xxx...
.......xx
x..F..x.x""",'\n')
 
function minimum_time_route(sequence timeframe, start, finish)
--
-- Get the fastest route from start to finish for some detailed sea/ship parameters.
-- timeframe is a massive 200 * 9x9 * {pt,SurfaceParameters}
-- note that polar data (ie winds, degrees, speeds) is static here, for simplicity.
--
atom t0 = time(),
mintime = 1000.0
integer xmax = length(chart[1]),
ymax = length(chart),
{py,px} = start
sequence todo = {start},
costs = repeat(repeat(-1,xmax),ymax), -- (lowest durations)
paths = repeat(repeat(0,xmax),ymax), -- (single backlinks)
minpath = {}
costs[py,px] = 0
while length(todo) do
{py,px} = todo[1]
todo = todo[2..$]
atom duration = costs[py,px]
integer sdx = remainder(floor(round(duration)/timeinterval),length(timeframe))+1
sequence s = timeframe[sdx]
for nx=px-1 to px+1 do
for ny=py-1 to py+1 do
if (nx!=px or ny!=py)
and nx>=1 and nx<=xmax
and ny>=1 and ny<=ymax
and chart[ny,nx]!='x' then
sequence gp1 = s[py,px], -- {pt,SurfaceParameters}
gp2 = s[ny,nx] -- ""
atom {lat1, lon1} = gp1[1],
{lat2, lon2} = gp2[1]
SurfaceParameters sp = gp1[2]
atom nt = duration + sailsegmenttime(sp, lat1, lon1, lat2, lon2)
if costs[ny,nx]=-1 or nt<costs[ny,nx] then
costs[ny,nx] = nt
paths[ny,nx] = {py,px}
if not find({ny,nx},todo) then
todo = append(todo,{ny,nx})
end if
elsif nt==costs[ny,nx] then
-- (Should multiple same-time routes exist, we could store
-- multiple back-links and whip up a simple [recursive]
-- routine to rebuild them all. Or just ignore them.)
?9/0
end if
end if
end for
end for
s = {} -- (simplify debugging)
end while
timeframe = {} -- (simplify debugging)
{py,px} = finish
mintime = costs[py,px]
minpath = {finish}
while true do
object pyx = paths[py,px]
if pyx=0 then exit end if
minpath = prepend(minpath,pyx)
paths[py,px] = 0
{py,px} = pyx
end while
if minpath[1]!=start then ?9/0 end if
return {minpath,elapsed(mintime*60),elapsed(time()-t0)}
end function
function surfacebylongitude(atom lon)
-- Create regional wind patterns on the map.
sequence p = iff(lon < -155.03 ? { -5.0, 8, 150, 0.5} :
iff(lon < -155.99 ? {-90.0, 20, 150, 0.4} :
{180.0, 25, 150, 0.3}))
SurfaceParameters res = new(p)
return res
end function
 
func findFirst(a: seq[float]; p: Pred): int =
procedure mutatetimeslices(sequence slices)
## Returns the index of the first element of 'a' for which 'p' returns true or -1 otherwise.
-- Vary wind speeds over time.
for i=1 to length(slices)in do0..a.high:
if p(a[i]): return i
sequence s = slices[i]
result = -1
for j=1 to length(s) do
 
sequence sj = s[j]
 
for k=1 to length(sj) do
func findLast(a: seq[float]; p: Pred): int =
object sjk = sj[k]
## Returns the index of the last element of 'a' for which 'p' returns true or -1 otherwise.
SurfaceParameters p = sjk[2]
for i in countdown(a.high, 0):
p.windvelocity = p.windvelocity * (1+0.002*i)
if p(a[i]): return i
end for
result = -1
end for
 
end for
 
end procedure
func boatSpeed(sp: SailingPolar; pointOfSail, windSpeed: float): float =
## Calculate the expected sailing speed in a specified direction in knots,
## given sailing polar data, a desired point of sail in degrees, and wind speed in knots.
let
udeg = sp.degrees.findLast(t => t <= pointOfSail)
odeg = sp.degrees.findFirst(t => t >= pointOfSail)
uvel = sp.winds.findLast(t => t <= windSpeed)
ovel = sp.winds.findFirst(t => t >= windSpeed)
if udeg == -1 or odeg == -1 or uvel == -1 or ovel == -1: return -1
let frac = if odeg == udeg and uvel == ovel:
1.0
elif odeg == udeg:
(windSpeed - sp.winds[uvel]) / (sp.winds[ovel] - sp.winds[uvel])
elif uvel == ovel:
(pointOfSail - sp.degrees[udeg]) / (sp.degrees[odeg] - sp.degrees[udeg])
else:
((pointOfSail - sp.degrees[udeg]) / (sp.degrees[odeg] - sp.degrees[udeg]) +
(windSpeed - sp.winds[uvel]) / (sp.winds[ovel] - sp.winds[uvel])) / 2
result = sp.speeds[udeg][uvel] + frac * (sp.speeds[odeg][ovel] - sp.speeds[udeg][uvel])
 
 
func sailingSpeed(sp: SailingPolar; azimuth, pointos, ws: float): float =
## Calculates the expected net boat speed in a desired direction versus the wind ('azimuth').
## This is generally different from the actual boat speed in its actual direction.
## Directions are in degrees ('pointos' is point of sail the ship direction from the wind),
## and velocity of wind ('ws') is in knots.
sp.boatSpeed(pointos, ws) * cosd(abs(pointos - azimuth))
 
 
func bestVectorSpeed(sp: SailingPolar;
dirTravel, dirWind, windSpeed, dirCur, velCur: float): (float, float) =
## Calculates the net direction and velocity of a sailing ship.
## Arguments are sailing polar data, direction of travel in degrees from north, wind direction in
## degrees from north, wind velocity in knots, surface current direction in degrees, and
## current velocity in knots.
var azimuth = (dirTravel - dirWind) mod 360
if azimuth < 0: azimuth += 360
if azimuth > 180: azimuth = 360 - azimuth
 
var vmg = sp.boatSpeed(azimuth, windSpeed)
var other = -1.0
var idx = -1
for i, d in sp.degrees:
let ss = sp.sailingSpeed(azimuth, d, windSpeed)
if ss > other:
other = ss
idx = i
if other > vmg:
azimuth = sp.degrees[idx]
vmg = other
 
let
dirChosen = dirWind + azimuth
wx = vmg * sind(dirChosen)
wy = vmg * cosd(dirChosen)
curX = velCur * sind(dirCur)
curY = velCur * cosd(dirCur)
result = (atand(wy + curY, wx + curX), sqrt((wx + curX)^2 + (wy + curY)^2))
 
 
func sailSegmentTime(sp: SailingPolar; p: SurfaceParameters;
lat1, long1, lat2, long2: float): float =
## Calculates the trip time in minutes from (lat1, long1) to the destination (lat2, long2).
## Uses the data in SurfaceParameters for wind and current velocity and direction.
let (distance, dir) = haversine(lat1, long1, lat2, long2)
let (_, vel) = sp.bestVectorSpeed(dir, p.windDeg, p.windKts, p.currentDeg, p.currentKts)
## minutes/s * m / (knots * (m/s / knot)) = minutes
result = (1 / 60) * distance / (vel * 1.94384)
 
 
# Structure that represents a point in 2-D space.
type Point2 = tuple[x, y: int]
 
func `+`(p1, p2: Point2): Point2 = (p1.x + p2.x, p1.y + p2.y)
 
func `$`(p: Point2): string = "($1, $2)".format(p.x, p.y)
 
 
type
 
# Tuple that consists of a tuple of latitude and longitude in degrees.
# NB: This uses latitude (often considered to be y) first then longitude (often considered to be x).
# This latitude, then longitude ordering is as per ISO 6709 (en.wikipedia.org/wiki/ISO_6709).
Position = tuple[lat, long: float]
 
# Tuple that represents a Position with the SurfaceParameters of wind and current at the Position.
GridPoint = tuple[pt: Position; sp: SurfaceParameters]
 
MatrixG = seq[seq[GridPoint]]
 
# Type alias for a matrix of GridPoints, each Position point with their SurfaceParameters.
# A vector of TimeSlice can give the surface characteristics for an ocean region over time.
TimeSlice = MatrixG
 
# Structure that represents a routing problem.
RoutingProblem = object
timeInterval: float # The minutes duration for each TimeSlice.
timeFrame: seq[TimeSlice] # A vector of sequential timeslices for the ocean region.
obstacleIndices: seq[Point2] # The cartesian indices in each TimeSlice for obstacles
# such as land or shoals, where the ship may not go.
startIndex: int # The TimeSlice position for time of starting.
start: Point2 # Starting location on grid of GridPoints.
finish: Point2 # Destination / finish location on grid of GridPoints.
allowRepeatVisits: bool # Whether the vessel may overlap its prior path, usually false.
 
# Structure that represents a timed path.
TimedPath = object
duration: float # Minutes total to travel the path.
path: seq[Point2] # Vector of cartesian indices of points in grid for path to travel.
 
 
func hash(t: TimedPath): Hash =
## Hash function to allow building a set of TimedPath values.
result = t.duration.hash !& t.path.hash
result = !$result
 
 
const Neighbors: seq[Point2] = @[(-1, -1), (-1, 0), (-1, 1), (0, -1),
( 0, 1), ( 1, -1), ( 1, 0), (1, 1)]
 
func surround(p: Point2; mat: TimeSlice; excluded: openArray[Point2]): seq[Point2] =
## Returns a list of points surrounding 'p' which are not otherwise excluded.
let xmax = mat.len
let ymax = mat[0].len
for x in Neighbors:
let q = p + x
if q.x >= 0 and q.x < xmax and q.y >= 0 and q.y < ymax and q notin excluded:
result.add q
 
 
proc minimumTimeRoute(rp: RoutingProblem; sp: SailingPolar; verbose: bool): TimedPath =
## Get the route (as a TimedPath) that minimizes time from start to finish for a given
## RoutingProblem (sea parameters) given sailing polar data (ship parameters).
 
var timedPaths = @[TimedPath(duration: 0, path: @[rp.start])]
var completed = false
result = TimedPath(duration: 1000)
for _ in 1..1000:
 
var newPaths: seq[TimedPath]
if verbose:
echo "Checking $1 paths of length $2".format(timedPaths.len, timedPaths[0].path.len)
for tpath in timedPaths:
if tpath.path[^1] == rp.finish:
completed = true
newPaths.add tpath
else:
let p1 = tpath.path[^1]
let num = tpath.duration.toInt
let den = rp.timeInterval.toInt
let slice = rp.timeFrame[num div den mod rp.timeFrame.len]
for p2 in p1.surround(slice, rp.obstacleIndices):
if not rp.allowRepeatVisits and p2 in tpath.path:
continue
let gp1 = slice[p1.x][p1.y]
let gp2 = slice[p2.x][p2.y]
let (lat1, long1) = gp1.pt
let (lat2, long2) = gp2.pt
let t = sp.sailSegmentTime(gp1.sp, lat1, long1, lat2, long2)
let path = tpath.path & p2
newPaths.add TimedPath(duration: tpath.duration + t, path: path)
 
timedPaths = newPaths.toHashSet().toSeq()
if completed:
var durations = collect(newSeq, for t in timedPaths: t.duration)
let minDur = min(durations)
let finished = collect(newSeq):
for t in timedPaths:
if t.path[^1] == rp.finish: t
durations = collect(newSeq, for f in finished: f.duration)
let idx = minIndex(durations)
let minFinDur = durations[idx]
if verbose:
echo "Current finished minimum: $1, others $2".format(finished[idx], minDur)
if minDur == minFinDur:
result = finished[idx]
break
 
 
#[ The data is selected so the best time path is slightly longer than the
shortest length path. The forbidden regions are x, representing land or reef.
The allowed sailing points are . and start and finish are S and F.
 
x . . F . . x . x
. . . . . . . x x
x . . x x x . . .
. . x x x x . x x
x . . . x x . x .
x . . . x x . x .
. . . . x . . x .
x . . . . . . x .
. . . S . . . . .
]#
 
 
const Forbidden: seq[Point2] = @[(0, 7), (1, 0), (1, 7), (2, 4), (2, 7), (3, 0), (3, 4),
(3, 5), (3, 7), (4, 0), (4, 4), (4, 5), (4, 7), (5, 2),
(5, 3), (5, 4), (5, 5), (5, 7), (5, 8), (6, 0), (6, 3),
(6, 4), (6, 5), (7, 7), (7, 8), (8, 0), (8, 6), (8, 8)]
 
 
func surfaceByLongitude(long: float): SurfaceParameters =
## Create regional wind patterns on the map.
if long < -155.03:
(-5.0, 8.0, 150.0, 0.5)
elif long < -155.99:
(-90.0, 20.0, 150.0, 0.4)
else:
(180.0, 25.0, 150.0, 0.3)
 
 
func mutateTimeSlices(slices: var seq[TimeSlice]) =
var i = 1
for slice in slices.mitems:
for j in 0..slice.high:
for x in slice[j].mitems:
x.sp = (x.sp.windDeg, x.sp.windKts * (1 + 0.002 * float64(i)),
x.sp.currentDeg, x.sp.currentKts)
inc i
 
 
let startPos: Point2 = (0, 3)
let endPos: Point2 = (8, 3)
var slices = newSeq[MatrixG](200)
 
for s in 0..slices.high:
var gpoints = newSeq[seq[GridPoint]](9)
for i in 0..<9:
gpoints[i].setLen(9)
for j in 0..<9:
let pt: Position = (19.78 - 1/60 + i/60, -155.0 - 5/60 + j/60)
gpoints[i][j] = (pt, surfaceByLongitude(pt.long))
slices[s] = move(gpoints)
 
slices.mutateTimeSlices()
let routeProb = RoutingProblem(timeInterval: 10, timeFrame: slices,
obstacleIndices: Forbidden, startIndex: 0,
start: startPos, finish: endPos, allowRepeatVisits: false)
let fileName = "polar.csv"
let sp = getPolarData(fileName)
let tp = routeProb.minimumTimeRoute(sp, false)
echo "The route taking the least time found was:"
echo tp.path
echo "which has duration ", int(tp.duration / 60), " hours ", toInt(tp.duration mod 60), " minutes."</syntaxhighlight>
 
{{out}}
<pre>The route taking the least time found was:
@[(0, 3), (0, 4), (1, 5), (2, 6), (3, 6), (4, 6), (5, 6), (6, 6), (7, 5), (7, 4), (8, 3)]
which has duration 4 hours 44 minutes.</pre>
 
=={{header|Phix}}==
{{trans|Go}}
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\Weather_Routing.exw
-- ================================
--</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">polar_csv</span> <span style="color: #0000FF;">=</span> <span style="font-size: 75%; color: #008000;">"""
TWA\TWS;0;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18;19;20;21;22;23;24;25;26;27;28;29;30;35;40;60;70
40;0;0.53;0.54;0.49;0.4;0.31;0.21;0.16;0.11;0.08;0.05;0.03;0.02;0.01;0;0;0;0;0;0;0;0;0;0;0;0;0;0;-0.01;-0.05;-0.1;-0.11
41;0;0.61;0.62;0.56;0.47;0.36;0.25;0.19;0.14;0.1;0.07;0.04;0.02;0.01;0.01;0;0;0;0;0;0;0;0;0;0;0;0;0;0;-0.04;-0.09;-0.1
44;0;0.89;0.91;0.82;0.69;0.56;0.42;0.33;0.24;0.18;0.13;0.08;0.05;0.03;0.02;0.01;0.01;0;0;0;0;0;0;0;0;0;0;0;0;-0.02;-0.06;-0.06
45;0;0.99;1.02;0.92;0.78;0.64;0.49;0.39;0.29;0.22;0.15;0.1;0.07;0.04;0.02;0.01;0.01;0;0;0;0;0;0;0;0;0;0;0;0;-0.01;-0.05;-0.05
46;0;1.11;1.14;1.02;0.87;0.73;0.57;0.45;0.35;0.26;0.18;0.13;0.08;0.05;0.03;0.02;0.01;0.01;0;0;0;0;0;0;0;0;0;0;0;-0.01;-0.04;-0.05
47;0;1.23;1.25;1.14;0.97;0.82;0.66;0.53;0.41;0.31;0.22;0.15;0.1;0.07;0.04;0.02;0.02;0.01;0.01;0;0;0;0;0;0;0;0;0;0;-0.01;-0.03;-0.04
48;0;1.37;1.37;1.26;1.08;0.93;0.76;0.61;0.48;0.36;0.26;0.19;0.13;0.08;0.05;0.03;0.02;0.01;0.01;0.01;0;0;0;0;0;0;0;0;0;0;-0.02;-0.03
49;0;1.5;1.5;1.39;1.2;1.05;0.87;0.71;0.56;0.42;0.31;0.22;0.15;0.1;0.07;0.04;0.03;0.02;0.01;0.01;0;0;0;0;0;0;0;0;0;0;-0.02;-0.02
50;0;1.65;1.64;1.52;1.33;1.18;1;0.81;0.65;0.49;0.37;0.26;0.19;0.13;0.08;0.05;0.04;0.03;0.02;0.01;0.01;0;0;0;0;0;0;0;0;0;-0.01;-0.02
51;0;1.79;1.77;1.67;1.46;1.32;1.13;0.92;0.74;0.57;0.43;0.31;0.22;0.15;0.1;0.07;0.05;0.03;0.02;0.02;0.01;0.01;0;0;0;0;0;0;0;0;-0.01;-0.02
53;0;2.1;2.07;1.99;1.76;1.62;1.4;1.14;0.95;0.74;0.57;0.43;0.31;0.22;0.16;0.1;0.08;0.06;0.04;0.03;0.02;0.01;0.01;0.01;0;0;0;0;0;0;-0.01;-0.01
54;0;2.26;2.22;2.16;1.92;1.78;1.55;1.28;1.06;0.84;0.65;0.5;0.37;0.27;0.19;0.13;0.1;0.07;0.06;0.04;0.03;0.02;0.01;0.01;0;0;0;0;0;0;0;-0.01
55;0;2.43;2.39;2.34;2.09;1.95;1.7;1.42;1.18;0.95;0.74;0.57;0.43;0.32;0.23;0.16;0.12;0.09;0.07;0.05;0.04;0.03;0.02;0.01;0.01;0;0;0;0;0;0;-0.01
60;0;3.29;3.33;3.33;3.08;2.93;2.64;2.29;1.98;1.66;1.36;1.1;0.88;0.68;0.53;0.39;0.32;0.26;0.21;0.17;0.13;0.1;0.07;0.05;0.04;0.03;0.02;0.01;0;0;0;0
70;0;5.2;5.53;5.74;5.59;5.5;5.22;4.84;4.46;3.94;3.51;3.08;2.65;2.26;1.9;1.55;1.38;1.22;1.06;0.92;0.78;0.66;0.55;0.46;0.37;0.3;0.24;0.18;0.03;0;0;0
80;0;6.8;7.43;7.97;8.02;8.23;8.34;8.2;7.9;7.37;6.91;6.43;5.9;5.32;4.72;4.12;3.83;3.55;3.25;2.96;2.67;2.4;2.13;1.88;1.65;1.43;1.22;1.04;0.37;0.09;0.01;0
90;0;7.59;8.5;9.4;9.73;10.4;11.16;11.53;11.56;11.3;11.05;10.77;10.44;9.83;9.07;8.34;8;7.65;7.27;6.88;6.46;6.04;5.61;5.15;4.74;4.33;3.88;3.51;1.72;0.67;0.12;0.03
100;0;7.34;8.25;9.16;9.86;10.5;11.95;12.79;13.5;14.02;14.4;14.37;14.5;14.4;13.92;13.52;13.19;12.79;12.51;12.1;11.66;11.22;10.77;10.26;9.72;9.2;8.58;8.01;4.87;2.51;0.7;0.23
110;0;7.09;7.97;8.84;9.74;10.09;11.85;12.75;13.84;14.99;16.02;16.33;17.1;17.83;17.99;18.32;18.14;17.81;17.84;17.6;17.3;17.05;16.83;16.53;16.03;15.59;15.03;14.37;10.26;6.41;2.32;0.86
120;0;6.59;7.42;8.3;9.1;9.56;10.83;11.6;13.1;13.87;14.66;15.75;16.67;17.63;18.43;19.62;20.17;20.6;21.12;21.55;21.75;21.91;22.07;21.9;21.58;21.29;20.92;20.29;16.47;12.03;5.49;2.26
129;0;6.14;6.93;7.83;8.52;9.09;9.89;10.57;12.42;12.87;13.43;15.23;16.16;17.08;18.07;19.48;20.35;21.22;21.93;22.85;23.44;23.98;24.55;24.59;24.55;24.51;24.46;24;21.56;17.75;9.64;4.25
130;0;6.07;6.87;7.76;8.44;9.02;9.8;10.48;12.29;12.73;13.27;15.08;16.03;16.97;17.96;19.36;20.25;21.15;21.88;22.82;23.44;24.03;24.6;24.66;24.68;24.67;24.64;24.24;22;18.33;10.11;4.5
135;0;5.72;6.57;7.36;8.02;8.65;9.38;10.11;11.52;11.97;12.55;13.85;15.31;16.31;17.33;18.54;19.48;20.35;21.28;22.3;23.08;24.09;24.63;24.69;24.78;24.79;24.91;24.82;23.74;20.98;12.39;5.78
136;0;5.66;6.5;7.28;7.93;8.57;9.3;10.04;11.34;11.82;12.42;13.62;15.06;16.17;17.2;18.35;19.29;20.15;21.12;22.15;22.96;24.07;24.6;24.67;24.76;24.75;24.85;24.81;23.98;21.45;12.8;6.03
139;0;5.42;6.31;6.92;7.67;8.34;9.08;9.86;10.86;11.32;12.03;12.99;14.3;15.73;16.76;17.76;18.71;19.53;20.6;21.66;22.54;23.92;24.44;24.53;24.64;24.58;24.65;24.67;24.47;22.68;13.79;6.73
140;0;5.35;6.22;6.79;7.59;8.26;9;9.8;10.72;11.16;11.89;12.79;14.06;15.5;16.62;17.57;18.51;19.32;20.43;21.49;22.4;23.84;24.36;24.46;24.58;24.51;24.57;24.61;24.56;23.02;14.08;6.96
141;0;5.29;6.12;6.67;7.48;8.18;8.93;9.74;10.57;11.02;11.77;12.62;13.82;15.26;16.47;17.38;18.32;19.04;20.28;21.31;22.07;23.53;24;24.21;24.29;24.43;24.48;24.55;24.61;23.33;14.31;7.18
142;0;5.23;6.02;6.57;7.39;8.1;8.86;9.67;10.43;10.88;11.64;12.45;13.59;15.03;16.24;17.14;18.06;18.77;19.98;21.01;21.75;23.18;23.65;23.86;23.95;24.34;24.39;24.48;24.61;23.61;14.54;7.4
143;0;5.16;5.93;6.45;7.3;8;8.78;9.54;10.27;10.75;11.5;12.28;13.36;14.8;16.01;16.9;17.81;18.5;19.69;20.72;21.43;22.84;23.31;23.52;23.61;24.05;24.27;24.41;24.57;23.85;14.8;7.6
144;0;5.09;5.83;6.33;7.23;7.92;8.66;9.41;10.13;10.62;11.39;12.13;13.13;14.57;15.78;16.65;17.56;18.24;19.41;20.43;21.12;22.5;22.97;23.19;23.28;23.73;24.08;24.33;24.49;24.04;15;7.8
145;0;5.02;5.73;6.23;7.15;7.85;8.55;9.28;9.98;10.51;11.27;11.98;12.92;14.35;15.56;16.42;17.31;17.97;19.13;20.14;20.82;22.17;22.64;22.87;22.96;23.42;23.81;24.23;24.41;24.19;15.14;7.98
146;0;4.96;5.64;6.12;7.07;7.77;8.43;9.15;9.84;10.38;11.16;11.83;12.71;14.12;15.35;16.19;17.07;17.72;18.86;19.86;20.51;21.84;22.31;22.56;22.65;23.12;23.48;23.94;24.33;24.3;15.3;8.16
148;0;4.82;5.45;5.91;6.9;7.59;8.21;8.89;9.55;10.14;10.89;11.55;12.29;13.7;14.92;15.74;16.6;17.23;18.32;19.3;19.91;21.2;21.67;21.95;22.05;22.53;22.87;23.38;24.13;24.39;15.52;8.46
149;0;4.76;5.35;5.81;6.78;7.49;8.09;8.78;9.42;10.01;10.76;11.41;12.1;13.48;14.71;15.52;16.36;16.98;18.06;19.03;19.63;20.89;21.37;21.67;21.77;22.26;22.61;23.12;23.98;24.37;15.57;8.58
150;0;4.69;5.26;5.7;6.67;7.37;7.96;8.64;9.26;9.86;10.6;11.24;11.89;13.26;14.48;15.29;16.11;16.73;17.79;18.74;19.33;20.55;21.04;21.37;21.48;21.98;22.34;22.83;23.69;24.11;15.6;8.67
155;0;4.33;4.74;5.16;6.16;6.79;7.33;7.96;8.51;9.15;9.81;10.4;10.85;12.14;13.37;14.1;14.87;15.48;16.42;17.3;17.8;18.88;19.39;19.86;20;20.54;20.97;21.45;22.25;22.77;15.38;8.89
160;0;4.09;4.41;4.83;5.77;6.39;6.94;7.55;8.04;8.67;9.28;9.83;10.24;11.46;12.69;13.39;14.11;14.73;15.6;16.41;16.87;17.85;18.4;18.97;19.15;19.72;20.2;20.65;21.35;21.84;14.95;8.74
162;0;4;4.29;4.69;5.62;6.23;6.77;7.38;7.86;8.48;9.07;9.6;10;11.18;12.42;13.1;13.81;14.43;15.27;16.06;16.5;17.43;18;18.62;18.81;19.39;19.89;20.33;20.99;21.48;14.76;8.61
168;0;3.74;3.93;4.35;5.15;5.75;6.31;6.93;7.34;7.92;8.45;8.95;9.35;10.44;11.68;12.32;12.99;13.63;14.39;15.11;15.5;16.31;16.94;17.7;17.92;18.53;19.08;19.49;19.99;20.46;14.34;8.3
170;0;3.69;3.85;4.27;5.04;5.65;6.22;6.82;7.23;7.8;8.31;8.8;9.22;10.27;11.51;12.15;12.81;13.45;14.19;14.9;15.28;16.06;16.7;17.51;17.73;18.34;18.91;19.31;19.77;20.22;14.24;8.24
174;0;3.57;3.69;4.11;4.83;5.43;6.01;6.62;7;7.55;8.03;8.5;8.93;9.95;11.19;11.81;12.45;13.11;13.81;14.48;14.84;15.57;16.24;17.11;17.35;17.98;18.57;18.95;19.33;19.77;14.03;8.13
180;0;3.51;3.6;4.03;4.71;5.31;5.91;6.51;6.88;7.41;7.88;8.33;8.79;9.78;11.02;11.63;12.26;12.93;13.61;14.26;14.61;15.31;15.99;16.9;17.15;17.79;18.39;18.77;19.09;19.52;13.87;8.07
"""</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">to_numbers</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
sequence slices = repeat(null,200)
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
for s=1 to length(slices) do
<span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">to_number</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
sequence gpoints = repeat(null,9)
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
for i=1 to 9 do
<span style="color: #008080;">return</span> <span style="color: #000000;">s</span>
atom lat = 19.78 - 2/60 + i/60
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
gpoints[i] = repeat(null,9)
for j=1 to 9 do
<span style="color: #008080;">function</span> <span style="color: #000000;">getpolardata</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
atom lon = -155.0 - 6/60 + j/60
<span style="color: #000080;font-style:italic;">--
gpoints[i][j] = {{lat,lon}, surfacebylongitude(lon)}
-- A sailing polar file is a CSV file, with ';' used as the comma separator instead of a comma.
end for
-- The first line of the file contains labels for the wind velocities that make up columns, and
end for
-- the first entry of each row makes up a column of angle of sailing direction from wind in degrees
slices[s] = gpoints
--</span>
end for
<span style="color: #004080;">sequence</span> <span style="color: #000000;">lines</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split_any</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\r\n"</span><span style="color: #0000FF;">),</span>
mutatetimeslices(slices)
<span style="color: #000000;">winds</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">to_numbers</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #008000;">";"</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]),</span>
constant fmt = """
<span style="color: #000000;">degrees</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span> <span style="color: #000000;">speeds</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
The route taking the least time found was:
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
%v
<span style="color: #004080;">sequence</span> <span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">to_numbers</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lines</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #008000;">";"</span><span style="color: #0000FF;">))</span>
which has duration %s [route found in %s]
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">)!=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">winds</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
"""
<span style="color: #000000;">degrees</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">degrees</span><span style="color: #0000FF;">,</span><span style="color: #000000;">l</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span>
printf(1,fmt,minimum_time_route(slices,{1,4},{9,4}))</lang>
<span style="color: #000000;">speeds</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">speeds</span><span style="color: #0000FF;">,</span><span style="color: #000000;">l</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">winds</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">degrees</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">speeds</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #000080;font-style:italic;">--
-- winds is a list of wind speeds
-- degrees is a list of angles in degrees of direction relative to the wind
-- (note 0 degrees is directly into the wind, 180 degrees is directly downwind)
-- each speeds[i] is an array of length(winds) for each degrees[i]
--</span>
<span style="color: #008080;">constant</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">winds</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">degrees</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">speeds</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">getpolardata</span><span style="color: #0000FF;">(</span><span style="color: #000000;">polar_csv</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--constant {winds, degrees, speeds} = getpolardata(get_text("polar.csv")) -- alt</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">R</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">6372800</span> <span style="color: #000080;font-style:italic;">-- Earth's approximate radius in meters</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">timeinterval</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">10</span> <span style="color: #000080;font-style:italic;">-- the minutes duration for each TimeSlice</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">deg2rad</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">deg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">deg</span><span style="color: #0000FF;">*</span><span style="color: #004600;">PI</span><span style="color: #0000FF;">/</span><span style="color: #000000;">180</span><span style="color: #0000FF;">+</span><span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #004600;">PI</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #004600;">PI</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">rad2deg</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">rad</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #7060A8;">remainder</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">rad</span><span style="color: #0000FF;">*(</span><span style="color: #000000;">180</span><span style="color: #0000FF;">/</span><span style="color: #004600;">PI</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">360</span><span style="color: #0000FF;">,</span><span style="color: #000000;">360</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">sind</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">deg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #7060A8;">sin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">deg2rad</span><span style="color: #0000FF;">(</span><span style="color: #000000;">deg</span><span style="color: #0000FF;">))</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">cosd</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">deg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #7060A8;">cos</span><span style="color: #0000FF;">(</span><span style="color: #000000;">deg2rad</span><span style="color: #0000FF;">(</span><span style="color: #000000;">deg</span><span style="color: #0000FF;">))</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">asind</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">deg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #000000;">rad2deg</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">arcsin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">deg</span><span style="color: #0000FF;">))</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">atand</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #000000;">rad2deg</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">atan2</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">))</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">haversine</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">lat1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lon1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lat2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lon2</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- Calculate the haversine function for two points on the Earth's surface.
--
-- Given two latitude, longitude pairs in degrees for a point on the Earth,
-- get distance in meters and the initial direction of travel in degrees for
-- movement from point 1 to point 2.
--</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">dlat</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">lat2</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">lat1</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">dlon</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">lon2</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">lon1</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sind</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlat</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">),</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">cosd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lat1</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">cosd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lat2</span><span style="color: #0000FF;">)*</span><span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sind</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlon</span><span style="color: #0000FF;">/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">),</span><span style="color: #000000;">2</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2.0</span> <span style="color: #0000FF;">*</span> <span style="color: #000000;">asind</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)),</span>
<span style="color: #000000;">theta</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">atand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sind</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlon</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">cosd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lat2</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">cosd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lat1</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">sind</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lat2</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">sind</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lat1</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">cosd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lat2</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">cosd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlon</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">theta</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">theta</span><span style="color: #0000FF;">+</span><span style="color: #000000;">360</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">360</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">R</span><span style="color: #0000FF;">*</span><span style="color: #000000;">c</span><span style="color: #0000FF;">*</span><span style="color: #000000;">0.5399565</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">theta</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">find_range</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- Returns the indexes of s of the first &gt;=v, and the last &lt;=v</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]>=</span><span style="color: #000000;">v</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]<=</span><span style="color: #000000;">v</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">j</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">boatspeed</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">pointofsail</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">windspeed</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- Calculate the expected sailing speed in a specified direction in knots,
-- given a desired point of sail in degrees, and wind speed in knots (for
-- the previously loaded sailing polar data)
--</span>
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">ld</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ud</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">find_range</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pointofsail</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">degrees</span><span style="color: #0000FF;">),</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">lv</span><span style="color: #0000FF;">,</span><span style="color: #000000;">uv</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">find_range</span><span style="color: #0000FF;">(</span><span style="color: #000000;">windspeed</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">winds</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ld</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ud</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lv</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">uv</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">wu</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">winds</span><span style="color: #0000FF;">[</span><span style="color: #000000;">uv</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">wl</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">winds</span><span style="color: #0000FF;">[</span><span style="color: #000000;">lv</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">du</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">degrees</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ud</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">dl</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">degrees</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ld</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">f</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ld</span><span style="color: #0000FF;">==</span><span style="color: #000000;">ud</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">f</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">uv</span><span style="color: #0000FF;">==</span><span style="color: #000000;">lv</span> <span style="color: #0000FF;">?</span> <span style="color: #000000;">1</span> <span style="color: #0000FF;">:</span>
<span style="color: #0000FF;">(</span><span style="color: #000000;">wu</span><span style="color: #0000FF;">-</span><span style="color: #000000;">windspeed</span><span style="color: #0000FF;">)/(</span><span style="color: #000000;">wu</span><span style="color: #0000FF;">-</span><span style="color: #000000;">wl</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">uv</span><span style="color: #0000FF;">==</span><span style="color: #000000;">lv</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">f</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">du</span><span style="color: #0000FF;">-</span><span style="color: #000000;">pointofsail</span><span style="color: #0000FF;">)/(</span><span style="color: #000000;">du</span><span style="color: #0000FF;">-</span><span style="color: #000000;">dl</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">f</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">((</span><span style="color: #000000;">du</span><span style="color: #0000FF;">-</span><span style="color: #000000;">pointofsail</span><span style="color: #0000FF;">)/(</span><span style="color: #000000;">du</span><span style="color: #0000FF;">-</span><span style="color: #000000;">dl</span><span style="color: #0000FF;">)+</span>
<span style="color: #0000FF;">(</span><span style="color: #000000;">wu</span><span style="color: #0000FF;">-</span><span style="color: #000000;">windspeed</span><span style="color: #0000FF;">)/(</span><span style="color: #000000;">wu</span><span style="color: #0000FF;">-</span><span style="color: #000000;">wl</span><span style="color: #0000FF;">))/</span><span style="color: #000000;">2</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">su</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">speeds</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ud</span><span style="color: #0000FF;">,</span><span style="color: #000000;">uv</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">sl</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">speeds</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ld</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lv</span><span style="color: #0000FF;">],</span>
<span style="color: #000080;font-style:italic;">-- res = su + f*(sl-su) -- (original)</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">su</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">*(</span><span style="color: #000000;">su</span><span style="color: #0000FF;">-</span><span style="color: #000000;">sl</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (equivalent)
-- res = sl + (1-f)*(su-sl) -- (also equivalent)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">sailingspeed</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">azimuth</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pointofsail</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ws</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- Calculate the expected net boat speed in a desired direction versus the wind (azimuth).
-- This is generally different from the actual boat speed in its actual direction.
-- Directions are in degrees (pointofsail is the ship direction from wind),
-- and velocity of wind (ws) is in knots.
--</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">boatspeed</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pointofsail</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ws</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">*</span> <span style="color: #000000;">cosd</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">abs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pointofsail</span><span style="color: #0000FF;">-</span><span style="color: #000000;">azimuth</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">bestvectorspeed</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">dirtravel</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">surfaceparameters</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- Calculate the net direction and velocity of a sailing ship.
--</span>
<span style="color: #004080;">atom</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">winddirection</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">windvelocity</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">currentdirection</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">currentvelocity</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">surfaceparameters</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">azimuth</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dirtravel</span><span style="color: #0000FF;">-</span><span style="color: #000000;">winddirection</span><span style="color: #0000FF;">,</span><span style="color: #000000;">360</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">azimuth</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000000;">azimuth</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">360</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">azimuth</span><span style="color: #0000FF;">></span><span style="color: #000000;">180</span> <span style="color: #008080;">then</span> <span style="color: #000000;">azimuth</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">360</span><span style="color: #0000FF;">-</span><span style="color: #000000;">azimuth</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">vmg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">boatspeed</span><span style="color: #0000FF;">(</span><span style="color: #000000;">azimuth</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">windvelocity</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">other</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">idx</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">degrees</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">ss</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">sailingspeed</span><span style="color: #0000FF;">(</span><span style="color: #000000;">azimuth</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">degrees</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">windvelocity</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ss</span><span style="color: #0000FF;">></span><span style="color: #000000;">other</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">other</span><span style="color: #0000FF;">,</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">ss</span><span style="color: #0000FF;">,</span><span style="color: #000000;">i</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">other</span><span style="color: #0000FF;">></span><span style="color: #000000;">vmg</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">azimuth</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">degrees</span><span style="color: #0000FF;">[</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">vmg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">other</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">dirchosen</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">deg2rad</span><span style="color: #0000FF;">(</span><span style="color: #000000;">winddirection</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">azimuth</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">dircurrent</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">deg2rad</span><span style="color: #0000FF;">(</span><span style="color: #000000;">currentdirection</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">wx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">vmg</span> <span style="color: #0000FF;">*</span> <span style="color: #7060A8;">sin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dirchosen</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">wy</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">vmg</span> <span style="color: #0000FF;">*</span> <span style="color: #7060A8;">cos</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dirchosen</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">curx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">currentvelocity</span> <span style="color: #0000FF;">*</span> <span style="color: #7060A8;">sin</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dircurrent</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">cury</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">currentvelocity</span> <span style="color: #0000FF;">*</span> <span style="color: #7060A8;">cos</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dircurrent</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wx</span><span style="color: #0000FF;">+</span><span style="color: #000000;">curx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wy</span><span style="color: #0000FF;">+</span><span style="color: #000000;">cury</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">sailsegmenttime</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">surfaceparameters</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">lat1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lon1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lat2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lon2</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- Calculate the trip time in minutes from (lat1, lon1) to the destination (lat2, lon2).
-- Uses the data in surfaceparameters for wind and current velocity and direction.
--</span>
<span style="color: #004080;">atom</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">distance</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">direction</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">haversine</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lat1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lon1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lat2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lon2</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">velocity</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bestvectorspeed</span><span style="color: #0000FF;">(</span><span style="color: #000000;">direction</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">surfaceparameters</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- minutes/s * m / (knots * (m/s / knot)) = minutes</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">/</span><span style="color: #000000;">60</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">*</span> <span style="color: #000000;">distance</span> <span style="color: #0000FF;">/</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">velocity</span> <span style="color: #0000FF;">*</span> <span style="color: #000000;">1.94384</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #000080;font-style:italic;">--
-- The data is selected so the best time path is slightly longer than the
-- shortest length path. The forbidden regions are x, representing land or reef.
-- The allowed sailing points are . and start and finish are S and F.
-- </span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">chart</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"""
...S.....
x......x.
....x..x.
x...xx.x.
x...xx.x.
..xxxx.xx
x..xxx...
.......xx
x..F..x.x"""</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">minimum_time_route</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">timeframe</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">start</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">finish</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- Get the fastest route from start to finish for some detailed sea/ship parameters.
-- timeframe is a massive 200 * 9x9 * {pt,surfaceparameters}
-- note that polar data (ie winds, degrees, speeds) is static here, for simplicity.
--</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">(),</span>
<span style="color: #000000;">mintime</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1000.0</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">xmax</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">chart</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]),</span>
<span style="color: #000000;">ymax</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">chart</span><span style="color: #0000FF;">),</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">px</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">start</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">todo</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">start</span><span style="color: #0000FF;">},</span>
<span style="color: #000000;">costs</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">xmax</span><span style="color: #0000FF;">),</span><span style="color: #000000;">ymax</span><span style="color: #0000FF;">),</span> <span style="color: #000080;font-style:italic;">-- (lowest durations)</span>
<span style="color: #000000;">paths</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">xmax</span><span style="color: #0000FF;">),</span><span style="color: #000000;">ymax</span><span style="color: #0000FF;">),</span> <span style="color: #000080;font-style:italic;">-- (single backlinks)</span>
<span style="color: #000000;">minpath</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #000000;">costs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">px</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">while</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">todo</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">px</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">todo</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">todo</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">todo</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">duration</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">costs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">px</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">sdx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">round</span><span style="color: #0000FF;">(</span><span style="color: #000000;">duration</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">timeinterval</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">timeframe</span><span style="color: #0000FF;">))+</span><span style="color: #000000;">1</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">timeframe</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sdx</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">nx</span><span style="color: #0000FF;">=</span><span style="color: #000000;">px</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">px</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">ny</span><span style="color: #0000FF;">=</span><span style="color: #000000;">py</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">py</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">px</span> <span style="color: #008080;">or</span> <span style="color: #000000;">ny</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">py</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">and</span> <span style="color: #000000;">nx</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">nx</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">xmax</span>
<span style="color: #008080;">and</span> <span style="color: #000000;">ny</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ny</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">ymax</span>
<span style="color: #008080;">and</span> <span style="color: #000000;">chart</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">]!=</span><span style="color: #008000;">'x'</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">gp1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">px</span><span style="color: #0000FF;">],</span> <span style="color: #000080;font-style:italic;">-- {pt,surfaceparameters}</span>
<span style="color: #000000;">gp2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">]</span> <span style="color: #000080;font-style:italic;">-- ""</span>
<span style="color: #004080;">atom</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">lat1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lon1</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">gp1</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">lat2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lon2</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">gp2</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">surfaceparameters</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">gp1</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">nt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">duration</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">sailsegmenttime</span><span style="color: #0000FF;">(</span><span style="color: #000000;">surfaceparameters</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lat1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lon1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lat2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">lon2</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">costs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">]=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">or</span> <span style="color: #000000;">nt</span><span style="color: #0000FF;"><</span><span style="color: #000000;">costs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- a larger (than 9x9) simulation might benefit from not
-- putting any already-too-long routes back on the todo
-- list and/or processing todo lowest duration first.</span>
<span style="color: #000000;">costs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">nt</span>
<span style="color: #000000;">paths</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">px</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">({</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">},</span><span style="color: #000000;">todo</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">todo</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">todo</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">nt</span><span style="color: #0000FF;">==</span><span style="color: #000000;">costs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ny</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nx</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- (Should multiple same-time routes exist, we could store
-- multiple back-links and whip up a simple [recursive]
-- routine to rebuild them all. Or just ignore them.)</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> <span style="color: #000080;font-style:italic;">-- (simplify debugging)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #000000;">timeframe</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> <span style="color: #000080;font-style:italic;">-- (simplify debugging)</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">px</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">finish</span>
<span style="color: #000000;">mintime</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">costs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">px</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">minpath</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">finish</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">pyx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">paths</span><span style="color: #0000FF;">[</span><span style="color: #000000;">py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">px</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">pyx</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">minpath</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">prepend</span><span style="color: #0000FF;">(</span><span style="color: #000000;">minpath</span><span style="color: #0000FF;">,</span><span style="color: #000000;">pyx</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">paths</span><span style="color: #0000FF;">[</span><span style="color: #000000;">py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">px</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> <span style="color: #000080;font-style:italic;">-- (be safe, why not)</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">py</span><span style="color: #0000FF;">,</span><span style="color: #000000;">px</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pyx</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">minpath</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]!=</span><span style="color: #000000;">start</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">minpath</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #000000;">mintime</span><span style="color: #0000FF;">*</span><span style="color: #000000;">60</span><span style="color: #0000FF;">),</span><span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">)}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">surfacebylongitude</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">lon</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- Create regional wind patterns on the map.</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">surfaceparameters</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lon</span> <span style="color: #0000FF;"><</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">155.03</span> <span style="color: #0000FF;">?</span> <span style="color: #0000FF;">{</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">5.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">150</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.5</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">:</span>
<span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lon</span> <span style="color: #0000FF;"><</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">155.99</span> <span style="color: #0000FF;">?</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">90.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">20</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">150</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.4</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">:</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">180.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">25</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">150</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.3</span><span style="color: #0000FF;">}))</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">surfaceparameters</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">slices</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #004600;">null</span><span style="color: #0000FF;">,</span><span style="color: #000000;">200</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">mutatetimeslices</span><span style="color: #0000FF;">()</span>
<span style="color: #000080;font-style:italic;">-- Vary wind speeds over time.</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">slices</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">slices</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">sj</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sj</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">windvelocity</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">sj</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">windvelocity</span> <span style="color: #0000FF;">*=</span> <span style="color: #000000;">1</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">0.002</span><span style="color: #0000FF;">*</span><span style="color: #000000;">i</span>
<span style="color: #000000;">sj</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">][</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">windvelocity</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">sj</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">slices</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">slices</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">gpoints</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #004600;">null</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">9</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">lat</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">19.78</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">/</span><span style="color: #000000;">60</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">/</span><span style="color: #000000;">60</span>
<span style="color: #000000;">gpoints</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #004600;">null</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">9</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">lon</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">155.0</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">6</span><span style="color: #0000FF;">/</span><span style="color: #000000;">60</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">/</span><span style="color: #000000;">60</span>
<span style="color: #000000;">gpoints</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">lat</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lon</span><span style="color: #0000FF;">},</span> <span style="color: #000000;">surfacebylongitude</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lon</span><span style="color: #0000FF;">)}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">slices</span><span style="color: #0000FF;">[</span><span style="color: #000000;">s</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">gpoints</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">mutatetimeslices</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">fmt</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
The route taking the least time found was:
%v
which has duration %s [route found in %s]
"""</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fmt</span><span style="color: #0000FF;">,</span><span style="color: #000000;">minimum_time_route</span><span style="color: #0000FF;">(</span><span style="color: #000000;">slices</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">}))</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 1,229 ⟶ 1,605:
 
As you'd expect, this takes many times longer than Julia to run (about 24.5 minutes versus 3 minutes 20 seconds) but gets there in the end :)
<langsyntaxhighlight ecmascriptlang="wren">import "io" for File
 
/*
Line 1,650 ⟶ 2,026:
var tp = minimumTimeRoute.call(routeProb, sp, false)
System.print("The route taking the least time found was:\n %(tp.path) \nwhich has duration " +
"%((tp.duration/60).truncate) hours, %((tp.duration%60).round) minutes.")</langsyntaxhighlight>
 
{{out}}
9,482

edits