RCube
Rcube Rest Server calculates sail routes based on Grib files and sailing boat polar files
Loading...
Searching...
No Matches
engine.c
Go to the documentation of this file.
1
9#include <float.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <stdbool.h>
14#include <sys/stat.h>
15#include <sys/time.h>
16#include <time.h>
17#include <math.h>
18#include "r3types.h"
19#include "glibwrapper.h"
20#include "inline.h"
21#include "r3util.h"
22#include "grib.h"
23
24#define MAX_N_INTERVAL 1000 // for chooseDeparture
25#define LIMIT 1 // for forwardSectorOptimize
26#define MIN_VMC_RATIO 0.5 // for forwardSectorOptimize
27#define MAX_N_HISTORY 20 // for saveRoute
28#define MAX_UNREACHABLE 0 // for bestTimeDeparture. 0 means stop after first unreeach detected.
29#define MIN_DT 0.1 // in hours, the minimum delta time to progress, including penalties
30
32Pp *isocArray = NULL; // list of isochrones Two dimensions array : maxNIsoc * MAX_SIZE_ISOC
33IsoDesc *isoDesc = NULL; // Isochrone meta data. Array one dimension.
34int maxNIsoc = 0; // Max number of isochrones based on based on Grib zone time stamp and isochrone time step
35int nIsoc = 0; // total number of isochrones
36Pp lastClosest; // closest point to destination in last isochrone computed
37
40HistoryRouteList historyRoute = { .n = 0, .r = NULL };
41
42ChooseDeparture chooseDeparture; // for choice of departure time
43
45static double pOrToPDestCog = 0.0; // cog from pOr to pDest.
46static int pId = 1; // global ID for points. -1 and 0 are reserved for pOr and pDest
47static double tDeltaCurrent = 0.0; // delta time in hours between wind zone and current zone
48
49typedef struct {
50 double vmc;
51 double orthoVmc;
52 int nPt;
53} Sector;
54
55Sector sector [2][MAX_N_SECTORS]; // we keep even and odd last sectors
56
58static inline double distSegmentWithFoot(double latX, double lonX, double latA, double lonA, double latB, double lonB, double *latH, double *lonH) {
59 // Conversion degree -> NM
60 const double cosLat = cos(latX * DEG_TO_RAD);
61
62 const double xA = lonA * cosLat * 60.0, yA = latA * 60.0;
63 const double xB = lonB * cosLat * 60.0, yB = latB * 60.0;
64 const double xX = lonX * cosLat * 60.0, yX = latX * 60.0;
65
66 // Vectors AB and AX
67 const double ABx = xB - xA, ABy = yB - yA;
68 const double AXx = xX - xA, AXy = yX - yA;
69
70 // Scalar projection AX on AB
71 const double AB_AB = ABx * ABx + ABy * ABy;
72 if (AB_AB == 0.0) { // avoid zero div
73 if (latH) *latH = latA;
74 if (lonH) *lonH = lonA;
75 return hypot(AXx, AXy);
76 }
77
78 double t = (AXx * ABx + AXy * ABy) / AB_AB;
79 t = CLAMP(t, 0.0, 1.0); // CLAMP to [0 1] interval to stay in AB segment
80
81 const double xH = xA + t * ABx;
82 const double yH = yA + t * ABy;
83
84 if (latH) *latH = yH / 60.0;
85 if (lonH) *lonH = (cosLat > 0.0) ? (xH / (60.0 * cosLat)) : lonA;
86
87 return hypot(xX - xH, yX - yH);
88}
89
91static inline int findFirst (int nIsoc) {
92 int best = 0, next;
93 double dSquare, dSquareMax = 0.0;
94 const int size = isoDesc[nIsoc].size;
95 if (size <= 1) return 0;
96 const int baseIndex = nIsoc * MAX_SIZE_ISOC;
97
98 for (int i = 0; i < size; i++) {
99 next = (i >= size -1) ? 0 : i + 1;
100 double nextLat = isocArray [baseIndex + next].lat;
101 double deltaLat = isocArray [baseIndex + i].lat - nextLat;
102 double deltaLon = (isocArray [baseIndex + i].lon - isocArray [baseIndex + next].lon) * cos (DEG_TO_RAD * nextLat);
103 // square pythagore distance in degrees
104 dSquare = deltaLat * deltaLat + deltaLon * deltaLon;
105 if (dSquare > dSquareMax) {
106 dSquareMax = dSquare;
107 best = next;
108 }
109 }
110 return best;
111}
112
114static inline void initSector(int nIsoc, int nMax) {
115 memset (sector[nIsoc], 0, nMax * sizeof(Sector));
116}
117
123static inline int forwardSectorOptimize (const Pp *pOr, const Pp *pDest, int nIsoc, const Pp *isoList, int isoLen, Pp *optIsoc) {
124 int iSector, k;
125 double focalLat, focalLon; // center of sectors
126 const double epsilonDenominator = 0.01;
127 const int thresholdSector = 5;
128 const int nSectors = (nIsoc < thresholdSector) ? 180 : par.nSectors;
129 const double thetaStep = 360.0 / nSectors;
130 const double invThetaStep = 1.0 / thetaStep; // replace division by multiplication for perf
131 const double denominator = cos (DEG_TO_RAD * (pOr->lat + pDest->lat) * 0.5);
132
133 if (denominator < epsilonDenominator) { // really small !
134 fprintf (stderr, "In forwardSectorOptimize, Error denominator: %.8lf\n", denominator);
135 return 0;
136 }
137
138 if (par.jFactor == 0 || nIsoc < LIMIT) { // LIMIT SOULD BE > 0
139 focalLat = pOr->lat;
140 focalLon = pOr->lon;
141 }
142 else {
143 const double dist = isoDesc [nIsoc - LIMIT].bestVmc * (par.jFactor / 100.0) - isoDesc[nIsoc - LIMIT].biggestOrthoVmc * (par.kFactor / 100.0);
144 const double dLat = dist * cos (DEG_TO_RAD * pOrToPDestCog); // nautical miles in N S direction
145 const double dLon = dist * sin (DEG_TO_RAD * pOrToPDestCog) / denominator; // nautical miles in E W direction
146 focalLat = pOr->lat + dLat / 60.0;
147 focalLon = pOr->lon + dLon / 60.0;
148 if (focalLat < -90.0 || focalLat > 90.0) {
149 fprintf (stderr, "In forwardSectorOptimize, Error lat: %.2lf\n", focalLat);
150 return 0;
151 }
152 if (focalLon < -360.0 || focalLon > 360.0) {
153 fprintf (stderr, "In forwardSectorOptimize, Error lon: %.2f", focalLon);
154 return 0;
155 }
156 }
157
158 isoDesc [nIsoc].focalLat = focalLat;
159 isoDesc [nIsoc].focalLon = focalLon;
160 const int currentSector = nIsoc % 2;
161 const int previousSector = (nIsoc - 1) % 2;
162
163 initSector (nIsoc % 2, nSectors);
164
165 for (int i = 0; i < isoLen; i++) {
166 const Pp *iso = &isoList[i];
167
168 const double alpha = orthoCap (focalLat, focalLon, iso->lat, iso->lon);
169 double theta = pOrToPDestCog - alpha;
170
171 if (theta < 0) theta += 360.0;
172 else if (theta >= 360.0) theta -= 360.0;
173
174 int iSector = round ((360.0 - theta) * invThetaStep);
175
176 Sector *sect = &sector[currentSector][iSector];
177
178 if (iso->vmc > sect->vmc) {
179 sect->vmc = iso->vmc;
180 sect->orthoVmc = iso->orthoVmc;
181 optIsoc [iSector] = *iso;
182 }
183 sect->nPt += 1;
184 }
185
186 k = 0;
187 for (iSector = 0; iSector < nSectors; iSector += 1) {
188 const Sector *current = &sector[currentSector][iSector]; // Direct access with pointer to improve perf
189 const Sector *previous = &sector[previousSector][iSector];
190
191 if ((current->nPt > 0) &&
192 (current->vmc < pOr->dd * 1.1) &&
193 ((current->orthoVmc >= isoDesc[nIsoc - 1].biggestOrthoVmc) || (current->vmc >= MIN_VMC_RATIO * isoDesc[nIsoc - 1].bestVmc)) &&
194 ((current->vmc >= previous->vmc))) {
195
196 optIsoc[k] = optIsoc [iSector];
197 //optIsoc[k].sector = iSector;
198 k++;
199 }
200 }
201 return k;
202}
203
205static inline int optimize (const Pp *pOr, const Pp *pDest, int nIsoc, int algo, const Pp *isoList, int isoLen, Pp *optIsoc) {
206 switch (algo) {
207 case 0:
208 memcpy (optIsoc, isoList, isoLen * sizeof (Pp));
209 return isoLen;
210 case 1:
211 return forwardSectorOptimize (pOr, pDest, nIsoc, isoList, isoLen, optIsoc);
212 }
213 return 0;
214}
215
218static int buildNextIsochrone (const Pp *pOr, const Pp *pDest, const Pp *isoList, int isoLen,
219 double t, double dt, Pp *newList, double *bestVmc, double *biggestOrthoVmc) {
220 static const double epsilon = 0.01;
221 Pp newPt;
222 int lenNewL = 0;
223 double u, v, gust, w, twa, sog, uCurr, vCurr, currTwd, currTws, vDirectCap;
224 double dLat, dLon, penalty, efficiency;
225 double waveCorrection, invDenominator, twd, tws;
226 int bidon; // useless
227
228 *bestVmc = 0;
229 *biggestOrthoVmc = 0;
230
231 for (int k = 0; k < isoLen; k++) {
232 const Pp *isoPt = &isoList[k];
233
234 if (!isInZone (isoPt->lat, isoPt->lon, &zone) && (par.constWindTws == 0)) continue;
235
236 findWindGrib (isoPt->lat, isoPt->lon, t, &u, &v, &gust, &w, &twd, &tws);
237 if (tws > par.maxWind) continue; // avoid location where wind speed too high...
238
239 if (par.withCurrent) findCurrentGrib (isoPt->lat, isoPt->lon, t - tDeltaCurrent, &uCurr, &vCurr, &currTwd, &currTws);
240
241 vDirectCap = orthoCap (isoPt->lat, isoPt->lon, pDest->lat, pDest->lon);
242 const bool useMotor = (maxSpeedInPolarAt (tws * par.xWind, &polMat) < par.threshold) && (par.motorSpeed > 0);
243 invDenominator = 1.0 / MAX (epsilon, cos (DEG_TO_RAD * isoPt->lat));
244
246 else efficiency = isDay(t, zone.dataDate[0], zone.dataTime[0], isoPt->lat, isoPt->lon) ? par.dayEfficiency : par.nightEfficiency;
247
248 const double minCog = vDirectCap - par.rangeCog;
249 const double maxCog = vDirectCap + par.rangeCog;
250
251 for (double cog = minCog; cog <= maxCog; cog += par.cogStep) {
252 twa = fTwa (cog, twd);
253 newPt.amure = (twa > 0.0) ? TRIBORD : BABORD;
254 newPt.toIndexWp = pDest->toIndexWp;
255
256 if (useMotor) {
257 sog = par.motorSpeed;
258 newPt.sail = 0;
259 } else {
260 sog = efficiency * findPolar (twa, tws * par.xWind, &polMat, &sailPolMat, &newPt.sail);
261 }
262
263 newPt.motor = useMotor;
264 waveCorrection = 1.0;
265 if (par.withWaves && (w > 0.0))
266 waveCorrection = findPolar( twa, w, &wavePolMat, NULL, &bidon) / 100.0;
267
268 sog *= waveCorrection;
269 penalty = 0.0;
270
271 if (!useMotor) {
272 if (newPt.amure != isoPt->amure) {
273 if (fabs (twa) < 90.0) penalty = par.penalty0 / 3600.0; // Tack
274 else penalty = par.penalty1 / 3600.0; // Gybe
275 }
276 if (newPt.sail != isoList [k].sail) // Sail change may bug
277 penalty += par.penalty2 / 3600.0;
278 }
279
280 double realDt = dt - penalty;
281 if (realDt < MIN_DT) realDt = MIN_DT; // In case penalty is very big...
282
283 dLat = sog * (realDt) * cos (DEG_TO_RAD * cog); // nautical miles in N S direction
284 dLon = sog * (realDt) * sin (DEG_TO_RAD * cog) * invDenominator; // nautical miles in E W direction
285
286 if (par.withCurrent) { // correction for current
287 dLat += MS_TO_KN * vCurr * dt;
288 dLon += MS_TO_KN * uCurr * dt * invDenominator;
289 }
290
291 newPt.lat = isoPt->lat + dLat / 60.0;
292 newPt.lon = isoPt->lon + dLon / 60.0;
293 newPt.id = pId++;
294 newPt.father = isoPt->id;
295 newPt.vmc = 0.0;
296 newPt.orthoVmc = 0.0;
297 // newPt.sector = 0;
298
299 if (par.allwaysSea || isSeaTolerant(tIsSea, newPt.lat, newPt.lon)) {
300 newPt.dd = orthoDist (newPt.lat, newPt.lon, pDest->lat, pDest->lon);
301 const double alpha = orthoCap (pOr->lat, pOr->lon, newPt.lat, newPt.lon) - pOrToPDestCog;
302 const double newPtToPorDist = orthoDist (newPt.lat, newPt.lon, pOr->lat, pOr->lon);
303 newPt.vmc = newPtToPorDist * cos(DEG_TO_RAD * alpha);
304 newPt.orthoVmc = newPtToPorDist * fabs(sin (DEG_TO_RAD * alpha));
305 if (newPt.vmc > *bestVmc) *bestVmc = newPt.vmc;
306 if (newPt.orthoVmc > *biggestOrthoVmc) *biggestOrthoVmc = newPt.orthoVmc;
307
308 if (lenNewL < MAX_SIZE_ISOC) newList [lenNewL++] = newPt; // new point added to the isochrone
309 else return -1;
310 }
311 }
312 }
313 return lenNewL;
314}
315
317static int findFather (int ptId, int i, int lIsoc) {
318 const Pp *iso = &isocArray [i * MAX_SIZE_ISOC]; // Access isoc i
319
320 for (int k = 0; k < lIsoc; k++) {
321 if (iso[k].id == ptId) return k;
322 }
323
324 fprintf (stderr, "In findFather, Error ptId not found: %d, Isoc No:%d, Isoc Len: %d\n", ptId, i, lIsoc);
325 return -1;
326}
327
330bool isoDescToStr (char *str, size_t maxLen) {
331 char line [MAX_SIZE_LINE];
332 char strLat [MAX_SIZE_LINE], strLon [MAX_SIZE_LINE];
333 if (maxLen < MAX_SIZE_LINE)
334 return false;
335 g_strlcpy (str, "No; toWp; Size; First; Closest; Distance; VMC; FocalLat; FocalLon\n", MAX_SIZE_LINE);
336
337 for (int i = 0; i < nIsoc; i++) {
338 //double distance = isoDesc [i].distance;
339 //if (distance >= DBL_MAX) distance = -1;
340 snprintf (line, MAX_SIZE_LINE, "%03d; %03d; %03d; %03d; %03d; %07.2lf; %07.2lf; %s; %s\n", i, isoDesc [i].toIndexWp,
341 isoDesc[i].size, isoDesc[i].first,
342 isoDesc[i].closest, -1.0, isoDesc[i].bestVmc,
343 latToStr (isoDesc [i].focalLat, par.dispDms, strLat, sizeof (strLat)),
344 lonToStr (isoDesc [i].focalLon, par.dispDms, strLon, sizeof (strLon)));
345 //printf ("i = %d\n", i);
346 //printf ("%s\n", line);
347
348 if ((strlen (str) + strlen (line)) > maxLen)
349 return false;
350 g_strlcat (str, line, maxLen);
351 }
352 return true;
353}
354
356bool dumpIsocToFile (const char *fileName) {
357 FILE *f;
358 Pp pt;
359 if (fileName [0] == '\0') return false;
360 if ((f = fopen (fileName, "w")) == NULL) {
361 fprintf (stderr, "In dumpAllIsoc, Error cannot write isoc: %s\n", fileName);
362 return false;
363 }
364 fprintf (f, " n; WP; Lat; Lon; Id; Father; Amure; Sail; Motor; dd; VMC\n");
365 for (int i = 0; i < nIsoc; i++) {
366 for (int k = 0; k < isoDesc [i].size; k++) {
367 pt = isocArray [i * MAX_SIZE_ISOC + k];
368 fprintf (f, "%03d; %03d; %06.2f; %06.2f; %6d; %6d; %6d; %6d; %6d; %6.2lf; %6.2lf\n",\
369 i, pt.toIndexWp, pt.lat, pt.lon, pt.id, pt.father, pt.amure, pt.sail, pt.motor, pt.dd, pt.vmc);
370 }
371 }
372 fprintf (f, "\n");
373 fclose (f);
374 return true;
375}
376
379 // allocate or rallocate space for routes
381 fprintf (stderr, "In saveRoute, Error: MAX_N_HISTORY reached: %d\n", MAX_N_HISTORY);
382 return;
383 }
384 SailRoute *newRoutes = realloc (historyRoute.r, (historyRoute.n + 1) * sizeof(SailRoute));
385 if (newRoutes == NULL) {
386 fprintf (stderr, "In saveRoute, Error: Memory allocation failed\n");
387 return;
388 }
389 historyRoute.r = newRoutes;
390 historyRoute.r[historyRoute.n] = *route; // Copy simple fields witout pointer
391
392 // Allocation and copy of points
393 size_t pointsSize = (route->nIsoc + 1) * sizeof (SailPoint);
394 historyRoute.r[historyRoute.n].t = malloc (pointsSize);
395 if (! historyRoute.r[historyRoute.n].t) {
396 fprintf (stderr, "In saveRoute, Error: Memory allocation for SailPoint array failed\n");
397 return;
398 }
399 memcpy (historyRoute.r[historyRoute.n].t, route->t, pointsSize); // deep copy of points
400
401 historyRoute.n += 1;
402}
403
406 free (historyRoute.r);
407 historyRoute.r = NULL;
408 historyRoute.n = 0;
409}
410
412static double calcDuration (SailRoute *route) {
413 double duration = (route->n - route->nWayPoints - 1) * par.tStep;
414 for (int i = 0; i < route->nWayPoints; i += 1) {
415 duration += route->lastStepWpDuration [i];
416 }
417 duration += route->lastStepDuration;
418 return duration;
419}
420
422static void statRoute (SailRoute *route) {
423 bool manoeuvre;
424 const double epsilon = 0.00001; // hours
425 const double epsilonSog = 0.001; // hours
426 Pp p = {0};
427 if (route->n == 0) return;
428 fprintf (stdout, "route.n = %d\n", route->n);
429 char *polarFileName = g_path_get_basename (par.polarFileName);
430 g_strlcpy (route->polarFileName, polarFileName, sizeof (route->polarFileName));
431 free (polarFileName);
432 route->dataDate = zone.dataDate [0]; // save Grib origin
434 route->nSailChange = 0;
435 route->nAmureChange = 0;
440 route->nSailChange = 0;
441 route-> t[0].stamina = par.staminaVR;
442 route -> t[0].time = 0;
443 double deltaTime = par.tStep;
444 double sog = 0;
445
446 for (int i = 1; i < route->n; i++) {
447 manoeuvre = false;
448 p.lat = route->t [i-1].lat;
449 p.lon = route->t [i-1].lon;
450 if ((i > 1) && (route->t [i-1].toIndexWp >= 0) && (route->t [i-1].toIndexWp < route->nWayPoints)
451 && (route->t [i-1].toIndexWp != route->t [i].toIndexWp)) {
452
453 fprintf (stdout, "i = %d, WayPoint no: %d\n", i, route-> t[i-1].toIndexWp);
454 deltaTime = route->lastStepWpDuration [route-> t[i-1].toIndexWp];
455 }
456 else if ((i == route->n - 1) && route->destinationReached)
457 deltaTime = route->lastStepDuration;
458 else deltaTime = par.tStep;
459
460 route->t [i].time = route->t [i-1].time + deltaTime;
461
462 route->t [i-1].ld = loxoDist (route->t[i-1].lat, route->t[i-1].lon, route->t[i].lat, route->t[i].lon);
463 route->t [i-1].od = orthoDist (route->t[i-1].lat, route->t[i-1].lon, route->t[i].lat, route->t[i].lon);
464 if (deltaTime > epsilon) {
465 sog = route->t [i-1].od / deltaTime;
466 }
467 route->t [i-1].sog = sog;
468 if (sog < epsilonSog && i > 1) {
469 route->t [i-1].oCap = route->t [i-2].oCap;
470 route->t [i-1].lCap = route->t [i-2].lCap;
471 }
472 else {
473 route->t [i-1].lCap = directCap (route->t[i-1].lat, route->t[i-1].lon, route->t[i].lat, route->t[i].lon);
474 route->t [i-1].oCap = orthoCap (route->t[i-1].lat, route->t[i-1].lon, route->t[i].lat, route->t[i].lon);
475 }
476 route->totDist += route->t [i-1].od;
477
479 &route->t [i-1].u, &route->t [i-1].v, &route->t [i-1].g, &route->t [i-1].w,
480 &route->t [i-1].twd, &route->t [i-1].tws);
481
482 /*double twa = fTwa (route->t[i-1].lCap, route->t[i-1].twd);
483 route-> t [i-1].amure = (twa > 0.0) ? TRIBORD : BABORD; // rewrite because bug
484 */
485 // printf ("i = %d, od = %.2lf, tot = %.2lf\n", i, route->t [i-1].od, route->totDist);
486 if ((i > 1) && (route-> t [i-1].sail != route-> t [i-2].sail)) {
487 route->t [i-1].stamina = fmax (0.0, route->t [i-2].stamina - 100.0 * fPointLoss (STAMINA_SHIP, STAMINA_SAIL, route ->t [i-2].tws, STAMINA_FULL_PACK));
488 manoeuvre = true;
489 route->nSailChange += 1;
490 }
491 if ((i > 1) && (route-> t [i-1].amure != route-> t [i-2].amure)) {
492 route->t [i-1].stamina = fmax (0.0, route->t [i-2].stamina - 100.0 * fPointLoss (STAMINA_SHIP, STAMINA_TACK, route ->t [i-2].tws, STAMINA_FULL_PACK));
493 manoeuvre = true;
494 route->nAmureChange += 1;
495 }
496
497 if (route->t [i-1].motor) {
498 route->motorDist += route->t [i-1].od;
499 }
500 else {
501 if (route->t [i-1].amure == TRIBORD)
502 route->tribordDist += route->t [i-1].od;
503 else if (route->t [i-1].amure == BABORD)
504 route->babordDist += route->t [i-1].od;
505 }
506 // printf ("i-1: %d, amure: %d, stamina: %.2lf, twa: %.2lf\n", i - 1, route-> t [i-1].amure, route->t [i-1].stamina, twa);
507 // route->t [i-1].sail = closestInPolar (twa, route->t[i-1].tws * par.xWind, &sailPolMat);
508 route->avrTws += route->t [i-1].tws;
509 route->avrGust += route->t [i-1].g;
510 route->avrWave += route->t [i-1].w;
511 route->maxTws = MAX (route->maxTws, route->t [i-1].tws);
512 route->maxGust = MAX (route->maxGust, route->t [i-1].g);
513 route->maxWave = MAX (route->maxWave, route->t [i-1].w);
514
515 if (! manoeuvre && i > 1) {
516 const double recup = fTimeToRecupOnePoint (route->t [i-1].tws); // time in seconds to get one point
517 if (recup > 1.0)
518 route-> t [i-1].stamina = fmin (100.0, route-> t [i-2].stamina + 3600.0 * route->isocTimeStep / recup);
519 }
520 } // end for
521
522 /*if (route->t [route->n - 1].motor) {
523 route->motorDist += route->t [route->n - 1].od;
524 }
525 else {
526 if (route->t [route->n - 1].amure == TRIBORD)
527 route->tribordDist += route->t [route->n - 1].od;
528 else if (route->t [route->n - 1].amure == BABORD)
529 route->babordDist += route->t [route->n - 1].od;
530 }*/
531 p.lat = route->t [route->n - 1].lat;
532 p.lon = route->t [route->n - 1].lon;
534 &route->t [route->n-1].u, &route->t [route->n-1].v, &route->t [route->n-1].g,
535 &route->t [route->n-1].w, &route->t [route->n-1].twd, &route->t [route->n-1].tws);
536
537 route->maxTws = MAX (route->maxTws, route->t [route->n-1].tws);
538 route->maxGust = MAX (route->maxGust, route->t [route->n-1].g);
539 route->maxWave = MAX (route->maxWave, route->t [route->n-1].w);
540 route->avrTws += route->t [route->n-1].tws;
541 route->avrGust += route->t [route->n-1].g;
542 route->avrWave += route->t [route->n-1].w;
543
544 if (route->n > 1) {
545 route->t [route->n-1].ld = route->t [route->n-1].od = 0;
546 route->t [route->n-1].sog = route->t [route->n-2].sog; // convention last destination has no speed in reality
547 route->t [route->n-1].lCap = route->t [route->n-2].lCap; // convention last destination has no cap in reality
548 route->t [route->n-1].oCap = route->t [route->n-2].oCap;
549 route->t [route->n-1].sail = route->t [route->n-2].sail; // convention. No need for sail
550 route->t [route->n-1].stamina = route->t [route->n-2].stamina;
551 }
552 route->avrTws /= route->n;
553 route->avrGust /= route->n;
554 route->avrWave /= route->n;
557}
558
561bool storeRoute (SailRoute *route, const Pp *pOr, const Pp *pDest) {
562 // route->destinationReached = (pDest.id == 0);
563 int iFather;
564 route->nIsoc = nIsoc;
565 route->n = (pDest->id == 0) ? nIsoc + 2 : nIsoc + 1;
566
567 Pp pt = *pDest;
568 Pp ptLast = *pDest;
569 route->t [route->n - 1].lat = pDest->lat;
570 route->t [route->n - 1].lon = lonCanonize (pDest->lon);
571 route->t [route->n - 1].id = pDest->id;
572 route->t [route->n - 1].father = pDest->father;
573 route->t [route->n - 1].motor = pDest->motor;
574 route->t [route->n - 1].amure = pDest->amure;
575 route->t [route->n - 1].toIndexWp = pDest->toIndexWp;
576 route->t [route->n - 1].sail = pDest->sail;
577
578 fprintf (stdout, "pDest with id: %d, father: %d, toIndexWp: %d, route.n: %d\n",
579 pDest->id, pDest->father, pDest->toIndexWp, route->n);
580
581 for (int i = route->n - 3; i >= 0; i--) {
582 iFather = findFather (pt.father, i, isoDesc[i].size);
583 //printf ("ISOC: %d, ID: %d, FATHER: %d, TO_INDEX_WP: %d\n", i, pt.id, pt.father, pt.toIndexWp);
584 if (iFather == -1) {
585 fprintf (stdout, "In storeRoute: ERROR findFather at isoc: %d\n", i);
586 return false;
587 }
588 pt = isocArray [i * MAX_SIZE_ISOC + iFather];
589 if ((pt.toIndexWp < -1) || pt.toIndexWp > route->nWayPoints) {
590 fprintf (stdout, "In storeRoute: ERROR isoc: %d pt.toIndexWp: %d\n", i, pt.toIndexWp);
591 }
592 route->t [i+1].lat = pt.lat;
593 route->t [i+1].lon = lonCanonize (pt.lon);
594 route->t [i+1].id = pt.id;
595 route->t [i+1].father = pt.father;
596 route->t [i+1].motor = ptLast.motor;
597 route->t [i+1].amure = ptLast.amure;
598 route->t [i+1].toIndexWp = ptLast.toIndexWp;
599 route->t [i+1].sail = pt.sail;
600 ptLast = pt;
601 }
602 route->t [0].lat = pOr->lat;
603 route->t [0].lon = lonCanonize (pOr->lon);
604 route->t [0].id = pOr->id;
605 route->t [0].father = pOr->father;
606 route->t [0].motor = ptLast.motor;
607 route->t [0].amure = ptLast.amure;
608 route->t [0].toIndexWp = ptLast.toIndexWp;
609 route->t [0].sail = ptLast.sail;
610
611 return true;
612}
613
615static char *motorTribordBabord (bool motor, int amure, char* str, size_t maxLen) {
616 if (motor) g_strlcpy (str, "Mot", maxLen);
617 else
618 if (amure == TRIBORD)
619 g_strlcpy (str, "Tri", maxLen);
620 else
621 g_strlcpy (str, "Bab", maxLen);
622 return str;
623}
624
627bool routeToStr (const SailRoute *route, char *str, size_t maxLen, char *footer, size_t maxLenFooter) {
628 char line [MAX_SIZE_LINE], strDate [MAX_SIZE_DATE];
629 char strLat [MAX_SIZE_NAME], strLon [MAX_SIZE_NAME], strSail [MAX_SIZE_NAME];
630 char shortStr [SMALL_SIZE], strDur [MAX_SIZE_LINE];
631 double awa, aws;
632 double maxAws = 0.0;
633 double sumAws = 0.0;
634 double twa = fTwa (route->t[0].lCap, route->t[0].twd);
635 fAwaAws (twa, route->t[0].tws, route->t[0].sog, &awa, &aws);
636 if (maxLen < MAX_SIZE_LINE) {
637 fprintf (stderr, "In routeToStr, maxLen too small: %zu\n", maxLen);
638 return false;
639 }
640
641 fSailName (route->t[0].sail, strSail, sizeof (strSail)),
642
643 g_strlcpy (str, " No; WP; Lat; Lon; Date-Time; Sail; M/T/B; HDG;\
644 Dist; SOG; Twd; Twa; Tws; Gust; Awa; Aws; Waves; Stamina\n", MAX_SIZE_LINE);
645 snprintf (line, MAX_SIZE_LINE, \
646 " pOr; %3d; %-12s;%-12s; %s; %-8s; %6s; %4d°; %7.2lf; %7.2lf; %4d°; %4.0lf°; %7.2lf; %7.2lf; %4.0lf°; %7.2lf; %7.2lf; %7.2lf\n",\
647 route->t[0].toIndexWp,\
648 latToStr (route->t[0].lat, par.dispDms, strLat, sizeof (strLat)),\
649 lonToStr (route->t[0].lon, par.dispDms, strLon, sizeof (strLon)),\
650 newDate (route->dataDate, route->dataTime/100 + par.startTimeInHours + route->t[0].time, strDate, sizeof (strDate)),\
651 strSail, \
652 motorTribordBabord (route->t[0].motor, route->t[0].amure, shortStr, SMALL_SIZE),\
653 ((int) (route->t[0].oCap + 360) % 360), route->t[0].od, route->t[0].sog,\
654 (int) (route->t[0].twd + 360) % 360,\
655 twa, route->t[0].tws,\
656 MS_TO_KN * route->t[0].g, awa, aws, route->t[0].w, route->t[0].stamina);
657
658 g_strlcat (str, line, maxLen);
659 for (int i = 1; i < route->n; i++) {
660 twa = fTwa (route->t[i].lCap, route->t[i].twd);
661 fAwaAws (twa, route->t[i].tws, route->t[i].sog, &awa, &aws);
662 if (aws > maxAws) maxAws = aws;
663 sumAws += aws;
664 if ((fabs(route->t[i].lon) > 180.0) || (fabs (route->t[i].lat) > 90.0))
665 snprintf (line, MAX_SIZE_LINE, " Isoc %3d: Error on latitude or longitude\n", i-1);
666 else
667 snprintf (line, MAX_SIZE_LINE, \
668 "%4d; %3d; %-12s;%-12s; %s; %-8s; %6s; %4d°; %7.2f; %7.2lf; %4d°; %4.0lf°; %7.2lf; %7.2lf; %4.0lf°; %7.2lf; %7.2lf; %7.2lf\n",\
669 i-1,\
670 route->t[i].toIndexWp,\
671 latToStr (route->t[i].lat, par.dispDms, strLat, sizeof (strLat)),\
672 lonToStr (route->t[i].lon, par.dispDms, strLon, sizeof (strLon)),\
673 newDate (route->dataDate, route->dataTime/100 + par.startTimeInHours + route->t[i].time, strDate, sizeof (strDate)), \
674 fSailName (route->t[i].sail, strSail, sizeof (strSail)), \
675 motorTribordBabord (route->t[i].motor, route->t[i].amure, shortStr, SMALL_SIZE), \
676 ((int) (route->t[i].oCap + 360) % 360), route->t[i].od, route->t[i].sog,\
677 (int) (route->t[i].twd + 360) % 360,\
678 fTwa (route->t[i].lCap, route->t[i].twd), route->t[i].tws,\
679 MS_TO_KN * route->t[i].g, awa, aws, route->t[i].w, route->t[i].stamina);
680 g_strlcat (str, line, maxLen);
681 }
682
683 g_strlcat (str, "\n \n", maxLen);
684 snprintf (line, MAX_SIZE_LINE, " Avr/Max Tws : %.2lf/%.2lf Kn\n", route->avrTws, route->maxTws);
685 g_strlcat (str, line, maxLen);
686 snprintf (line, MAX_SIZE_LINE, " Total/Motor Dist.: %.2lf/%.2lf NM\n", route->totDist, route->motorDist);
687 g_strlcat (str, line, maxLen);
688 snprintf (line, MAX_SIZE_LINE, " Total duration : %sHours\n", \
689 durationToStr (route->duration, strDur, sizeof (strDur)));
690 g_strlcat (str, line, maxLen);
691 snprintf (line, MAX_SIZE_LINE, " Sail Changes : %d\n", route->nSailChange);
692 g_strlcat (str, line, maxLen);
693 snprintf (line, MAX_SIZE_LINE, " Amures Changes : %d\n", route->nAmureChange);
694 g_strlcat (str, line, maxLen);
695 snprintf (line, MAX_SIZE_LINE, " Polar file : %s\n", route->polarFileName);
696 g_strlcat (str, line, maxLen);
697
698 snprintf (footer, maxLenFooter, "%s Arrival: %s Route length: %d, Isoc time Step: %.2lf",
700 newDate (route->dataDate, route->dataTime/100 + route->t[0].time + route->duration, strDate, sizeof (strDate)),\
701 route->n,
703 return true;
704}
705
712static inline bool simpleGoalP (const Pp *pA, const Pp *pDest, double t, double dt, double *timeTo,
713 double *distance, bool *motor, int *amure, int *sail) {
714 static const double epsilon = 0.1; // kn
715 double u, v, gust, w, twd, tws, sog, efficiency;
716 int bidon;
717 const double d = orthoDist (pDest->lat, pDest->lon, pA->lat, pA->lon);
718 *distance = d;
719
720 // Cap (COG) from pA to pDest
721 const double coeffLat = cos(DEG_TO_RAD * ((pA->lat + pDest->lat) * 0.5));
722 const double dLat = pDest->lat - pA->lat;
723 const double dLon = (pDest->lon - pA->lon) * coeffLat;
724 const double cog = RAD_TO_DEG * atan2(dLon, dLat);
725
726 // Wind & waves at A point
727 findWindGrib(pA->lat, pA->lon, t, &u, &v, &gust, &w, &twd, &tws);
728
729 // TWA & amure
730 const double twa = fTwa(cog, twd);
731 *amure = (twa > 0) ? TRIBORD : BABORD;
732
733 // Motor if speed with polar under threshold
734 const bool useMotor = ((maxSpeedInPolarAt(tws * par.xWind, &polMat) < par.threshold) && (par.motorSpeed > 0.0));
735 *motor = useMotor;
736
737 // Day/Night efficiency
739 else efficiency = isDay(t, zone.dataDate[0], zone.dataTime[0], pA->lat, pA->lon) ? par.dayEfficiency : par.nightEfficiency;
740
741 // Speed (kn)
742 int sailChoice = 0;
743 if (useMotor) {
744 sog = par.motorSpeed;
745 *sail = 0;
746 } else {
747 sog = efficiency * findPolar(twa, tws * par.xWind, &polMat, &sailPolMat, &sailChoice);
748 *sail = sailChoice;
749 }
750
751 // Wave Correction
752 if (par.withWaves && w > 0.0 ) {
753 const double waveCorrection = findPolar(twa, w, &wavePolMat, NULL, &bidon);
754 if (waveCorrection > 0.0) sog *= waveCorrection * 0.01;
755 }
756
757 if (sog <= epsilon) {
758 *timeTo = DBL_MAX; // hours
759 return false;
760 }
761
762 // Time to go to best point in hours
763 *timeTo = d / sog; // NM / (NM/h) = h
764
765 // Reachability test in dt interval time (hours)
766 return (sog * dt) >= d;
767}
768
772static inline bool simpleGoal (Pp *pDest, Pp *isoList, int len, double t, double dt, double *lastStepDuration, bool *motor, int *amure) {
773 double bestTime = DBL_MAX, time, distance;
774 bool destinationReached = false, locMotor, bestMotor = false;
775 int sail, locAmure, bestAmure = 0;
776
777 for (int k = 0; k < len; k++) {
778 const Pp *curr = &isoList[k];
779 if (!par.allwaysSea && !isSea(tIsSea, curr->lat, curr->lon)) continue;
780 if (simpleGoalP (curr, pDest, t, dt, &time, &distance, &locMotor, &locAmure, &sail)) {
781 destinationReached = true;
782 }
783 if (time < bestTime) {
784 bestTime = time;
785 if (destinationReached) {
786 pDest->father = curr->id;
787 pDest->motor = *motor;
788 pDest->amure = *amure;
789 pDest->sail = sail;
790 bestMotor = locMotor;
791 bestAmure = locAmure;
792 }
793 // if (distance < minDistance) minDistance = distance;
794 }
795 }
796 // isoDesc[nIsoc -1].distance = minDistance;
797 *lastStepDuration = bestTime;
798 *motor = bestMotor;
799 *amure = bestAmure;
800 return destinationReached;
801}
802
811static inline bool goalP (const Pp *pA, const Pp *pB, const Pp *pDest, double t,
812 double dt, double *timeTo,
813 double *distance, bool *motor, int *amure, int *sail, bool *bestFirst) {
814 static const double epsilon = 0.1; // kn
815 double u, v, gust, w, twd, tws, twa, sog, efficiency;
816 int bidon; // unused but needed by API
817
818 // 1) Minimum distance
819 double bestLat, bestLon;
820 double latH, lonH;
821 const double distToSegment = distSegmentWithFoot(pDest->lat, pDest->lon, pA->lat, pA->lon, pB->lat, pB->lon, &latH, &lonH);
822 const double dA = orthoDist (pDest->lat, pDest->lon, pA->lat, pA->lon);
823 const double dB = orthoDist (pDest->lat, pDest->lon, pB->lat, pB->lon);
824 if (dA < dB) {
825 *distance = dA;
826 bestLat = pA->lat;
827 bestLon = pA->lon;
828 *bestFirst = true;
829 }
830 else {
831 *distance = dB;
832 bestLat = pB->lat;
833 bestLon = pB->lon;
834 *bestFirst = false;
835 }
836 // 2) Cap (COG) from best to pDest
837 const double coeffLat = cos(DEG_TO_RAD * ((bestLat + pDest->lat) * 0.5));
838 const double dLat = pDest->lat - bestLat;
839 const double dLon = (pDest->lon - bestLon) * coeffLat;
840 const double cog = RAD_TO_DEG * atan2(dLon, dLat);
841
842 // 3) Wind & waves at H point
843 findWindGrib(bestLat, bestLon, t, &u, &v, &gust, &w, &twd, &tws);
844
845 // 4) TWA & amure
846 twa = fTwa(cog, twd);
847 *amure = (twa > 0.0) ? TRIBORD : BABORD;
848
849 // 5) Motor if speed with polar under threshold
850 const bool useMotor = ((maxSpeedInPolarAt(tws * par.xWind, &polMat) < par.threshold) && (par.motorSpeed > 0.0));
851 *motor = useMotor;
852 // 6) Day/Night efficiency
854 else efficiency = isDay(t, zone.dataDate[0], zone.dataTime[0], bestLat, bestLon) ? par.dayEfficiency : par.nightEfficiency;
855
856
857 // 7) Speed (kn)
858 int sailChoice = 0;
859 if (useMotor) {
860 sog = par.motorSpeed;
861 *sail = 0;
862 } else {
863 sog = efficiency * findPolar(twa, tws * par.xWind, &polMat, &sailPolMat, &sailChoice);
864 *sail = sailChoice;
865 }
866
867 // 8) Wave Correction
868 if (par.withWaves && (w > 0.0)) {
869 const double waveCorrection = findPolar(twa, w, &wavePolMat, NULL, &bidon);
870 if (waveCorrection > 0) sog *= (waveCorrection / 100.0);
871 }
872
873 if (sog <= epsilon) {
874 *timeTo = DBL_MAX; // hours
875 return false;
876 }
877
878 // 9) Time to go to best point in hours
879 *timeTo = *distance / sog; // NM / (NM/h) = h
880
881 // 10) Reachability test in dt interval time (hours)
882 return (sog * dt) > fmin (distToSegment, *distance); // distSegment should allays be lesser than distance
883 // return (sog * dt) > *distance;
884}
885
889static inline bool goal (Pp *pDest, Pp *isoList, int len, double t, double dt, double *lastStepDuration, bool *motor, int *amure) {
890 double bestTime = DBL_MAX;
891 double time, distance;
892 bool destinationReached = false;
893 int sail;
894 // double minDistance = 9999.99;
895 const Pp *prev = &isoList[0];
896 bool bestFirst;
897
898 for (int k = 1; k < len; k++) {
899 const Pp *curr = &isoList[k];
900 if (par.allwaysSea || isSeaTolerant(tIsSea, curr->lat, curr->lon)) {
901 if (goalP (prev, curr, pDest, t, dt, &time, &distance, motor, amure, &sail, &bestFirst)) {
902 destinationReached = true;
903 }
904 if (time < bestTime) {
905 bestTime = time;
906 if (destinationReached) {
907 pDest->father = bestFirst ? prev->id : curr->id;
908 pDest->motor = *motor;
909 pDest->amure = *amure;
910 pDest->sail = sail;
911 }
912 }
913 // if (distance < minDistance) minDistance = distance;
914 }
915 prev = curr;
916 }
917 // isoDesc[nIsoc -1].distance = minDistance;
918 *lastStepDuration = bestTime;
919 return destinationReached;
920}
921
923static int fClosest (const Pp *isoc, int n, const Pp *pDest, Pp *closest) {
924 *closest = isoc [0];
925 double lastClosestDist = DBL_MAX; // closest distance to destination in last isochrone computed
926 double d;
927 int i;
928 int index = -1;
929 for (i = 0; i < n; i++) {
930 const Pp *curr = &isoc[i];
931 d = orthoDist (pDest->lat, pDest->lon, curr->lat, curr->lon);
932 if (d < lastClosestDist) {
933 lastClosestDist = d;
934 *closest = *curr;
935 index = i;
936 }
937 }
938 return index;
939}
940
943static void replicate(int n) {
944 if (n <= 0) return;
945 const int len = isoDesc[n - 1].size;
946 Pp *src = &isocArray[(n - 1) * MAX_SIZE_ISOC];
947 Pp *dst = &isocArray[n * MAX_SIZE_ISOC];
948
949 memcpy(dst, src, len * sizeof(Pp)); // copy isochrone n - 1 to isochrone n
950
951 for (int i = 0; i < len; i++) {
952 int idSrc = src [i].id; // Be careful to specific id and father fields
953 dst[i].id = idSrc + len;
954 dst[i].father = idSrc;
955 }
956 isoDesc[n] = isoDesc[n - 1];
957}
958
966static int routing (Pp *pOr, Pp *pDest, int toIndexWp, double t, double dt, double *lastStepDuration) {
967 const double minStep = 0.25;
968 bool motor = false;
969 int amure, sail = 0;
970 double distance;
971 double timeToReach = 0;
972 int lTempList = 0;
973 double timeLastStep;
974 Pp *tempList = NULL; // one dimension array of points
975 bool bidon;
976
977 if (dt < minStep) {
978 fprintf (stderr, "In routing: time step for routing <= %.2lf\n", minStep);
979 return -1;
980 }
981
982 if ((tempList = malloc (MAX_SIZE_ISOC * sizeof(Pp))) == NULL) {
983 fprintf (stderr, "in routing: error in memory templIst allocation\n");
984 return -1;
985 }
986
987 maxNIsoc = (int) ((1 + zone.timeStamp [zone.nTimeStamp - 1]) / dt);
988 if (maxNIsoc > MAX_N_ISOC) {
989 fprintf (stderr, "in routing maxNIsoc exeed MAX_N_ISOC\n");
990 free (tempList);
991 return -1;
992 }
993
994 Pp *tempIsocArray = (Pp*) realloc (isocArray, maxNIsoc * MAX_SIZE_ISOC * sizeof(Pp));
995 if (tempIsocArray == NULL) {
996 fprintf (stderr, "in routing: realloc error for isocArray\n");
997 free (tempList);
998 return -1;
999 }
1000 isocArray = tempIsocArray;
1001
1002 IsoDesc *tempIsoDesc = (IsoDesc *) realloc (isoDesc, maxNIsoc * sizeof (IsoDesc));
1003 if (tempIsoDesc == NULL) {
1004 fprintf (stderr, "in routing: realloc for IsoDesc failed\n");
1005 free (isocArray);
1006 free (tempList);
1007 return -1;
1008 }
1009 isoDesc = tempIsoDesc;
1010
1011 SailPoint *tempSailPoint = (SailPoint *) realloc (route.t, (maxNIsoc + 1) * sizeof(SailPoint));
1012 if (tempSailPoint == NULL) {
1013 fprintf (stderr, "in routing: realloc for route.t failed\n");
1014 free (isoDesc);
1015 free (isocArray);
1016 free (tempList);
1017 return -1;
1018 }
1019 route.t = tempSailPoint;
1020
1021 pOr->dd = orthoDist (pOr->lat, pOr->lon, pDest->lat, pDest->lon);
1022 pOr->vmc = 0;
1023 //pOrToPDestCog = orthoCap (pOr->lat, pOr->lon, pDest->lat, pDest->lon);
1024 pOrToPDestCog = directCap (pOr->lat, pOr->lon, pDest->lat, pDest->lon); // better
1025 pDest->toIndexWp = toIndexWp;
1026 tempList [0] = *pOr; // list with just one element;
1027 initSector (nIsoc % 2, par.nSectors);
1028
1029 if (goalP (pOr, pOr, pDest, t, dt, &timeToReach, &distance, &motor, &amure, &sail, &bidon)) {
1030 pDest->father = pOr->id;
1031 pDest->motor = motor;
1032 pDest->amure = amure;
1033 pDest->sail = sail;
1034 *lastStepDuration = timeToReach;
1035 free (tempList);
1036 fprintf (stdout, "destination reached directly. No isochrone\n");
1037 return nIsoc + 1;
1038 }
1039 isoDesc [nIsoc].size = buildNextIsochrone (pOr, pDest, tempList, 1, t, dt,
1040 &isocArray [nIsoc * MAX_SIZE_ISOC], &isoDesc [nIsoc].bestVmc, &isoDesc [nIsoc].biggestOrthoVmc);
1041
1042 if (isoDesc [nIsoc].size == -1) {
1043 free (tempList);
1044 fprintf (stderr, "In routing: isoc Size error, nIsoc: %d\n", nIsoc);
1045 return -1;
1046 }
1047 // printf ("%-20s%d, %d\n", "Isochrone no, len: ", 0, isoDesc [0].size);
1048 // keep track of closest point in isochrone
1049 isoDesc [nIsoc].first = 0;
1051 isoDesc [nIsoc].toIndexWp = toIndexWp;
1052 isoDesc [nIsoc].focalLat = pOr->lat;
1053 isoDesc [nIsoc].focalLon = pOr->lon;
1054 if (isoDesc [nIsoc].size == 0) { // no wind at the beginning.
1055 isoDesc [nIsoc].size = 1;
1056 isocArray [nIsoc * MAX_SIZE_ISOC + 0] = *pOr;
1057 }
1058
1059 nIsoc += 1;
1060 //printf ("Routing t = %.2lf, zone: %.2ld\n", t, zone.timeStamp [zone.nTimeStamp-1]);
1061 while (t < (zone.timeStamp [zone.nTimeStamp - 1]/* + par.tStep*/) && (nIsoc < maxNIsoc)) { // ATT
1062 if (g_atomic_int_get (&route.ret) == ROUTING_STOPPED) { // -2
1063 free (tempList);
1064 return ROUTING_STOPPED; // stopped by user in another thread !!!
1065 }
1066 t += dt;
1067 // printf ("nIsoc = %d\n", nIsoc);
1068 if (simpleGoal (pDest, &isocArray [(nIsoc - 1) * MAX_SIZE_ISOC], isoDesc[nIsoc - 1].size, t, dt, &timeLastStep, &motor, &amure)) {
1069 // if (goal (pDest, &isocArray [(nIsoc - 1) * MAX_SIZE_ISOC], isoDesc[nIsoc - 1].size, t, dt, &timeLastStep, &motor, &amure)) {
1070
1071 isoDesc [nIsoc].size = optimize (pOr, pDest, nIsoc, par.opt, tempList, lTempList, &isocArray [nIsoc * MAX_SIZE_ISOC]);
1072 if (isoDesc [nIsoc].size == 0) { // no Wind ... we copy
1073 fprintf (stderr, "In routing, goal reached but no wind at isoc: %d\n", nIsoc);
1074 replicate (nIsoc);
1075 }
1078 isoDesc [nIsoc].toIndexWp = toIndexWp;
1079 *lastStepDuration = timeLastStep;
1080 fprintf (stdout, "In routing, Destination reached to WP %d for %s\n", toIndexWp, competitors.t [competitors.runIndex].name);
1081 fprintf (stdout, "pDest.id: %d, pDest.father: %d, pDest.toIndexWP: %d\n", pDest->id, pDest->father, pDest->toIndexWp);
1082 free (tempList);
1083 return nIsoc + 1;
1084 }
1085 lTempList = buildNextIsochrone (pOr, pDest, &isocArray [(nIsoc -1) * MAX_SIZE_ISOC],
1086 isoDesc [nIsoc - 1].size, t, dt, tempList, &isoDesc [nIsoc].bestVmc, &isoDesc [nIsoc].biggestOrthoVmc);
1087 if (lTempList == -1) {
1088 free (tempList);
1089 fprintf (stderr, "In routing: buildNextIsochrone return: -1 value. See MAX_SIZE_ISOC\n");
1090 return -1;
1091 }
1092 isoDesc [nIsoc].size = optimize (pOr, pDest, nIsoc, par.opt, tempList, lTempList, &isocArray [nIsoc * MAX_SIZE_ISOC]);
1093 if (isoDesc [nIsoc].size == 0) { // no Wind ... we copy
1094 fprintf (stderr, "In routing, no wind at isoc: %d\n", nIsoc);
1095 replicate (nIsoc);
1096 }
1099 isoDesc [nIsoc].toIndexWp = toIndexWp;
1100 // printf ("Isoc: %d Biglist length: %d optimized size: %d\n", nIsoc, lTempList, isoDesc [nIsoc].size);
1101 nIsoc += 1;
1102 }
1103 *lastStepDuration = 0.0;
1104 free (tempList);
1105 return NIL;
1106}
1107
1109static void initRouting (void) {
1110 isocArray = NULL;
1111 isoDesc = NULL;
1112 maxNIsoc = 0;
1113 nIsoc = 0;
1114 pOrToPDestCog = 0;
1115 memset (sector, 0, sizeof(sector));
1117 tDeltaCurrent = zoneTimeDiff (&currentZone, &zone); // global variable
1118 par.pOr.id = -1;
1119 par.pOr.father = -1;
1120 par.pDest.id = 0;
1121 par.pDest.father = 0;
1122 pId = 1;
1123 memset (&route, 0, sizeof (SailRoute));
1125 route.destinationReached = false;
1126}
1127
1142static void checkArrival (SailRoute *route, Pp *pDest) {
1143 double foot0Lat, foot0Lon, foot1Lat, foot1Lon;
1144 strlcpy (route->lastPointInfo, "\"\"", sizeof route->lastPointInfo);
1145
1146 const int lastI = route->nIsoc - 1; // last isochrone
1147 if (lastI < 1) return;
1148 const int size = isoDesc[lastI].size;
1149 if (size < 1 || size > MAX_SIZE_ISOC) return;
1150
1151 int index;
1152 if (route->destinationReached) index = findFather (pDest->father, lastI, size);
1153 else index = findFather (pDest->id, lastI, size);
1154
1155 int prev = index - 1;
1156 if (prev < 0) prev = size - 1;
1157 int next = index + 1;
1158 if (next >= size) next = 0;
1159
1160 Pp pCurr = isocArray [lastI * MAX_SIZE_ISOC + index];
1161 Pp pPrev = isocArray [lastI * MAX_SIZE_ISOC + prev];
1162 Pp pNext = isocArray [lastI * MAX_SIZE_ISOC + next];
1163
1164 const double dSeg0 = orthoDist (pPrev.lat, pPrev.lon, pCurr.lat, pCurr.lon);
1165 const double dSeg1 = orthoDist (pNext.lat, pNext.lon, pCurr.lat, pCurr.lon);
1166 const double dCurr = orthoDist (pDest->lat, pDest->lon, pCurr.lat, pCurr.lon);
1167 const double dPrev = orthoDist (pDest->lat, pDest->lon, pPrev.lat, pPrev.lon);
1168 const double dNext = orthoDist (pDest->lat, pDest->lon, pNext.lat, pNext.lon);
1169
1170 const double dFoot0 = distSegmentWithFoot(pDest->lat, pDest->lon, pPrev.lat, pPrev.lon,
1171 pCurr.lat, pCurr.lon, &foot0Lat, &foot0Lon); // NM
1172
1173 const double dFoot1 = distSegmentWithFoot(pDest->lat, pDest->lon, pNext.lat, pNext.lon,
1174 pCurr.lat, pCurr.lon, &foot1Lat, &foot1Lon); // NM
1175
1176 snprintf (route->lastPointInfo, sizeof route->lastPointInfo,
1177 "{\n"
1178 " \"latDest\": %.6lf, \"lonDest\": %.6lf, \"latCurr\": %.6lf, \"lonCurr\": %.6lf,\n"
1179 " \"latPrev\": %.6lf, \"lonPrev\": %.6lf, \"latNext\": %.6lf, \"lonNext\": %.6lf,\n"
1180 " \"latFoot0\": %.6lf, \"lonFoot0\": %.6lf, \"latFoot1\": %.6lf, \"lonFoot1\": %.6lf,\n"
1181 " \"dSeg0\": %.2lf, \"dSeg1\": %.2lf, \"dCurr\": %.2lf,\n"
1182 " \"dPrev\": %.2lf, \"dNext\": %.2lf, \"dFoot0\": %.2lf, \"dFoot1\": %.2lf\n"
1183 "}",
1184 pDest->lat, pDest->lon, pCurr.lat, pCurr.lon, pPrev.lat, pPrev.lon, pNext.lat, pNext.lon,
1185 foot0Lat, foot0Lon, foot1Lat, foot1Lon,
1186 dSeg0, dSeg1, dCurr,
1187 dPrev, dNext, dFoot0, dFoot1
1188 );
1189}
1190
1193 struct timeval t0, t1;
1194 long ut0, ut1;
1195 double lastStepDuration;
1196 Pp pNext;
1197 initRouting ();
1199 fprintf (stdout, "In routingLaunch: competitor index: %d, name: %s\n", competitors.runIndex, competitors.t[competitors.runIndex].name);
1200 int ret = -1;
1201
1202 gettimeofday (&t0, NULL);
1203 ut0 = t0.tv_sec * MILLION + t0.tv_usec;
1204 double wayPointStartTime = par.startTimeInHours;
1205
1206 fprintf (stdout, "Before Routing, pDest ID: %d, Father: %d\n", par.pDest.id, par.pDest.father);
1207 //Launch routing
1208 if (wayPoints.n == 0) {
1209 ret = routing (&par.pOr, &par.pDest, -1, wayPointStartTime, par.tStep, &lastStepDuration);
1210 }
1211 else {
1212 for (int i = 0; i < wayPoints.n; i ++) {
1213 pNext.lat = wayPoints.t[i].lat;
1214 pNext.lon = wayPoints.t[i].lon;
1215 pNext.id = -2 - i;
1216 if (i == 0) {
1217 ret = routing (&par.pOr, &pNext, i, wayPointStartTime, par.tStep, &lastStepDuration);
1218 }
1219 else {
1220 ret = routing (&isocArray [(nIsoc-1) * MAX_SIZE_ISOC + 0], &pNext, i, wayPointStartTime, par.tStep, &lastStepDuration);
1221 }
1222 fprintf (stdout, "After Waypoint; %d, ret: %d, pNext ID: %d, Father: %d\n", i, ret, pNext.id, pNext.father);
1223 route.lastStepWpDuration [i] = lastStepDuration;
1224 if (ret > 0) {
1225 wayPointStartTime = par.startTimeInHours + (nIsoc * par.tStep) + lastStepDuration;
1226 isocArray [nIsoc * MAX_SIZE_ISOC + 0].lat = pNext.lat;
1227 isocArray [nIsoc * MAX_SIZE_ISOC + 0].lon = pNext.lon;
1228 isocArray [nIsoc * MAX_SIZE_ISOC + 0].father = pNext.father;
1229 isocArray [nIsoc * MAX_SIZE_ISOC + 0].amure = pNext.amure;
1230 isocArray [nIsoc * MAX_SIZE_ISOC + 0].id = pId++;
1231 isoDesc [nIsoc].size = 1;
1232 isoDesc [nIsoc].toIndexWp = (i < (wayPoints.n - 1)) ? i + 1 : -1;
1237 nIsoc += 1;
1238 }
1239 else break;
1240 }
1241 if (ret > 0) {
1242 ret = routing (&isocArray [(nIsoc-1) * MAX_SIZE_ISOC + 0], &par.pDest, -1, wayPointStartTime, par.tStep, &lastStepDuration);
1243 }
1244 }
1245 fprintf (stdout, "After Routing, ret: %d, pDest ID: %d, Father: %d\n", ret, par.pDest.id, par.pDest.father);
1246 if (ret == -1) {
1248 return NULL;
1249 }
1250 route.lastStepDuration = lastStepDuration;
1252 fprintf (stdout, "Number of wayPoints: %d\n", wayPoints.n);
1253
1254 gettimeofday (&t1, NULL);
1255 ut1 = t1.tv_sec * MILLION + t1.tv_usec;
1256 route.calculationTime = (double) ((ut1-ut0)/ 1000000.0); // in seconds
1257 route.destinationReached = (ret > 0 && par.pDest.father != 0);
1259 // if (storeRoute (&route, &par.pOr, &lastClosest))
1260 g_atomic_int_set (&route.ret, ret); // route.ret is positionned just before ending. route.ret is shared between threads !
1261 else
1263 statRoute (&route);
1265 return NULL;
1266}
1267
1270 double minDuration = DBL_MAX, maxDuration = 0;
1271 int localRet, nUnreachable = 0;
1272
1276 chooseDeparture.tStop = chooseDeparture.tEnd; // default value
1277
1280 fprintf (stderr, "In bestTimeDeparture, chooseDeparture.count exceed limit %d\n", chooseDeparture.count);
1281 break;
1282 }
1284 routingLaunch ();
1285 localRet = g_atomic_int_get (&route.ret);
1286 if (localRet == ROUTING_STOPPED) {
1288 return NULL;
1289 }
1290 if (localRet > 0) {
1292 if (route.duration < minDuration) {
1293 minDuration = route.duration;
1296 fprintf (stdout, "Count: %d, time %.2lf, duration: %.2lf, min: %.2lf, bestTime: %.2lf\n", \
1298 }
1299 if (route.duration > maxDuration) {
1300 maxDuration = route.duration;
1301 }
1302 }
1303 else {
1305 fprintf (stdout, "Count: %d, time %.2lf, Unreachable\n", chooseDeparture.count, t);
1306 break;
1308 if (nUnreachable > MAX_UNREACHABLE) {
1309 break;
1310 }
1311 nUnreachable += 1;
1312 }
1314 }
1315 if (chooseDeparture.bestCount >= 0) {
1317 fprintf (stdout, "Solution exist: best startTime: %.2lf\n", par.startTimeInHours);
1318 chooseDeparture.minDuration = minDuration;
1319 chooseDeparture.maxDuration = maxDuration;
1320 routingLaunch ();
1322 }
1323 else {
1325 fprintf (stdout, "No solution\n");
1326 }
1327 return NULL;
1328}
1329
1332 bool existSolution = false;
1333 int localRet;
1334
1335 for (int i = 0; i < competitors.n; i += 1) // reset eta(s)
1336 competitors.t [i].strETA [0] = '\0';
1337
1338 // we begin by the end in order to keep main (index 0) competitor as last for display route
1339 for (int i = competitors.n - 1; i >= 0; i -= 1) {
1340 fprintf (stdout, "In allCompetitors: competitor: %d\n", i);
1342 par.pOr.lat = competitors.t [i].lat;
1343 par.pOr.lon = competitors.t [i].lon;
1344 routingLaunch ();
1345 saveRoute (&route);
1346 localRet = g_atomic_int_get (&route.ret);
1347 if (localRet == ROUTING_STOPPED) {
1349 return NULL;
1350 }
1351 if (localRet < 0) {
1352 fprintf (stderr, "In allCompetitors, No solution for competitor: %s with return: %d\n",\
1354 g_strlcpy (competitors.t [i].strETA, "No Solution", MAX_SIZE_DATE);
1355 competitors.t [i].duration = 0; // hours
1356 competitors.t [i].dist = 0;
1357 continue;
1358 }
1361 competitors.t [i].duration = route.duration; // hours
1363 existSolution = true;
1364 }
1366 return NULL;
1367}
1368
1370void logReport (int n) {
1371 time_t now = time (NULL);
1372 char arrivalDate [MAX_SIZE_DATE];
1373 char startDate [MAX_SIZE_LINE];
1374 char strLat0 [MAX_SIZE_NAME], strLon0 [MAX_SIZE_NAME], strLat1 [MAX_SIZE_NAME], strLon1 [MAX_SIZE_NAME];
1375 struct tm *timeInfos = gmtime (&now);
1376 FILE *f;
1377 if (par.logFileName [0] == '\0') return; // check that a log file name is defined
1378 struct stat st;
1379 const bool existFile = stat (par.logFileName, &st) == 0;
1380
1381 if ((f = fopen (par.logFileName, "a")) == NULL) {
1382 fprintf (stderr, "In logReport, Error opening lo report file: %s\n", par.logFileName);
1383 return;
1384 }
1385
1386 if (! existFile)
1387 fprintf (f, "logDate; isocStep; nOcc; Reach; nWP; pOr lat; pOr lon; pDest lat; pDest lon; Start; Arrival; toDest; HDG; polar; grib\n");
1388
1390 startDate, sizeof (startDate));
1391
1393 arrivalDate, sizeof (arrivalDate));
1394
1395 char *polarFileName = g_path_get_basename (par.polarFileName);
1396 char *gribFileName = g_path_get_basename (par.gribFileName);
1397
1398 fprintf (f, "%04d-%02d-%02d %02d:%02d:%02d; %4.2lf; %4d; %c; %d; %s; %s; %s; %s; %s; %s; %.2lf; %3d°; %s; %s\n",
1399 timeInfos->tm_year+1900, timeInfos->tm_mon+1, timeInfos->tm_mday,
1400 timeInfos->tm_hour, timeInfos->tm_min, timeInfos->tm_sec,
1401 par.tStep, n, (route.destinationReached) ? 'R' : 'U',
1402 wayPoints.n,
1403 latToStr (par.pOr.lat, par.dispDms, strLat0, sizeof (strLat0)),
1404 lonToStr (par.pOr.lon, par.dispDms, strLon0, sizeof (strLon0)),
1405 latToStr (par.pDest.lat, par.dispDms, strLat1, sizeof (strLat1)),
1406 lonToStr (par.pDest.lon, par.dispDms, strLon1, sizeof (strLon1)),
1407 startDate,
1408 arrivalDate,
1410 (int) (route.t[0].oCap + 360) % 360,
1411 polarFileName,
1412 gribFileName
1413 );
1414 free (polarFileName);
1415 free (gribFileName);
1416 fclose (f);
1417}
1418
1420bool exportRouteToGpx (const SailRoute *route, const char *fileName) {
1421 FILE *f;
1422 char strTime [MAX_SIZE_DATE];
1423 if (! route || ! fileName || fileName [0] == '\0') return false;
1424
1425 if ((f = fopen (fileName, "w")) == NULL) {
1426 fprintf (stderr, "In exportRouteToGpx: Impossible to write open %s:", fileName);
1427 return true;
1428 }
1429 // GPX header
1430 fprintf (f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1431 fprintf (f, "<gpx version=\"1.1\" creator=\"%s\" xmlns=\"http://www.topografix.com/GPX/1/1\">\n", PROG_NAME);
1432 fprintf (f, " <rte>\n");
1433 fprintf (f, " <name>Maritime Route</name>\n");
1434
1435 // Parcours des points et écriture des <trkpt>
1436 for (int i = 0; i < route->n; i++) {
1437 SailPoint *p = &route->t[i];
1438
1439 newDate (route->dataDate, route->dataTime/100 + par.startTimeInHours + p->time, strTime, sizeof (strTime));
1440
1441 fprintf (f, " <rtept lat=\"%.6f\" lon=\"%.6f\">\n", p->lat, p->lon);
1442 fprintf (f, " <name>%d</name>\n", i);
1443 fprintf (f, " <time>%s</time>\n", strTime);
1444 fprintf (f, " <course>%.2f</course>\n", fmod (p->oCap + 360.0, 360.0)); // degrees
1445 fprintf (f, " <speed>%.2f</speed>\n", p->sog); // speed (knots)
1446 fprintf (f, " </rtept>\n");
1447 }
1448 fprintf (f, " <rtept lat=\"%.6f\" lon=\"%.6f\">\n", par.pDest.lat, par.pDest.lon);
1449 fprintf (f, " <name>Destination</name>\n");
1450 fprintf (f, " </rtept>\n");
1451 // Close GPX
1452 fprintf (f, " </rte>\n");
1453 fprintf (f, "</gpx>\n");
1454
1455 fclose (f);
1456 printf ("GPX file:%s generated\n", fileName);
1457 return true;
1458}
#define MAX_N_INTERVAL
\Engine tws = True Wind Speed twd = True Wind Direction twa = True Wind Angle - the angle of the boat...
Definition engine.c:24
void * bestTimeDeparture()
choose best time to reach pDest in minimum time
Definition engine.c:1269
static double tDeltaCurrent
Definition engine.c:47
bool storeRoute(SailRoute *route, const Pp *pOr, const Pp *pDest)
store route response false if error
Definition engine.c:561
void freeHistoryRoute()
free space for history route
Definition engine.c:405
static char * motorTribordBabord(bool motor, int amure, char *str, size_t maxLen)
produce string that says if Motor, Tribord, Babord
Definition engine.c:615
static double distSegmentWithFoot(double latX, double lonX, double latA, double lonA, double latB, double lonB, double *latH, double *lonH)
return distance (nm) from point X do segment [AB].
Definition engine.c:58
void saveRoute(SailRoute *route)
store current route in history
Definition engine.c:378
static void replicate(int n)
when no wind, build next isochrone as a replica of previous isochrone Manage carefully id and father ...
Definition engine.c:943
static int forwardSectorOptimize(const Pp *pOr, const Pp *pDest, int nIsoc, const Pp *isoList, int isoLen, Pp *optIsoc)
reduce the size of Isolist note influence of parameters par.nSector, par.jFactor and par....
Definition engine.c:123
static bool goal(Pp *pDest, Pp *isoList, int len, double t, double dt, double *lastStepDuration, bool *motor, int *amure)
true if goal can be reached directly in dt from isochrone update isoDesc side effect : pDest....
Definition engine.c:889
static int routing(Pp *pOr, Pp *pDest, int toIndexWp, double t, double dt, double *lastStepDuration)
find optimal routing from p0 to pDest using grib file and polar return number of steps to reach pDest...
Definition engine.c:966
static void initSector(int nIsoc, int nMax)
initialization of sector
Definition engine.c:114
static void statRoute(SailRoute *route)
add additionnal information to the route
Definition engine.c:422
int nIsoc
Definition engine.c:35
#define MIN_DT
Definition engine.c:29
static int findFather(int ptId, int i, int lIsoc)
find father of point in previous isochrone
Definition engine.c:317
bool isoDescToStr(char *str, size_t maxLen)
copy isoc Descriptors in a string true if enough space, false if truncated
Definition engine.c:330
bool routeToStr(const SailRoute *route, char *str, size_t maxLen, char *footer, size_t maxLenFooter)
copy route in a string true if enough space, false if truncated
Definition engine.c:627
#define LIMIT
Definition engine.c:25
static void initRouting(void)
global variable initialization for routing
Definition engine.c:1109
static bool goalP(const Pp *pA, const Pp *pB, const Pp *pDest, double t, double dt, double *timeTo, double *distance, bool *motor, int *amure, int *sail, bool *bestFirst)
return closest index point to pDest in Isoc, and this point
Definition engine.c:811
int maxNIsoc
Definition engine.c:34
ChooseDeparture chooseDeparture
Definition engine.c:42
static int buildNextIsochrone(const Pp *pOr, const Pp *pDest, const Pp *isoList, int isoLen, double t, double dt, Pp *newList, double *bestVmc, double *biggestOrthoVmc)
build the new list describing the next isochrone, starting from isoList returns length of the newlist...
Definition engine.c:218
#define MIN_VMC_RATIO
Definition engine.c:26
static int pId
Definition engine.c:46
void * routingLaunch()
launch routing with parameters
Definition engine.c:1192
static int optimize(const Pp *pOr, const Pp *pDest, int nIsoc, int algo, const Pp *isoList, int isoLen, Pp *optIsoc)
choice of algorithm used to reduce the size of Isolist
Definition engine.c:205
SailRoute route
store sail route calculated in engine.c by routing
Definition engine.c:39
static bool simpleGoalP(const Pp *pA, const Pp *pDest, double t, double dt, double *timeTo, double *distance, bool *motor, int *amure, int *sail)
return true if pDest can be reached from pA - in less time than dt timeTo give the time to get to pDe...
Definition engine.c:712
HistoryRouteList historyRoute
Definition engine.c:40
Pp lastClosest
Definition engine.c:36
static bool simpleGoal(Pp *pDest, Pp *isoList, int len, double t, double dt, double *lastStepDuration, bool *motor, int *amure)
true if goal can be reached directly in dt from isochrone update isoDesc side effect : pDest....
Definition engine.c:772
bool dumpIsocToFile(const char *fileName)
write in CSV file Isochrones
Definition engine.c:356
IsoDesc * isoDesc
Definition engine.c:33
void logReport(int n)
log one CSV line report.
Definition engine.c:1370
void * allCompetitors()
launch all competitors
Definition engine.c:1331
#define MAX_UNREACHABLE
Definition engine.c:28
Sector sector[2][MAX_N_SECTORS]
Definition engine.c:55
bool exportRouteToGpx(const SailRoute *route, const char *fileName)
export route with GPX format
Definition engine.c:1420
static void checkArrival(SailRoute *route, Pp *pDest)
check arrival between pDest and segments [pPrev-pCurr] and [pCurr-pNext] pFoot0 is the projection of ...
Definition engine.c:1142
static double calcDuration(SailRoute *route)
return the total duration of the route, taking into acount last steps duration
Definition engine.c:412
static int findFirst(int nIsoc)
find first point in isochrone.
Definition engine.c:91
Pp * isocArray
global variables
Definition engine.c:32
static double pOrToPDestCog
static global variable.
Definition engine.c:45
static int fClosest(const Pp *isoc, int n, const Pp *pDest, Pp *closest)
return closest index point to pDest in Isoc, and this point
Definition engine.c:923
#define MAX_N_HISTORY
Definition engine.c:27
static void g_atomic_int_set(int *x, int val)
Attention NOT SAFE.
#define MAX(i, j)
Definition glibwrapper.h:6
#define g_strlcat(dest, src, size)
Definition glibwrapper.h:10
#define CLAMP(x, lo, hi)
Definition glibwrapper.h:7
static int g_atomic_int_get(int *x)
Attention NOT SAFE.
#define g_strlcpy(dest, src, size)
Definition glibwrapper.h:9
static char * g_path_get_basename(const char *path)
close to Glib g_path_get_basename
void findCurrentGrib(double lat, double lon, double t, double *uCurr, double *vCurr, double *tcd, double *tcs)
use findflow to get current
Definition r3grib.c:507
double zoneTimeDiff(const Zone *zone1, const Zone *zone0)
return difference in hours between two zones (current zone and Wind zone)
Definition r3grib.c:19
void findWindGrib(double lat, double lon, double t, double *u, double *v, double *gust, double *w, double *twd, double *tws)
use findflow to get wind and waves
Definition r3grib.c:488
static bool isInZone(double lat, double lon, Zone *zone)
true if P (lat, lon) is within the zone
Definition inline.h:47
static double fTwa(double heading, double twd)
return TWA between -180 and 180 note : tribord amure if twa < 0
Definition inline.h:64
static double maxSpeedInPolarAt(double tws, const PolMat *mat)
return max speed of boat at tws for all twa
Definition inline.h:308
static bool isSea(char *isSeaArray, double lat, double lon)
this file contains small inlines functions to be included in source files
Definition inline.h:8
static double findPolar(double twa, double w, const PolMat *mat, const PolMat *sailMat, int *sail)
find in polar boat speed or wave coeff
Definition inline.h:174
static double directCap(double lat1, double lon1, double lat2, double lon2)
return loxodromic cap from origin to destination
Definition inline.h:89
static double orthoDist(double lat1, double lon1, double lat2, double lon2)
return orthodromic distance in nautical miles from origin to destination
Definition inline.h:147
static double orthoCap(double lat1, double lon1, double lat2, double lon2)
return initial orthodromic cap from origin to destination equivalent to : return directCap (lat1,...
Definition inline.h:96
static bool isDay(double t, long dataDate, long dataTime, double lat, double lon)
true if day light, false if night
Definition inline.h:421
static double lonCanonize(double lon)
return lon on ]-180, 180 ] interval
Definition inline.h:29
static double loxoDist(double lat1, double lon1, double lat2, double lon2)
return loxodromic distance in nautical miles from origin to destination
Definition inline.h:119
static void fAwaAws(double twa, double tws, double sog, double *awa, double *aws)
return AWA and AWS Apparent Wind Angle and Speed
Definition inline.h:70
static bool isSeaTolerant(char *isSeaArray, double lat, double lon)
say if point is in sea
Definition inline.h:16
@ NO_SOLUTION
Definition r3types.h:81
@ STOPPED
Definition r3types.h:81
@ EXIST_SOLUTION
Definition r3types.h:81
#define DEG_TO_RAD
Definition r3types.h:28
#define NIL
Definition r3types.h:38
#define MILLION
Definition r3types.h:37
#define PROG_NAME
Definition r3types.h:31
#define MS_TO_KN
Definition r3types.h:23
#define STAMINA_FULL_PACK
Definition r3types.h:9
@ TRIBORD
Definition r3types.h:80
@ BABORD
Definition r3types.h:80
#define STAMINA_SHIP
Definition r3types.h:6
#define RAD_TO_DEG
Definition r3types.h:27
#define MAX_N_ISOC
Definition r3types.h:40
#define MAX_SIZE_NAME
Definition r3types.h:61
#define SMALL_SIZE
Definition r3types.h:66
#define MAX_SIZE_DATE
Definition r3types.h:52
#define STAMINA_SAIL
Definition r3types.h:7
#define MAX_SIZE_LINE
Definition r3types.h:45
#define STAMINA_TACK
Definition r3types.h:8
@ ROUTING_STOPPED
Definition r3types.h:82
@ ROUTING_ERROR
Definition r3types.h:82
@ ROUTING_RUNNING
Definition r3types.h:82
#define MAX_SIZE_ISOC
Definition r3types.h:39
#define MAX_N_SECTORS
Definition r3types.h:73
WayPointList wayPoints
list of wayPoint
Definition r3util.c:43
char * lonToStr(double lon, int type, char *str, size_t maxLen)
convert lon to str according to type
Definition r3util.c:462
Zone currentZone
Definition r3util.c:65
char * durationToStr(double duration, char *res, size_t maxLen)
convert hours in string with days, hours, minutes
Definition r3util.c:429
double fPointLoss(int shipIndex, int type, double tws, bool fullPack)
for virtual Regatta.
Definition r3util.c:1002
PolMat wavePolMat
polar matrix for waves
Definition r3util.c:55
char * tIsSea
table describing if sea or earth
Definition r3util.c:61
PolMat polMat
polar matrix description
Definition r3util.c:49
char * newDate(long intDate, double nHours, char *res, size_t maxLen)
return date and time using ISO notation after adding myTime (hours) to the Date
Definition r3util.c:386
PolMat sailPolMat
polar matrix for sails
Definition r3util.c:52
Par par
parameter
Definition r3util.c:58
char * fSailName(int val, char *str, size_t maxLen)
return the name of the sail
Definition r3util.c:68
Zone zone
geographic zone covered by grib file
Definition r3util.c:64
CompetitorsList competitors
list of competitors
Definition r3util.c:46
char * latToStr(double lat, int type, char *str, size_t maxLen)
convert lat to str according to type
Definition r3util.c:440
double fTimeToRecupOnePoint(double tws)
for virtual Regatta.
Definition r3util.c:1014
double minDuration
Definition r3types.h:109
double tInterval
Definition r3types.h:106
double t[MAX_N_TIME_STAMPS]
Definition r3types.h:108
double bestTime
Definition r3types.h:111
double maxDuration
Definition r3types.h:110
double duration
Definition r3types.h:265
double lon
Definition r3types.h:263
double lat
Definition r3types.h:262
char name[MAX_SIZE_NAME]
Definition r3types.h:267
char strETA[MAX_SIZE_DATE]
Definition r3types.h:266
double dist
Definition r3types.h:264
Competitor t[MAX_N_COMPETITORS]
Definition r3types.h:275
History Route description
Definition r3types.h:312
SailRoute * r
Definition r3types.h:314
isochrone meta data
Definition r3types.h:188
int size
Definition r3types.h:195
int closest
Definition r3types.h:193
double biggestOrthoVmc
Definition r3types.h:192
double focalLon
Definition r3types.h:197
int toIndexWp
Definition r3types.h:189
double focalLat
Definition r3types.h:196
int first
Definition r3types.h:194
double bestVmc
Definition r3types.h:191
double nightEfficiency
Definition r3types.h:394
char polarFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:344
int jFactor
Definition r3types.h:333
int penalty1
Definition r3types.h:390
int withCurrent
Definition r3types.h:421
int penalty0
Definition r3types.h:389
Pp pDest
Definition r3types.h:367
double maxWind
Definition r3types.h:397
char gribFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:337
int kFactor
Definition r3types.h:334
double constWindTws
Definition r3types.h:328
int withWaves
Definition r3types.h:420
double tStep
Definition r3types.h:324
double dayEfficiency
Definition r3types.h:395
double threshold
Definition r3types.h:393
double motorSpeed
Definition r3types.h:392
int nSectors
Definition r3types.h:335
char logFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:359
int allwaysSea
Definition r3types.h:320
int opt
Definition r3types.h:323
int penalty2
Definition r3types.h:391
Pp pOr
Definition r3types.h:366
double xWind
Definition r3types.h:396
double staminaVR
Definition r3types.h:363
int rangeCog
Definition r3types.h:326
double startTimeInHours
Definition r3types.h:365
int dispDms
Definition r3types.h:376
int cogStep
Definition r3types.h:325
Point in isochrone.
Definition r3types.h:172
bool motor
Definition r3types.h:177
int id
Definition r3types.h:173
int toIndexWp
Definition r3types.h:179
double vmc
Definition r3types.h:183
int father
Definition r3types.h:174
int sail
Definition r3types.h:176
double dd
Definition r3types.h:182
double lat
Definition r3types.h:180
double lon
Definition r3types.h:181
int amure
Definition r3types.h:175
double orthoVmc
Definition r3types.h:184
Point for Sail Route
Definition r3types.h:227
int sail
Definition r3types.h:235
double w
Definition r3types.h:245
double twd
Definition r3types.h:247
int amure
Definition r3types.h:233
int toIndexWp
Definition r3types.h:234
int father
Definition r3types.h:232
double tws
Definition r3types.h:248
double oCap
Definition r3types.h:238
double v
Definition r3types.h:244
double time
Definition r3types.h:237
double ld
Definition r3types.h:241
double g
Definition r3types.h:246
double od
Definition r3types.h:239
double stamina
Definition r3types.h:228
double sog
Definition r3types.h:242
double lon
Definition r3types.h:230
double lat
Definition r3types.h:229
double lCap
Definition r3types.h:240
bool motor
Definition r3types.h:236
double u
Definition r3types.h:243
Route description
Definition r3types.h:279
double babordDist
Definition r3types.h:294
int nWayPoints
Definition r3types.h:289
double avrGust
Definition r3types.h:298
double maxWave
Definition r3types.h:303
double avrSog
Definition r3types.h:300
double isocTimeStep
Definition r3types.h:284
int nSailChange
Definition r3types.h:305
bool destinationReached
Definition r3types.h:296
double avrWave
Definition r3types.h:299
char polarFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:280
double totDist
Definition r3types.h:291
double lastStepDuration
Definition r3types.h:287
int nAmureChange
Definition r3types.h:306
long dataTime
Definition r3types.h:282
double duration
Definition r3types.h:290
double tribordDist
Definition r3types.h:293
double avrTws
Definition r3types.h:297
double motorDist
Definition r3types.h:292
double calculationTime
Definition r3types.h:286
double lastStepWpDuration[MAX_N_WAY_POINT]
Definition r3types.h:288
double maxGust
Definition r3types.h:302
char lastPointInfo[MAX_SIZE_INFO]
Definition r3types.h:307
long dataDate
Definition r3types.h:281
int competitorIndex
Definition r3types.h:304
int ret
Definition r3types.h:295
SailPoint * t
Definition r3types.h:308
int nIsoc
Definition r3types.h:283
double maxTws
Definition r3types.h:301
int nPt
Definition engine.c:52
double vmc
Definition engine.c:50
double orthoVmc
Definition engine.c:51
WayPoint t[MAX_N_WAY_POINT]
Definition r3types.h:256
double lon
Definition r3types.h:219
double lat
Definition r3types.h:218
long dataTime[MAX_N_DATA_TIME]
Definition r3types.h:165
size_t nTimeStamp
Definition r3types.h:157
long timeStamp[MAX_N_TIME_STAMPS]
Definition r3types.h:163
long dataDate[MAX_N_DATA_DATE]
Definition r3types.h:164