RCube
Rcube Rest Server calculates sail routes based on Grib files and sailing boat polar files
Loading...
Searching...
No Matches
r3util.c
Go to the documentation of this file.
1
2#define MAX_N_SHIP_TYPE 2 // for Virtual Regatta Stamina calculation
3
4#include <float.h>
5#include <ctype.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <stdbool.h>
10#include <sys/stat.h>
11#include <dirent.h>
12#include <unistd.h>
13#include <time.h>
14#include <math.h>
15#include <locale.h>
16#include "glibwrapper.h"
17#include "r3types.h"
18#include "inline.h"
19
20/* For virtual regatta Stamina calculation */
21struct {
23 double cShip;
24 double tMin [3];
25 double tMax [3];
27 {"Imoca", 1.2, {300, 300, 420}, {660, 660, 600}},
28 {"Normal", 1.0, {300, 300, 336}, {660, 660, 480}}
29};
30
33
35const struct MeteoElmt meteoTab [N_METEO_ADMIN] = {{7, "Weather service US"}, {78, "DWD Germany"}, {85, "Meteo France"}, {98,"ECMWF European"}};
36
38const size_t sailNameSize = 7;
39const char *sailName [] = {"C0", "HG", "Jib", "LG", "LJ", "Spi", "SS"}; // for sail polars
40const char *colorStr [] = {"green", "purple", "gray", "blue", "yellow", "orange", "red"};
41
44
47
50
53
56
59
61char *tIsSea = NULL;
62
64Zone zone; // wind
65Zone currentZone; // current
66
68char *fSailName (int val, char *str, size_t maxLen) {
69 if (val > 0 && val <= (int) polMat.nSail)
70 strlcpy (str, polMat.tSail[val-1].name, maxLen);
71 else
72 g_strlcpy (str, "--", maxLen);
73 return str;
74}
75
78char *newFileNameSuffix (const char *fileName, const char *suffix, char *newFileName, size_t maxLen) {
79 const char *lastDot = strrchr(fileName, '.'); // find last point position
80 const size_t baseLen = (lastDot == NULL) ? strlen (fileName) : (size_t) (lastDot - fileName); // lenght of base
81
82 // check resulting lenght is in maxLen
83 if (baseLen + strlen (suffix) + 1 >= maxLen) { // for the '.'
84 return NULL; // not enough space
85 }
86 g_strlcpy (newFileName, fileName, baseLen + 1);
87 strlcat (newFileName, ".", maxLen);
88 strlcat (newFileName, suffix, maxLen);
89
90 return newFileName;
91}
92
94bool isEmpty (const char *str) {
95 if (str == NULL) return true;
96 while (*str) {
97 if (!g_ascii_isspace(*str)) return false;
98 str++;
99 }
100 return true;
101}
102
104char *formatThousandSep (char *buffer, size_t maxLen, long value) {
105 char str [MAX_SIZE_LINE];
106 snprintf (str, MAX_SIZE_LINE, "%ld", value);
107 const int length = strlen (str);
108 const int nSep = length / 3;
109 const int mod = length % 3;
110 int i = 0, j = 0;
111 for (i = 0; i < mod; i++)
112 buffer [j++] = str [i];
113 if ((nSep > 0) && (mod > 0)) buffer [j++] = ' ';
114 for (int k = 0; k < nSep; k++) {
115 buffer [j++] = str [i++];
116 buffer [j++] = str [i++];
117 buffer [j++] = str [i++];
118 buffer [j++] = ' ';
119 if (j >= (int) maxLen) {
120 j = maxLen - 1;
121 break;
122 }
123 }
124 buffer [j] = '\0';
125 if (buffer [j - 1] == ' ') buffer [j - 1] = '\0';
126 return buffer;
127}
128
130bool hasSlash(const char *name) {
131 if (!name || !*name) return false;
132 const size_t len = strlen(name);
133 return name[len - 1] == '/';
134}
135
138bool mostRecentFile (const char *directory, const char *pattern0, const char *pattern1, char *name, size_t maxLen) {
139 DIR *dir = opendir (directory);
140 if (dir == NULL) {
141 fprintf (stderr, "In mostRecentFile, Error opening: %s\n", directory);
142 return false;
143 }
144
145 struct dirent *entry;
146 struct stat statbuf;
147 time_t latestTime = 0;
148 char filepath [MAX_SIZE_DIR_NAME + MAX_SIZE_FILE_NAME];
149
150 while ((entry = readdir(dir)) != NULL) {
151 snprintf (filepath, sizeof (filepath), "%s%s%s", directory, hasSlash(directory) ? "" : "/", entry->d_name);
152 if ((strstr (entry->d_name, pattern0) != NULL)
153 && (strstr (entry->d_name, pattern1) != NULL)
154 && (stat(filepath, &statbuf) == 0)
155 && (S_ISREG(statbuf.st_mode)
156 && (statbuf.st_size > 0) // select file only if not empty
157 && statbuf.st_mtime > latestTime)) {
158
159 latestTime = statbuf.st_mtime;
160 if (strlen (entry->d_name) < maxLen)
161 snprintf (name, maxLen, "%s/%s", directory, entry->d_name);
162 else {
163 fprintf (stderr, "In mostRecentFile, Error File name:%s size is: %zu and exceed Max Size: %zu\n", \
164 entry->d_name, strlen (entry->d_name), maxLen);
165 break;
166 }
167 }
168 }
169 closedir(dir);
170 return (latestTime > 0);
171}
172
174bool isNumber (const char *name) {
175 return (name != NULL) && (strpbrk (name, "0123456789") != NULL);
176}
177
179double getCoord (const char *str, double minLimit, double maxLimit) {
180 if (str == NULL) return 0.0;
181 double deg = 0.0, min = 0.0, sec = 0.0;
182 bool minFound = false;
183 const char *neg = "SsWwOo"; // value returned is negative if south or West
184 int sign = (strpbrk (str, neg) == NULL) ? 1 : -1; // -1 if neg found
185 char *pt = NULL;
186
187 // find degrees
188 while (*str && (! (isdigit (*str) || (*str == '-') || (*str == '+'))))
189 str++;
190 deg = strtod (str, NULL);
191 if (deg < 0) sign = -1; // force sign if negative value found
192 deg = fabs (deg);
193 // find minutes
194 if ((strchr (str, '\'') != NULL)) {
195 minFound = true;
196 if ((pt = strstr (str, "°")) != NULL) pt += 2;// degree ° is UTF8 coded with 2 bytes
197 else
198 if ((pt = strpbrk (str, neg)) != NULL) pt += 1;
199
200 if (pt != NULL) min = strtod (pt, NULL);
201 }
202 // find seconds
203 if (minFound && (strchr (str, '"') != NULL)) {
204 sec = strtod (strchr (str, '\'') + 1, NULL);
205 }
206
207 return CLAMP (sign * (deg + min/60.0 + sec/3600.0), minLimit, maxLimit);
208}
209
219/*char *buildRootName (const char *fileName, char *rootName, size_t maxLen) {
220 const char *workingDir = par.workingDir[0] != '\0' ? par.workingDir : WORKING_DIR;
221 char *fullPath = (g_path_is_absolute (fileName)) ? g_strdup (fileName) : g_build_filename (workingDir, fileName, NULL);
222 if (!fullPath) return NULL;
223 g_strlcpy (rootName, fullPath, maxLen);
224 g_free (fullPath);
225 return rootName;
226}
227*/
230char *buildRootName(const char *fileName, char *rootName, size_t maxLen) {
231 if (!fileName || !rootName || maxLen == 0) return NULL;
232 const char *workingDir = (par.workingDir[0] != '\0') ? par.workingDir : WORKING_DIR;
233 int n;
234
235 if (fileName [0] == '/') n = snprintf(rootName, maxLen, "%s", fileName);
236 else n = snprintf(rootName, maxLen, "%s%s%s", workingDir, hasSlash (workingDir) ? "" : "/", fileName);
237
238 if (n < 0 || (size_t)n >= maxLen) {
239 // overflow or writing error
240 if (maxLen) rootName[0] = '\0';
241 return NULL;
242 }
243 return rootName;
244}
245
247char *epochToStr (time_t t, bool seconds, char *str, size_t maxLen) {
248 struct tm *utc = gmtime (&t);
249 if (!utc) return NULL;
250 if (seconds)
251 snprintf (str, maxLen, "%04d-%02d-%02d %02d:%02d:%02d",
252 utc->tm_year + 1900, utc->tm_mon + 1, utc->tm_mday,
253 utc->tm_hour, utc->tm_min, utc->tm_sec);
254 else
255 snprintf (str, maxLen, "%04d-%02d-%02d %02d:%02d",
256 utc->tm_year + 1900, utc->tm_mon + 1, utc->tm_mday,
257 utc->tm_hour, utc->tm_min);
258
259 return str;
260}
261
263double offsetLocalUTC (void) {
264 time_t now;
265 time (&now);
266 struct tm localTm = *localtime (&now);
267 struct tm utcTm = *gmtime (&now);
268 time_t localTime = mktime (&localTm);
269 time_t utcTime = mktime (&utcTm);
270 double offsetSeconds = difftime (localTime, utcTime);
271 if (localTm.tm_isdst > 0) offsetSeconds += 3600; // add one hour if summer time
272 return offsetSeconds;
273}
274
276char *gribDateTimeToStr (long date, long time, char *str, size_t maxLen) {
277 const int year = date / 10000;
278 const int mon = (date % 10000) / 100;
279 const int day = date % 100;
280 const int hour = time / 100;
281 const int min = time % 100;
282 snprintf (str, maxLen, "%04d/%02d/%02d %02d:%02d", year, mon, day, hour, min);
283 return str;
284}
285
299struct tm gribDateToTm(long intDate, double nHours) {
300 struct tm tm0 = {0};
301
302 tm0.tm_year = (int)(intDate / 10000) - 1900;
303 tm0.tm_mon = (int)((intDate % 10000) / 100) - 1;
304 tm0.tm_mday = (int)(intDate % 100);
305
306 int totalMinutes = (int)lround(nHours * 60.0);
307 int days = totalMinutes / (24 * 60);
308 int minutesDay = totalMinutes % (24 * 60);
309
310 tm0.tm_mday += days;
311 tm0.tm_hour = minutesDay / 60;
312 tm0.tm_min = minutesDay % 60;
313 tm0.tm_isdst = 0; // UTC → no DST
314
315 // Normalize pure UTC pur
316 time_t t = timegm(&tm0);
317 struct tm out;
318 gmtime_r(&t, &out);
319 return out;
320}
321
323static inline bool bissextile (int year) { /* */
324 return (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0));
325}
326
328static bool getYMDHM (long dataDate, double nHours, int *yyyy, int *mm, int *dd, int *hh, int *min) {
329 if (nHours < 0.0) {
330 fprintf(stderr, "getYMDHM: nHours must be >= 0 (%.3f)\n", nHours);
331 return false;
332 }
333 static const int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
334
335 int year = (int)(dataDate / 10000);
336 int month = (int)((dataDate % 10000) / 100) - 1; // 0..11
337 int day = (int)(dataDate % 100);
338
339 long totalMinutes = lround(nHours * 60.0);
340 int addDays = (int)(totalMinutes / (60 * 24));
341 int hour = (int)((totalMinutes / 60) % 24);
342 int minute = (int)(totalMinutes % 60);
343
344 day += addDays;
345
346 if (minute >= 60) {
347 hour += minute / 60;
348 minute = minute % 60;
349 }
350 if (hour >= 24) {
351 day += hour / 24;
352 hour = hour % 24;
353 }
354
355 for (;;) {
356 int dim = daysInMonth[month];
357 if (month == 1 && bissextile(year)) dim += 1;
358 if (day <= dim) break;
359 day -= dim;
360 month++;
361 if (month >= 12) {
362 month = 0;
363 year++;
364 }
365 }
366 *yyyy = year;
367 *mm = month + 1; // 1..12 for caller
368 *dd = day;
369 *hh = hour;
370 *min = minute;
371 return true;
372}
373
374
376char *otherNewDate (long dataDate, double nHours, char *res, size_t maxLen) {
377 //struct tm tm0 = gribDateToTm (intDate, nHours);
378 int yyyy = 0, mm = 0, dd = 0 , hh = 0, min = 0;
379 getYMDHM (dataDate, nHours, &yyyy, &mm, &dd, &hh, &min);
380 snprintf (res, maxLen, "%4d-%02d-%02d %02d:%02d", yyyy, mm, dd, hh, min);
381 return res;
382}
383
384
386char *newDate (long intDate, double nHours, char *res, size_t maxLen) {
387 struct tm tm0 = gribDateToTm (intDate, nHours);
388 snprintf (res, maxLen, "%4d-%02d-%02d %02d:%02d", tm0.tm_year + 1900, tm0.tm_mon + 1, tm0.tm_mday,\
389 tm0.tm_hour, tm0.tm_min);
390 return res;
391}
392
394char *newDateWeekDay (long intDate, double nHours, char *res, size_t maxLen) {
395 struct tm tm0 = gribDateToTm (intDate, nHours);
396 strftime (res, maxLen, "%a %H:%M", &tm0);
397 return res;
398}
399
401char *newDateWeekDayVerbose (long intDate, double nHours, char *res, size_t maxLen) {
402 struct tm tm0 = gribDateToTm (intDate, nHours);
403 strftime (res, maxLen, "%A, %b %d at %H:%M UTC", &tm0);
404 return res;
405}
406
408time_t gribDateTimeToEpoch(long date, long hhmm) {
409 struct tm tm_utc = {0}; // UTC time with tm_utc.tm_isdst = 0;
410 tm_utc.tm_year = (int)(date / 10000) - 1900; // YYYY -> tm_year
411 tm_utc.tm_mon = (int)((date % 10000) / 100) - 1; // MM -> 0..11
412 tm_utc.tm_mday = (int)(date % 100); // DD
413 tm_utc.tm_hour = (int)(hhmm / 100); // HH
414 tm_utc.tm_min = (int)(hhmm % 100); // MM
415
416 return timegm(&tm_utc);
417}
418
420double getDepartureTimeInHour (struct tm *startUtc) {
421 const time_t t0 = gribDateTimeToEpoch(zone.dataDate[0], zone.dataTime[0]);
422 if (t0 == (time_t)-1) return NAN;
423 const time_t tStart = timegm(startUtc); // interprétation en UTC
424 if (tStart == (time_t)-1) return NAN;
425 return difftime(tStart, t0) / 3600.0;
426}
427
429char *durationToStr (double duration, char *res, size_t maxLen) {
430 const int nDays = duration / 24;
431 const int nHours = fmod (duration, 24.0);
432 const int nMin = 60 * fmod (duration, 1.0);
433 if (nDays == 0) snprintf (res, maxLen, "%02d:%02d", nHours, nMin);
434 else snprintf (res, maxLen, "%d Days %02d:%02d", nDays, nHours, nMin);
435 // printf ("Duration: %.2lf hours, equivalent to %d days, %02d:%02d\n", duration, nDays, nHours, nMin);
436 return res;
437}
438
440char *latToStr (double lat, int type, char* str, size_t maxLen) {
441 const double mn = 60 * lat - 60 * (int) lat;
442 const double sec = 3600 * lat - (3600 * (int) lat) - (60 * (int) mn);
443 const char c = (lat > 0) ? 'N' : 'S';
444
445 if (lat > 90.0 || lat < -90.0) {
446 g_strlcpy (str, "Lat Errror", maxLen);
447 return str;
448 }
449 switch (type) {
450 case BASIC: snprintf (str, maxLen, "%.2lf°", lat); break;
451 case DD: snprintf (str, maxLen, "%06.2lf°%c", fabs (lat), c); break;
452 case DM: snprintf (str, maxLen, "%02d°%05.2lf'%c", (int) fabs (lat), fabs(mn), c); break;
453 case DMS:
454 snprintf (str, maxLen, "%02d°%02d'%02.0lf\"%c", (int) fabs (lat), (int) fabs(mn), fabs(sec), c);
455 break;
456 default:;
457 }
458 return str;
459}
460
462char *lonToStr (double lon, int type, char *str, size_t maxLen) {
463 const double mn = 60 * lon - 60 * (int) lon;
464 const double sec = 3600 * lon - (3600 * (int) lon) - (60 * (int) mn);
465 const char c = (lon > 0) ? 'E' : 'W';
466
467 if (lon > 180.0 || lon < -180.0) {
468 g_strlcpy (str, "Lon Errror", maxLen);
469 return str;
470 }
471 switch (type) {
472 case BASIC: snprintf (str, maxLen, "%.2lf°", lon); break;
473 case DD: snprintf (str, maxLen, "%06.2lf°%c", fabs (lon), c); break;
474 case DM: snprintf (str, maxLen, "%03d°%05.2lf'%c", (int) fabs (lon), fabs(mn), c); break;
475 case DMS:
476 snprintf (str, maxLen, "%03d°%02d'%02.0lf\"%c", (int) fabs (lon), (int) fabs(mn), fabs(sec), c);
477 break;
478 default:;
479 }
480 return str;
481}
482
484bool readIsSea (const char *fileName) {
485 FILE *f = NULL;
486 int i = 0;
487 char c;
488 int nSea = 0;
489 if ((f = fopen (fileName, "r")) == NULL) {
490 fprintf (stderr, "In readIsSea, Error cannot open: %s\n", fileName);
491 return false;
492 }
493 if ((tIsSea = (char *) malloc (SIZE_T_IS_SEA + 1)) == NULL) {
494 fprintf (stderr, "In readIsSea, error Malloc");
495 fclose (f);
496 return false;
497 }
498
499 while (((c = fgetc (f)) != -1) && (i < SIZE_T_IS_SEA)) {
500 if (c == '1') nSea += 1;
501 tIsSea [i] = c - '0';
502 i += 1;
503 }
504 fclose (f);
505 // printf ("isSea file : %s, Size: %d, nIsea: %d, Proportion sea: %lf\n", fileName, i, nSea, (double) nSea/ (double) i);
506 return true;
507}
508
512static bool isInPolygon (double lat, double lon, const MyPolygon *po) {
513 int i, j;
514 bool inside = false;
515 // printf ("isInPolygon lat:%.2lf lon: %.2lf\n", p.lat, p.lon);
516 for (i = 0, j = po->n - 1; i < po->n; j = i++) {
517 if ((po->points[i].lat > lat) != (po->points[j].lat > lat) &&
518 (lon < (po->points[j].lon - po->points[i].lon) * (lat - po->points[i].lat) / (po->points[j].lat - po->points[i].lat) + po->points[i].lon)) {
519 inside = !inside;
520 }
521 }
522 return inside;
523}
524
526static bool isInForbidArea (double lat, double lon) {
527 for (int i = 0; i < par.nForbidZone; i++) {
528 if (isInPolygon (lat, lon, &forbidZones [i])) return true;
529 }
530 return false;
531}
532
535 if (tIsSea == NULL) return;
536 if (par.nForbidZone <= 0) return;
537 for (int i = 0; i < SIZE_T_IS_SEA; i++) {
538 const double lon = (i % 3601) / 10 - 180.0;
539 const double lat = 90.0 - (i / (3601 *10));
540 if (isInForbidArea (lat, lon))
541 tIsSea [i] = 0;
542 }
543}
544
548static void forbidZoneAdd (char *line, int n) {
549 int idx = 0;
550 char *latToken, *lonToken;
551 // printf ("Forbid Zone : %d\n", n);
552 Point *temp = (Point *) realloc (forbidZones [n].points, MAX_SIZE_FORBID_ZONE * sizeof(Point));
553 if (temp == NULL) {
554 fprintf (stderr, "In forbidZoneAdd, Error realloc with n = %d\n", n);
555 return;
556 }
557 forbidZones [n].points = temp;
558
559 if (((latToken = strtok (line, ",")) == NULL) || ((lonToken = strtok (NULL, "]")) == NULL)) return;
560 forbidZones [n].points[idx].lat = getCoord (latToken, MIN_LAT, MAX_LAT);
561 forbidZones [n].points[idx].lon = getCoord (lonToken, MIN_LON, MAX_LON);
562 idx = 1;
563 while ((idx < MAX_SIZE_FORBID_ZONE) && ((latToken = strtok (NULL, ",")) != NULL) && ((lonToken = strtok (NULL, "]")) != NULL)) {
564 // printf ("latToken: %s, lonToken: %s\n", latToken, lonToken);
565 forbidZones [n].points[idx].lat = getCoord (latToken, MIN_LAT, MAX_LAT);
566 forbidZones [n].points[idx].lon = getCoord (lonToken, MIN_LON, MAX_LON);
567 idx += 1;
568 }
569 forbidZones [n].n = idx;
570}
571
573bool readParam (const char *fileName, bool initDisp) {
574 bool inWp = false, inForbidZone = false, inCompetitor = false;
575 FILE *f = NULL;
576 char *pt = NULL;
577 char str [MAX_SIZE_LINE], strLat [MAX_SIZE_NAME] = "", strLon [MAX_SIZE_NAME] = "";
578 char buffer [MAX_SIZE_TEXT];
579 char *pLine = &buffer [0];
580 memset (&par, 0, sizeof (Par));
581 par.opt = 1;
582 par.tStep = 1.0;
583 par.cogStep = 5;
584 par.rangeCog = 90;
585 par.dayEfficiency = 1;
587 par.kFactor = 1;
588 par.jFactor = 300;
590 if (initDisp) {
591 par.style = 1;
592 par.showColors =2;
593 par.dispDms = 2;
594 par.windDisp = 1;
595 par.stepIsocDisp = 1;
596 }
597 par.xWind = 1.0;
598 par.maxWind = 50.0;
599 par.staminaVR = 100.0;
600 wayPoints.n = 0;
603 competitors.n = 0;
605
606 if ((f = fopen (fileName, "r")) == NULL) {
607 fprintf (stderr, "In readParam, Error Cannot open: %s\n", fileName);
608 return false;
609 }
610
611 while (fgets (pLine, sizeof (buffer), f) != NULL ) {
612 str [0] = '\0';
613 g_strstrip (pLine);
614 // printf ("%s", pLine);
615 if ((!*pLine) || *pLine == '#' || *pLine == '\n') continue;
616 if ((pt = strchr (pLine, '#')) != NULL) // comment elimination
617 *pt = '\0';
618 if (strncmp (pLine, "-", 1) != 0) inWp = inForbidZone = inCompetitor = false;
619
620 if (strncmp (pLine, "---", 3) == 0) {} // ignore for yaml compatibility
621 // if (strncmp (pLine, "...", 3) == 0) break; // end for yaml compatibility
622 else if (sscanf (pLine, "DESC:%255[^\n]", par.description) > 0)
624 else if (sscanf (pLine, "ALLWAYS_SEA:%d", &par.allwaysSea) > 0);
625 else if (sscanf (pLine, "WD:%255s", par.workingDir) > 0); // should be first !!!
626 else if (sscanf (pLine, "POI:%255s", str) > 0)
628 else if (sscanf (pLine, "PORT:%255s", str) > 0)
630
631 else if (sscanf(pLine, "POR: [%63[^,], %63[^]]", strLat, strLon) == 2) { // POR: [lat, lon]
632 par.pOr.lat = getCoord (strLat, MIN_LAT, MAX_LAT);
633 par.pOr.lon = getCoord (strLon, MIN_LON, MAX_LON);
634 par.pOr.id = par.pOr.father = -1;
635 }
636
637 else if (sscanf(pLine, "PDEST: [%63[^,], %63[^]]", strLat, strLon) == 2) { // PDEST: [lat, lon]
638 par.pDest.lat = getCoord (strLat, MIN_LAT, MAX_LAT);
639 par.pDest.lon = getCoord (strLon, MIN_LON, MAX_LON);
640 par.pDest.id = par.pDest.father = 0;
641 }
642
643 else if (strstr (pLine, "WP:") != NULL) inWp = true; // format is WP: then -
644 else if (inWp && (sscanf (pLine, "- [%63[^,], %63[^]]", strLat, strLon) == 2)) { // - [lat, lon]
646 fprintf (stderr, "In readParam, Error: number of wayPoints exceeded; %d\n", MAX_N_WAY_POINT);
647 else {
650 wayPoints.n += 1;
651 }
652 }
653 else if (strstr (pLine, "COMPETITORS:") != NULL) inCompetitor = true; // format is COMPETITORS: then -
654 else if (inCompetitor &&
655 (sscanf (pLine, "- [%d, %63[^,], %63[^,], %63[^]]", // - [color, lat, lon, name]
656 &competitors.t [competitors.n].colorIndex, strLat, strLon, competitors.t [competitors.n].name) == 4)
657 ) {
659 fprintf (stderr, "In readParam, Error number of competitors exceeded; %d\n", MAX_N_COMPETITORS);
660 else {
664 if (competitors.n == 0) {
665 par.pOr.lat = competitors.t [0].lat;
666 par.pOr.lon = competitors.t [0].lon;
667 }
668 competitors.n += 1;
669 }
670 }
671
672 else if (sscanf (pLine, "POR_NAME:%255s", par.pOrName) > 0);
673 else if (sscanf (pLine, "PDEST_NAME:%255s", par.pDestName) > 0);
674 else if (sscanf (pLine, "GRIB_RESOLUTION:%lf", &par.gribResolution) > 0);
675 else if (sscanf (pLine, "GRIB_TIME_STEP:%d", &par.gribTimeStep) > 0);
676 else if (sscanf (pLine, "GRIB_TIME_MAX:%d", &par.gribTimeMax) > 0);
677 else if (sscanf (pLine, "MARKS:%255s", str) > 0)
679 else if (sscanf (pLine, "TRACE:%255s", str) > 0)
681 else if (sscanf (pLine, "CGRIB:%255s", str) > 0)
683 else if (sscanf (pLine, "CURRENT_GRIB:%255s", str) > 0)
685 else if (sscanf (pLine, "WAVE_POL:%255s", str) > 0)
687 else if (sscanf (pLine, "POLAR:%255s", str) > 0)
689 else if (sscanf (pLine, "ISSEA:%255s", str) > 0)
691 else if (sscanf (pLine, "TIDES:%255s", str) > 0)
693 else if (sscanf (pLine, "MID_COUNTRY:%255s", str) > 0)
695 else if (sscanf (pLine, "CLI_HELP:%255s", str) > 0)
697 else if (strstr (pLine, "VR_DASHBOARD:") != NULL) {
698 pLine = strchr (pLine, ':') + 1;
699 g_strstrip (pLine);
700 buildRootName (pLine, par.dashboardVR, sizeof (par.dashboardVR));
701 }
702 else if (sscanf (pLine, "VR_STAMINA:%lf", &par.staminaVR) > 0);
703 else if (sscanf (pLine, "VR_DASHB_UTC:%d", &par.dashboardUTC) > 0);
704 else if (sscanf (pLine, "HELP:%255s", par.helpFileName) > 0); // full link required
705 else if (sscanf (pLine, "CURL_SYS:%d", &par.curlSys) > 0);
706 else if (sscanf (pLine, "PYTHON:%d", &par.python) > 0);
707 else if (sscanf (pLine, "SMTP_SCRIPT:%255[^\n]", par.smtpScript) > 0)
709 else if (sscanf (pLine, "IMAP_TO_SEEN:%255[^\n]", par.imapToSeen) > 0)
711 else if (sscanf (pLine, "IMAP_SCRIPT:%255[^\n]", par.imapScript) > 0)
713 else if (sscanf (pLine, "SHP:%255s", str) > 0) {
715 par.nShpFiles += 1;
717 fprintf (stderr, "In readParam, Error Number max of SHP files reached: %d\n", par.nShpFiles);
718 }
719 else if (sscanf (pLine, "AUTHENT:%d", &par.authent) > 0);
720 else if (sscanf (pLine, "MOST_RECENT_GRIB:%d", &par.mostRecentGrib) > 0);
721 else if (sscanf (pLine, "START_TIME:%lf", &par.startTimeInHours) > 0);
722 else if (sscanf (pLine, "T_STEP:%lf", &par.tStep) > 0);
723 else if (sscanf (pLine, "RANGE_COG:%d", &par.rangeCog) > 0);
724 else if (sscanf (pLine, "COG_STEP:%d", &par.cogStep) > 0);
725 else if (sscanf (pLine, "SPECIAL:%d", &par.special) > 0);
726 else if (sscanf (pLine, "MOTOR_S:%lf", &par.motorSpeed) > 0);
727 else if (sscanf (pLine, "THRESHOLD:%lf", &par.threshold) > 0);
728 else if (sscanf (pLine, "DAY_EFFICIENCY:%lf", &par.dayEfficiency) > 0);
729 else if (sscanf (pLine, "NIGHT_EFFICIENCY:%lf", &par.nightEfficiency) > 0);
730 else if (sscanf (pLine, "X_WIND:%lf", &par.xWind) > 0);
731 else if (sscanf (pLine, "MAX_WIND:%lf", &par.maxWind) > 0);
732 else if (sscanf (pLine, "CONST_WAVE:%lf", &par.constWave) > 0);
733 else if (sscanf (pLine, "CONST_WIND_TWS:%lf", &par.constWindTws) > 0);
734 else if (sscanf (pLine, "CONST_WIND_TWD:%lf", &par.constWindTwd) > 0);
735 else if (sscanf (pLine, "CONST_CURRENT_S:%lf", &par.constCurrentS) > 0);
736 else if (sscanf (pLine, "CONST_CURRENT_D:%lf", &par.constCurrentD) > 0);
737 else if (sscanf (pLine, "WP_GPX_FILE:%255s", str) > 0)
739 else if (sscanf (pLine, "DUMPI:%255s", str) > 0)
741 else if (sscanf (pLine, "DUMPR:%255s", str) > 0)
743 else if (sscanf (pLine, "PAR_INFO:%254s", str) > 0)
745 else if (sscanf (pLine, "LOG:%254s", str) > 0)
747 else if (sscanf (pLine, "FEEDBACK:%254s", str) > 0)
749 else if ((sscanf (pLine, "WEB:%254s", str) > 0) || (strstr (pLine, "WEB:") != NULL)) {
750 buildRootName (str, par.web, sizeof (par.web));
751 }
752 else if (sscanf (pLine, "OPT:%d", &par.opt) > 0);
753 else if (sscanf (pLine, "J_FACTOR:%d", &par.jFactor) > 0);
754 else if (sscanf (pLine, "K_FACTOR:%d", &par.kFactor) > 0);
755 else if (sscanf (pLine, "PENALTY0:%d", &par.penalty0) > 0);
756 else if (sscanf (pLine, "PENALTY1:%d", &par.penalty1) > 0);
757 else if (sscanf (pLine, "PENALTY2:%d", &par.penalty2) > 0);
758 else if (sscanf (pLine, "N_SECTORS:%d", &par.nSectors) > 0);
759 else if (sscanf (pLine, "WITH_WAVES:%d", &par.withWaves) > 0);
760 else if (sscanf (pLine, "WITH_CURRENT:%d", &par.withCurrent) > 0);
761 else if (sscanf (pLine, "ISOC_DISP:%d", &par.style) > 0);
762 else if (sscanf (pLine, "STEP_ISOC_DISP:%d", &par.stepIsocDisp) > 0);
763 else if (sscanf (pLine, "COLOR_DISP:%d", &par.showColors) > 0);
764 else if (sscanf (pLine, "DMS_DISP:%d", &par.dispDms) > 0);
765 else if (sscanf (pLine, "WIND_DISP:%d", &par.windDisp) > 0);
766 else if (sscanf (pLine, "INFO_DISP:%d", &par.infoDisp) > 0);
767 else if (sscanf (pLine, "INDICATOR_DISP:%d", &par.indicatorDisp) > 0);
768 else if (sscanf (pLine, "CURRENT_DISP:%d", &par.currentDisp) > 0);
769 else if (sscanf (pLine, "WAVE_DISP:%d", &par.waveDisp) > 0);
770 else if (sscanf (pLine, "GRID_DISP:%d", &par.gridDisp) > 0);
771 else if (sscanf (pLine, "LEVEL_POI_DISP:%d", &par.maxPoiVisible) > 0);
772 else if (sscanf (pLine, "SPEED_DISP:%d", &par.speedDisp) > 0);
773 else if (sscanf (pLine, "AIS_DISP:%d", &par.aisDisp) > 0);
774 else if (sscanf (pLine, "TECHNO_DISP:%d", &par.techno) > 0);
775 else if (sscanf (pLine, "CLOSEST_DISP:%d", &par.closestDisp) > 0);
776 else if (sscanf (pLine, "FOCAL_DISP:%d", &par.focalDisp) > 0);
777 else if (sscanf (pLine, "SHP_POINTS_DISP:%d", &par.shpPointsDisp) > 0);
778 else if (sscanf (pLine, "GOOGLE_API_KEY:%1024s", par.googleApiKey) > 0);
779 else if (sscanf (pLine, "WINDY_API_KEY:%1024s", par.windyApiKey) > 0);
780 else if (sscanf (pLine, "WEBKIT:%255[^\n]", par.webkit) > 0) g_strstrip (par.webkit);
781 else if (strstr (pLine, "FORBID_ZONES:") != NULL) inForbidZone = true;
782 else if (inForbidZone && ((pt = strstr (pLine, "- [[")) != NULL)) {
784 forbidZoneAdd (pLine + 2, par.nForbidZone);
785 par.nForbidZone += 1;
786 }
787 else fprintf (stderr, "In readParam, MAX_N_FORBID_ZONE: %d\n", MAX_N_FORBID_ZONE);
788 }
789 else if (sscanf (pLine, "SMTP_SERVER:%255s", par.smtpServer) > 0);
790 else if (sscanf (pLine, "SMTP_USER_NAME:%255s", par.smtpUserName) > 0);
791 else if (sscanf (pLine, "SMTP_TO:%255s", par.smtpTo) > 0);
792 else if (sscanf (pLine, "MAIL_PW:%255s", par.mailPw) > 0);
793 else if (sscanf (pLine, "IMAP_SERVER:%255s", par.imapServer) > 0);
794 else if (sscanf (pLine, "IMAP_USER_NAME:%255s", par.imapUserName) > 0);
795 else if (sscanf (pLine, "IMAP_MAIL_BOX:%255s", par.imapMailBox) > 0);
796 else if ((par.nNmea < N_MAX_NMEA_PORTS) &&
797 (sscanf (pLine, "NMEA:%255s %d", par.nmea [par.nNmea].portName, &par.nmea [par.nNmea].speed) > 0)) {
798 par.nNmea += 1;
799 }
800 else fprintf (stderr, "In readParam, Error Cannot interpret: %s\n", pLine);
801 } // end while
802 if (par.mailPw [0] != '\0') {
803 par.storeMailPw = true;
804 }
805 if (competitors.n > 0) {
806 par.pOr.lat = competitors.t [0].lat;
807 par.pOr.lon = competitors.t [0].lon;
808 }
809 par.staminaVR = CLAMP (par.staminaVR, 0.0, 100.0);
810 fclose (f);
812 return true;
813}
814
815static void fprintfNoNull (FILE *f, const char *fmt, const char *param) {
816 if (!param || ! *param) return;
817 fprintf (f, fmt, param);
818}
819static void fprintfNoZero (FILE *f, const char *fmt, int param) {
820 if (param == 0) return;
821 fprintf (f, fmt, param);
822}
823
826bool writeParam (const char *fileName, bool header, bool password, bool yaml) {
827 char strLat [MAX_SIZE_NAME] = "";
828 char strLon [MAX_SIZE_NAME] = "";
829 FILE *f = NULL;
830 if ((f = fopen (fileName, "w")) == NULL) {
831 fprintf (stderr, "In writeParam, Error Cannot write: %s\n", fileName);
832 return false;
833 }
834 if (header) fprintf (f, "Name Value\n");
835 if (yaml) fprintf (f, "---\n");
836 fprintfNoNull (f, "DESC: %s\n", par.description);
837 fprintfNoNull (f, "WD: %s\n", par.workingDir);
838 fprintf (f, "ALLWAYS_SEA: %d\n", par.allwaysSea);
839
840 latToStr (par.pOr.lat, par.dispDms, strLat, sizeof (strLat));
841 lonToStr (par.pOr.lon, par.dispDms, strLon, sizeof (strLon));
842 fprintf (f, "POR: [%.2lf, %.2lf]\n", par.pOr.lat, par.pOr.lon);
843
844 latToStr (par.pDest.lat, par.dispDms, strLat, sizeof (strLat));
845 lonToStr (par.pDest.lon, par.dispDms, strLon, sizeof (strLon));
846 fprintf (f, "PDEST: [%.2lf, %.2lf]\n", par.pDest.lat, par.pDest.lon);
847
848 fprintfNoNull (f, "POR_NAME: %s\n", par.pOrName);
849 fprintfNoNull (f, "PDEST_NAME: %s\n", par.pDestName);
850 if (wayPoints.n > 0) {
851 fprintf (f, "WP:\n");
852 for (int i = 0; i < wayPoints.n; i++) {
853 fprintf (f, " - [%.2lf, %.2lf]\n", wayPoints.t [i].lat, wayPoints.t [i].lon);
854 }
855 }
856 if (competitors.n > 0) {
857 fprintf (f, "COMPETITORS:\n");
858 for (int i = 0; i < competitors.n; i++) { // competitors
859 latToStr (competitors.t [i].lat, par.dispDms, strLat, sizeof (strLat));
860 lonToStr (competitors.t [i].lon, par.dispDms, strLon, sizeof (strLon));
861 fprintf (f, " - [%d, %s, %s, %s]\n", competitors.t[i].colorIndex, strLat, strLon, competitors.t[i].name);
862 }
863 }
864 fprintfNoNull (f, "WEB: %s\n", par.web);
865 for (int i = 0; i < par.nShpFiles; i++)
866 fprintf (f, "SHP: %s\n", par.shpFileName [i]);
867 fprintfNoNull (f, "POI: %s\n", par.poiFileName);
868 fprintfNoNull (f, "PORT: %s\n", par.portFileName);
869 fprintfNoNull (f, "MARKS: %s\n", par.marksFileName);
870 fprintfNoNull (f, "TRACE: %s\n", par.traceFileName);
871 fprintfNoNull (f, "POLAR: %s\n", par.polarFileName);
872 fprintfNoNull (f, "WAVE_POL: %s\n", par.wavePolFileName);
873 fprintfNoNull (f, "ISSEA: %s\n", par.isSeaFileName);
874 fprintfNoNull (f, "MID_COUNTRY: %s\n", par.midFileName);
875 fprintfNoNull (f, "TIDES: %s\n", par.tidesFileName);
876 fprintfNoNull (f, "HELP: %s\n", par.helpFileName);
877 fprintfNoNull (f, "CLI_HELP: %s\n", par.cliHelpFileName);
878 fprintfNoNull (f, "VR_DASHBOARD: %s\n", par.dashboardVR);
879 fprintfNoNull (f, "WP_GPX_FILE: %s\n", par.wpGpxFileName);
880 fprintfNoNull (f, "DUMPI: %s\n", par.dumpIFileName);
881 fprintfNoNull (f, "DUMPR: %s\n", par.dumpRFileName);
882 fprintfNoNull (f, "PAR_INFO: %s\n", par.parInfoFileName);
883 fprintfNoNull (f, "LOG: %s\n", par.logFileName);
884 fprintfNoNull (f, "FEEDBACK: %s\n", par.feedbackFileName);
885 fprintfNoNull (f, "CURRENT_GRIB: %s\n", par.currentGribFileName);
886 fprintfNoNull (f, "CGRIB: %s\n", par.gribFileName);
887 fprintf (f, "MOST_RECENT_GRIB: %d\n", par.mostRecentGrib);
888 fprintf (f, "GRIB_RESOLUTION: %.2lf\n", par.gribResolution);
889 fprintfNoZero (f, "GRIB_TIME_STEP: %d\n", par.gribTimeStep);
890 fprintfNoZero (f, "GRIB_TIME_MAX: %d\n", par.gribTimeMax);
891 fprintf (f, "VR_STAMINA: %.2lf\n", par.staminaVR);
892 fprintfNoZero (f, "VR_DASHB_UTC: %d\n", par.dashboardUTC);
893
894 fprintf (f, "START_TIME: %.2lf\n", par.startTimeInHours);
895 fprintf (f, "T_STEP: %.2lf\n", par.tStep);
896 fprintf (f, "RANGE_COG: %d\n", par.rangeCog);
897 fprintf (f, "COG_STEP: %d\n", par.cogStep);
898 fprintf (f, "PENALTY0: %d\n", par.penalty0);
899 fprintf (f, "PENALTY1: %d\n", par.penalty1);
900 fprintf (f, "PENALTY2: %d\n", par.penalty2);
901 fprintf (f, "MOTOR_S: %.2lf\n", par.motorSpeed);
902 fprintf (f, "THRESHOLD: %.2lf\n", par.threshold);
903 fprintf (f, "DAY_EFFICIENCY: %.2lf\n", par.dayEfficiency);
904 fprintf (f, "NIGHT_EFFICIENCY: %.2lf\n", par.nightEfficiency);
905 fprintf (f, "X_WIND: %.2lf\n", par.xWind);
906 fprintf (f, "MAX_WIND: %.2lf\n", par.maxWind);
907 fprintf (f, "WITH_WAVES: %d\n", par.withWaves);
908 fprintf (f, "WITH_CURRENT: %d\n", par.withCurrent);
909 fprintfNoZero (f, "SPECIAL: %d\n", par.special);
910
911 if (par.constWave != 0)
912 fprintf (f, "CONST_WAVE: %.6lf\n", par.constWave);
913
914 if (par.constWindTws != 0) {
915 fprintf (f, "CONST_WIND_TWS: %.6lf\n", par.constWindTws);
916 fprintf (f, "CONST_WIND_TWD: %.2lf\n", par.constWindTwd);
917 }
918 if (par.constCurrentS != 0) {
919 fprintf (f, "CONST_CURRENT_S: %.6f\n", par.constCurrentS);
920 fprintf (f, "CONST_CURRENT_D: %.2lf\n", par.constCurrentD);
921 }
922
923 fprintfNoZero (f, "OPT: %d\n", par.opt);
924 fprintfNoZero (f, "ISOC_DISP: %d\n", par.style);
925 fprintfNoZero (f, "STEP_ISOC_DISP: %d\n", par.stepIsocDisp);
926 fprintfNoZero (f, "COLOR_DISP: %d\n", par.showColors);
927 fprintfNoZero (f, "DMS_DISP: %d\n", par.dispDms);
928 fprintfNoZero (f, "WIND_DISP: %d\n", par.windDisp);
929 fprintfNoZero (f, "INFO_DISP: %d\n", par.infoDisp);
930 fprintfNoZero (f, "INDICATOR_DISP: %d\n", par.indicatorDisp);
931 fprintfNoZero (f, "CURRENT_DISP: %d\n", par.currentDisp);
932 fprintfNoZero (f, "WAVE_DISP: %d\n", par.waveDisp);
933 fprintfNoZero (f, "GRID_DISP: %d\n", par.gridDisp);
934 fprintfNoZero (f, "LEVEL_POI_DISP: %d\n", par.maxPoiVisible);
935 fprintfNoZero (f, "SPEED_DISP: %d\n", par.speedDisp);
936 fprintfNoZero (f, "AIS_DISP: %d\n", par.aisDisp);
937 fprintfNoZero (f, "SHP_POINTS_DISP: %d\n", par.shpPointsDisp);
938 fprintfNoZero (f, "TECHNO_DISP: %d\n", par.techno);
939 fprintfNoZero (f, "CLOSEST_DISP: %d\n", par.closestDisp);
940 fprintfNoZero (f, "FOCAL_DISP: %d\n", par.focalDisp);
941 fprintf (f, "J_FACTOR: %d\n", par.jFactor);
942 fprintf (f, "K_FACTOR: %d\n", par.kFactor);
943 fprintf (f, "N_SECTORS: %d\n", par.nSectors);
944 fprintfNoZero (f, "PYTHON: %d\n", par.python);
945 fprintfNoZero (f, "CURL_SYS: %d\n", par.curlSys);
946 fprintfNoNull (f, "SMTP_SCRIPT: %s\n", par.smtpScript);
947 fprintfNoNull (f, "IMAP_TO_SEEN: %s\n", par.imapToSeen);
948 fprintfNoNull (f, "IMAP_SCRIPT: %s\n", par.imapScript);
949 fprintfNoNull (f, "WINDY_API_KEY: %s\n", par.windyApiKey);
950 fprintfNoNull (f, "GOOGLE_API_KEY: %s\n", par.googleApiKey);
951 fprintfNoNull (f, "WEBKIT: %s\n", par.webkit);
952 fprintfNoNull (f, "SMTP_SERVER: %s\n", par.smtpServer);
953 fprintfNoNull (f, "SMTP_USER_NAME: %s\n", par.smtpUserName);
954 fprintfNoNull (f, "SMTP_TO: %s\n", par.smtpTo);
955 fprintfNoNull (f, "IMAP_SERVER: %s\n", par.imapServer);
956 fprintfNoNull (f, "IMAP_USER_NAME: %s\n", par.imapUserName);
957 fprintfNoNull (f, "IMAP_MAIL_BOX: %s\n", par.imapMailBox);
958 fprintf (f, "AUTHENT: %d\n", par.authent);
959 for (int i = 0; i < par.nNmea; i++)
960 fprintf (f, "NMEA: %s %d\n", par.nmea [i].portName, par.nmea [i].speed);
961
962 if (par.nForbidZone > 0) {
963 fprintf (f, "FORBID_ZONES:\n");
964 for (int i = 0; i < par.nForbidZone; i++) {
965 fprintf (f, " - [");
966 for (int j = 0; j < forbidZones [i].n; j++) {
967 latToStr (forbidZones [i].points [j].lat, par.dispDms, strLat, sizeof (strLat));
968 lonToStr (forbidZones [i].points [j].lon, par.dispDms, strLon, sizeof (strLon));
969 fprintf (f, "[%s, %s]%s", strLat, strLon, j < forbidZones [i].n - 1 ? ", " : "");
970 }
971 if (yaml) fprintf (f, "] # yamllint disable-line\n");
972 else fprintf (f, "]\n");
973 }
974 }
975 if (password)
976 fprintf (f, "MAIL_PW: %s\n", par.mailPw);
977 if (yaml) fprintf (f, "...\n");
978
979 fclose (f);
980 return true;
981}
982
984double fPenalty (int shipIndex, int type, double tws, double energy, double *cStamina, bool fullPack) {
985 if (type < 0 || type > 2) {
986 fprintf (stderr, "In fPenalty, type unknown: %d\n", type);
987 return -1;
988 };
989 const double kPenalty = 0.015;
990 const double cShip = shipParam [shipIndex].cShip;
991 *cStamina = 2.0 - fmin (energy, 100.0) * kPenalty;
992 const double tMin = shipParam [shipIndex].tMin [type];
993 const double tMax = shipParam [shipIndex].tMax [type];
994 const double fTws = 50.0 - 50.0 * cos (G_PI * ((fmax (10.0, fmin (tws, 30.0))-10.0)/(30.0 - 10.0)));
995 //printf ("cShip: %.2lf, cStamina: %.2lf, tMin: %.2lf, tMax: %.2lf, fTws: %.2lf\n", cShip, cStamina, tMin, tMax, fTws);
996 double t = tMin + fTws * (tMax - tMin) / 100.0;
997 if (fullPack) t *= 0.8;
998 return t * cShip * (*cStamina);
999}
1000
1002double fPointLoss (int shipIndex, int type, double tws, bool fullPack) {
1003 const double fPCoeff = fullPack ? 0.8 : 1.0;
1004 const double loss = (type == 2) ? 0.2 : 0.1;
1005 const double cShip = shipParam [shipIndex].cShip;
1006 const double fTws = (tws <= 10.0) ? 0.02 * tws + 1.0 :
1007 (tws <= 20.0) ? 0.03 * tws + 0.9 :
1008 (tws <= 30) ? 0.05 * tws + 0.5 :
1009 2.0;
1010 return fPCoeff * loss * cShip * fTws;
1011}
1012
1014double fTimeToRecupOnePoint (double tws) {
1015 const double timeToRecupLow = 5.0 * 60.0; // 5 minutes in secondes
1016 const double timeToRecupHigh = 15.0 * 60.0; // 15 minutes in seconds
1017 const double fTws = 1.0 - cos (G_PI * (fmin (tws, 30.0)/30.0));
1018 return timeToRecupLow + fTws * (timeToRecupHigh - timeToRecupLow) / 2.0;
1019}
1020
1023char *paramToStrJson (Par *par, char *out, size_t maxLen) {
1024 if (!par || !out || maxLen == 0) return NULL;
1025
1026 char *fileName = g_path_get_basename (par->gribFileName);
1027 char *fileNameCurrent = g_path_get_basename (par->currentGribFileName);
1028 char *polarFileName = g_path_get_basename (par->polarFileName);
1029 char *wavePolarFileName= g_path_get_basename (par->wavePolFileName);
1030 char *isSeaFileName = g_path_get_basename (par->isSeaFileName);
1031
1032 int n = snprintf(out, maxLen,
1033 "{\n"
1034 " \"wd\": \"%s\",\n"
1035 " \"grib\": \"%s\",\n"
1036 " \"bottomLat\": %.2f, \"leftLon\": %.2f, \"topLat\": %.2f, \"rightLon\": %.2f,\n"
1037 " \"currentGrib\": \"%s\",\n"
1038 " \"polar\": \"%s\",\n"
1039 " \"wavePolar\": \"%s\",\n"
1040 " \"issea\": \"%s\"\n"
1041 "}\n",
1042 par->workingDir,
1043 fileName,
1045 fileNameCurrent,
1046 polarFileName,
1047 wavePolarFileName,
1048 isSeaFileName
1049 );
1050
1051 free(fileName);
1052 free(fileNameCurrent);
1053 free(polarFileName);
1054 free(wavePolarFileName);
1055 free(isSeaFileName);
1056
1057 if (n < 0) return NULL;
1058 if ((size_t)n >= maxLen) return NULL; // Trunc
1059 return out;
1060}
1061
1063int nearestPort (double lat, double lon, const char *fileName, char *res, size_t maxLen) {
1064 const double minShomLat = 42.0;
1065 const double maxShomLat = 52.0;
1066 const double minShomLon = -6.0;
1067 const double maxShomLon = 4.0;
1068 double minDist = DBL_MAX;
1069 FILE *f;
1070 char str [MAX_SIZE_LINE];
1071 double latPort, lonPort;
1072 char portName [MAX_SIZE_NAME];
1073 int id = 0, bestId = 0;
1074 res [0] = '\0';
1075 if ((lat < minShomLat) || (lat > maxShomLat) || (lon < minShomLon) || (lon > maxShomLon))
1076 return 0;
1077
1078 if ((f = fopen (fileName, "r")) == NULL) {
1079 fprintf (stderr, "In nearestPort, Error cannot open: %s\n", fileName);
1080 return 0;
1081 }
1082 while (fgets (str, MAX_SIZE_LINE, f) != NULL ) {
1083 if (sscanf (str, "%lf,%lf,%63[^,],%d", &latPort, &lonPort, portName, &id) > 2) {
1084 double d = orthoDist (lat, lon, latPort, lonPort);
1085 if (d < minDist) {
1086 minDist = d;
1087 g_strstrip (portName);
1088 g_strlcpy (res, portName, maxLen);
1089 bestId = id;
1090 //printf ("%s %.2lf %.2lf %.2lf %.2lf %.2lf \n", portName, d, lat, lon, latPort, lonPort);
1091 }
1092 }
1093 }
1094 fclose (f);
1095 return bestId;
1096}
1097
1099double monotonic (void) {
1100 struct timespec ts;
1101 clock_gettime(CLOCK_MONOTONIC, &ts);
1102 return (double) ts.tv_sec + (double) ts.tv_nsec * 1e-9;
1103}
1104
1106char *readTextFile (const char *fileName, char *errMessage, size_t maxLen) {
1107 FILE *f = fopen(fileName, "rb");
1108 if (!f) {
1109 snprintf(errMessage, maxLen, "In readFile: Error Cannot open: %s\n", fileName);
1110 return NULL;
1111 }
1112 struct stat st;
1113 if (fstat(fileno(f), &st) != 0) {
1114 snprintf(errMessage, maxLen, "In readFile: cannot stat %s\n", fileName);
1115 fclose(f);
1116 return NULL;
1117 }
1118 if (st.st_size < 0) {
1119 snprintf(errMessage, maxLen, "In readFile: negative file size?\n");
1120 fclose(f);
1121 return NULL;
1122 }
1123 size_t fileSize = (size_t)st.st_size;
1124 char *buffer = malloc(fileSize + 1); // +1 pour '\0'
1125 if (!buffer) {
1126 snprintf(errMessage, maxLen, "In readFile: Malloc failed: %zu\n", fileSize + 1);
1127 fclose(f);
1128 return NULL;
1129 }
1130 size_t nread = fread(buffer, 1, fileSize, f);
1131 if (nread != fileSize && ferror(f)) {
1132 snprintf(errMessage, maxLen, "In readFile: fread error\n");
1133 free(buffer);
1134 fclose(f);
1135 return NULL;
1136 }
1137 buffer[nread] = '\0';
1138 fclose(f);
1139 return buffer;
1140}
1141
1144bool readMarkCSVToJson (const char *fileName, char *out, size_t maxLen) {
1145 FILE *f = NULL;
1146 char buffer [MAX_SIZE_TEXT_FILE];
1147 char str [MAX_SIZE_TEXT];
1148 char *what, *name, *id, *coord0, *coord1, *status, *end, *ptLon;
1149 double lat0 = 0.0, lon0 = 0.0, lat1 = 0.0, lon1 = 0.0;
1150 char empty [] = "";
1151
1152 if ((f = fopen (fileName, "r")) == NULL) {
1153 snprintf (out, maxLen, "Error in readMarkCSVToJson: cannot open: %s\n", fileName);
1154 return false;
1155 }
1156 strlcpy (out, "[\n", maxLen);
1157
1158 while (fgets(buffer, sizeof buffer, f)) {
1159 //buffer[strcspn(buffer, "\r\n")] = '\0';
1160 char **t = g_strsplit(buffer, ";", -1);
1161 if (t == NULL) continue;
1162
1163 what = t[0] ? g_strstrip(t[0]) : empty;
1164 name = t[1] ? g_strstrip(t[1]) : empty;
1165 id = t[2] ? g_strstrip(t[2]) : empty;
1166 coord0 = t[3] ? g_strstrip(t[3]) : empty;
1167 coord1 = t[4] ? g_strstrip(t[4]) : empty;
1168 status = t[5] ? g_strstrip(t[5]) : empty;
1169
1170 ptLon = coord0 ? strchr (coord0, '-') : NULL;
1171 if (ptLon) *ptLon = '\0'; // cut coord end eliminate '-'
1172 lat0 = getCoord (coord0, MIN_LAT, MAX_LAT);
1173 lon0 = ptLon ? getCoord (ptLon + 1, MIN_LON, MAX_LON) : 0.0;
1174
1175 ptLon = coord1 ? strchr (coord1, '-') : NULL;
1176 if (ptLon) *ptLon = '\0'; // cut coord end eliminate '-'
1177 lat1 = getCoord (coord1, MIN_LAT, MAX_LAT);
1178 lon1 = ptLon ? getCoord (ptLon + 1, MIN_LON, MAX_LON) : 0.0;
1179
1180 snprintf(str, sizeof str,
1181 " {\"what\": \"%s\", \"name\": \"%s\", \"id\": \"%s\", "
1182 "\"lat0\": %.4lf, \"lon0\": %.4lf, \"lat1\": %.4lf, \"lon1\": %.4lf, \"status\": \"%s\"},\n",
1183 what, name, id, lat0, lon0, lat1, lon1, status);
1184
1185 strlcat (out, str, maxLen);
1186 g_strfreev(t);
1187 }
1188 end = strrchr (out, ',');
1189 *end = '\0'; // trunk from last comma
1190 strlcat (out, "\n]\n", maxLen);
1191 fclose (f);
1192 return true;
1193}
1194
1196void normalizeSpaces(char *s) {
1197 char *src = s;
1198 char *dst = s;
1199 bool inSpace = false;
1200
1201 while (*src) {
1202 if (*src == ' ') {
1203 if (!inSpace) {
1204 *dst++ = ' ';
1205 inSpace = true;
1206 }
1207 } else {
1208 *dst++ = *src;
1209 inSpace = false;
1210 }
1211 src++;
1212 }
1213 *dst = '\0';
1214}
1215
#define G_PI
Definition glibwrapper.h:4
static void g_strfreev(char **strv)
Free array with elements (like GLib g_strfreev)
Definition glibwrapper.h:30
#define MIN(i, j)
Definition glibwrapper.h:5
static bool g_ascii_isspace(unsigned char c)
GLib LIKE ' ', '\t', ' ', '\v', '\f', '\r'.
#define CLAMP(x, lo, hi)
Definition glibwrapper.h:7
#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
static char ** g_strsplit(const char *string, const char *delimiter, int max_tokens)
Clone of GLib g_strsplit.
Definition glibwrapper.h:37
static char * g_strstrip(char *s)
Équivalent to GLIB g_strstrip: trim in place, return s.
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 fTws(double u, double v)
true wind speed.
Definition inline.h:58
#define MAX_N_COMPETITORS
Definition r3types.h:71
#define SIZE_T_IS_SEA
Definition r3types.h:29
#define MAX_SIZE_FORBID_ZONE
Definition r3types.h:67
#define MAX_N_FORBID_ZONE
Definition r3types.h:68
#define N_MAX_NMEA_PORTS
Definition r3types.h:10
#define MAX_LON
Definition r3types.h:19
#define N_METEO_ADMIN
Definition r3types.h:69
#define MAX_N_WAY_POINT
Definition r3types.h:30
#define MIN_LON
Definition r3types.h:18
@ BASIC
Definition r3types.h:79
@ DM
Definition r3types.h:79
@ DMS
Definition r3types.h:79
@ DD
Definition r3types.h:79
#define WORKING_DIR
Definition r3types.h:12
#define MAX_SIZE_DIR_NAME
Definition r3types.h:64
#define MAX_LAT
Definition r3types.h:17
#define MAX_SIZE_NAME
Definition r3types.h:61
#define MAX_SIZE_FILE_NAME
Definition r3types.h:63
#define MAX_N_SHP_FILES
Definition r3types.h:65
#define MAX_SIZE_LINE
Definition r3types.h:45
#define MAX_SIZE_TEXT
Definition r3types.h:48
#define MAX_SIZE_TEXT_FILE
Definition r3types.h:49
#define MAX_N_SECTORS
Definition r3types.h:73
#define MIN_LAT
Definition r3types.h:16
char * epochToStr(time_t t, bool seconds, char *str, size_t maxLen)
convert epoch time to string with or without seconds
Definition r3util.c:247
bool writeParam(const char *fileName, bool header, bool password, bool yaml)
write parameter file from struct par header or not, password or not yaml style or not
Definition r3util.c:826
char * newDateWeekDayVerbose(long intDate, double nHours, char *res, size_t maxLen)
return date and time using week day after adding myTime (hours) to the Date
Definition r3util.c:401
static void forbidZoneAdd(char *line, int n)
read forbid zone format [[lat, lon], [lat, lon] ...] ...
Definition r3util.c:548
static bool getYMDHM(long dataDate, double nHours, int *yyyy, int *mm, int *dd, int *hh, int *min)
return year, month (1..12), day, hour, minutes from Grib dataDate and hours
Definition r3util.c:328
WayPointList wayPoints
list of wayPoint
Definition r3util.c:43
double fPenalty(int shipIndex, int type, double tws, double energy, double *cStamina, bool fullPack)
for virtual Regatta.
Definition r3util.c:984
char * lonToStr(double lon, int type, char *str, size_t maxLen)
convert lon to str according to type
Definition r3util.c:462
bool readParam(const char *fileName, bool initDisp)
read parameter file and build par struct
Definition r3util.c:573
void updateIsSeaWithForbiddenAreas(void)
complement according to forbidden areas
Definition r3util.c:534
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
#define MAX_N_SHIP_TYPE
compilation: gcc -c r3util.c
Definition r3util.c:2
double offsetLocalUTC(void)
return offset Local UTC in seconds
Definition r3util.c:263
bool readMarkCSVToJson(const char *fileName, char *out, size_t maxLen)
read CSV file marks (Virtual Regatta) if check then polarCheck
Definition r3util.c:1144
double monotonic(void)
return seconds with decimals
Definition r3util.c:1099
static bool isInForbidArea(double lat, double lon)
return true if p is in forbid area
Definition r3util.c:526
double fPointLoss(int shipIndex, int type, double tws, bool fullPack)
for virtual Regatta.
Definition r3util.c:1002
bool isNumber(const char *name)
true if name contains a number
Definition r3util.c:174
PolMat wavePolMat
polar matrix for waves
Definition r3util.c:55
const size_t sailNameSize
sail attributes
Definition r3util.c:38
char * paramToStrJson(Par *par, char *out, size_t maxLen)
Return JSON formatted subset of parameters into 'out'.
Definition r3util.c:1023
MyPolygon forbidZones[MAX_N_FORBID_ZONE]
forbid ones is a set of polygons
Definition r3util.c:32
bool hasSlash(const char *name)
true if name terminates with slash
Definition r3util.c:130
char * buildRootName(const char *fileName, char *rootName, size_t maxLen)
Build root name if not already a root name.
Definition r3util.c:230
char * tIsSea
table describing if sea or earth
Definition r3util.c:61
PolMat polMat
polar matrix description
Definition r3util.c:49
char * newDateWeekDay(long intDate, double nHours, char *res, size_t maxLen)
return date and time using week day after adding myTime (hours) to the Date
Definition r3util.c:394
bool mostRecentFile(const char *directory, const char *pattern0, const char *pattern1, char *name, size_t maxLen)
select most recent file in "directory" that contains "pattern0" and "pattern1" in name return true if...
Definition r3util.c:138
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
bool isEmpty(const char *str)
return true if str is empty
Definition r3util.c:94
static bool isInPolygon(double lat, double lon, const MyPolygon *po)
fill str with polygon information
Definition r3util.c:512
struct tm gribDateToTm(long intDate, double nHours)
return tm struct equivalent to date hours found in grib (UTC time) struct tm gribDateToTm (long intDa...
Definition r3util.c:299
bool readIsSea(const char *fileName)
read issea file and fill table tIsSea
Definition r3util.c:484
static void fprintfNoNull(FILE *f, const char *fmt, const char *param)
Definition r3util.c:815
double getDepartureTimeInHour(struct tm *startUtc)
calculate difference in hours between departure time in UTC and time 0
Definition r3util.c:420
PolMat sailPolMat
polar matrix for sails
Definition r3util.c:52
double tMin[3]
Definition r3util.c:24
char * readTextFile(const char *fileName, char *errMessage, size_t maxLen)
read all text file in buffer.
Definition r3util.c:1106
struct @11 shipParam[MAX_N_SHIP_TYPE]
char * formatThousandSep(char *buffer, size_t maxLen, long value)
format big number with thousand sep.
Definition r3util.c:104
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
const struct MeteoElmt meteoTab[N_METEO_ADMIN]
dictionnary of meteo services
Definition r3util.c:35
char * gribDateTimeToStr(long date, long time, char *str, size_t maxLen)
return str representing grib date
Definition r3util.c:276
double cShip
Definition r3util.c:23
double getCoord(const char *str, double minLimit, double maxLimit)
translate str in double for latitude longitude
Definition r3util.c:179
int nearestPort(double lat, double lon, const char *fileName, char *res, size_t maxLen)
return id and name of nearest port found in file fileName from lat, lon.
Definition r3util.c:1063
const char * sailName[]
Definition r3util.c:39
char * otherNewDate(long dataDate, double nHours, char *res, size_t maxLen)
return date and time using ISO notation after adding myTime (hours) to the Date
Definition r3util.c:376
char * latToStr(double lat, int type, char *str, size_t maxLen)
convert lat to str according to type
Definition r3util.c:440
char * newFileNameSuffix(const char *fileName, const char *suffix, char *newFileName, size_t maxLen)
replace former suffix (after last dot) by suffix example : "pol/bibi.toto.csv" with suffix "sailpol" ...
Definition r3util.c:78
double tMax[3]
Definition r3util.c:25
char name[MAX_SIZE_NAME]
Definition r3util.c:22
double fTimeToRecupOnePoint(double tws)
for virtual Regatta.
Definition r3util.c:1014
time_t gribDateTimeToEpoch(long date, long hhmm)
convert long date/time from GRIB to time_t (UTC, via timegm)
Definition r3util.c:408
const char * colorStr[]
Definition r3util.c:40
void normalizeSpaces(char *s)
replace multiple spaces by just one
Definition r3util.c:1196
static void fprintfNoZero(FILE *f, const char *fmt, int param)
Definition r3util.c:819
static bool bissextile(int year)
retrurn true if year is bissextile
Definition r3util.c:323
int colorIndex
Definition r3types.h:261
double lon
Definition r3types.h:263
double lat
Definition r3types.h:262
char name[MAX_SIZE_NAME]
Definition r3types.h:267
Competitor t[MAX_N_COMPETITORS]
Definition r3types.h:275
Structure for polygon.
Definition r3types.h:94
int n
Definition r3types.h:95
Point * points
Definition r3types.h:96
Parameters.
Definition r3types.h:318
double nightEfficiency
Definition r3types.h:394
int nForbidZone
Definition r3types.h:411
int nNmea
Definition r3types.h:419
int speedDisp
Definition r3types.h:385
char polarFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:344
int jFactor
Definition r3types.h:333
double gribResolution
Definition r3types.h:339
struct Par::@10 nmea[N_MAX_NMEA_PORTS]
char description[MAX_SIZE_LINE]
Definition r3types.h:372
char shpFileName[MAX_N_SHP_FILES][MAX_SIZE_FILE_NAME]
Definition r3types.h:349
char windyApiKey[MAX_SIZE_TEXT]
Definition r3types.h:399
char pOrName[MAX_SIZE_NAME]
Definition r3types.h:368
char imapToSeen[MAX_SIZE_LINE]
Definition r3types.h:374
int penalty1
Definition r3types.h:390
char imapUserName[MAX_SIZE_NAME]
Definition r3types.h:407
int withCurrent
Definition r3types.h:421
int special
Definition r3types.h:327
int penalty0
Definition r3types.h:389
int showColors
Definition r3types.h:371
Pp pDest
Definition r3types.h:367
char smtpScript[MAX_SIZE_LINE]
Definition r3types.h:373
double maxWind
Definition r3types.h:397
char portName[MAX_SIZE_NAME]
Definition r3types.h:415
int gridDisp
Definition r3types.h:381
char gribFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:337
int focalDisp
Definition r3types.h:383
int kFactor
Definition r3types.h:334
char feedbackFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:358
char dashboardVR[MAX_SIZE_FILE_NAME]
Definition r3types.h:361
double constWindTws
Definition r3types.h:328
char isSeaFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:350
int withWaves
Definition r3types.h:420
int indicatorDisp
Definition r3types.h:380
int maxPoiVisible
Definition r3types.h:322
int techno
Definition r3types.h:413
char marksFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:362
char traceFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:355
char dumpIFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:346
char helpFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:348
char imapServer[MAX_SIZE_NAME]
Definition r3types.h:406
int authent
Definition r3types.h:319
bool storeMailPw
Definition r3types.h:410
char workingDir[MAX_SIZE_FILE_NAME]
Definition r3types.h:336
int closestDisp
Definition r3types.h:382
int curlSys
Definition r3types.h:401
int nShpFiles
Definition r3types.h:364
char web[MAX_SIZE_DIR_NAME]
Definition r3types.h:342
double constCurrentD
Definition r3types.h:332
char imapMailBox[MAX_SIZE_NAME]
Definition r3types.h:408
double tStep
Definition r3types.h:324
double constWindTwd
Definition r3types.h:329
int style
Definition r3types.h:370
int waveDisp
Definition r3types.h:379
char wavePolFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:345
char smtpServer[MAX_SIZE_NAME]
Definition r3types.h:403
double dayEfficiency
Definition r3types.h:395
double threshold
Definition r3types.h:393
double motorSpeed
Definition r3types.h:392
int nSectors
Definition r3types.h:335
double constWave
Definition r3types.h:330
char pDestName[MAX_SIZE_NAME]
Definition r3types.h:369
char smtpUserName[MAX_SIZE_NAME]
Definition r3types.h:404
char logFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:359
int dashboardUTC
Definition r3types.h:321
int allwaysSea
Definition r3types.h:320
int opt
Definition r3types.h:323
int penalty2
Definition r3types.h:391
char midFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:356
Pp pOr
Definition r3types.h:366
int speed
Definition r3types.h:416
char googleApiKey[MAX_SIZE_TEXT]
Definition r3types.h:400
char currentGribFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:343
char webkit[MAX_SIZE_NAME]
Definition r3types.h:398
int stepIsocDisp
Definition r3types.h:388
char mailPw[MAX_SIZE_NAME]
Definition r3types.h:409
int python
Definition r3types.h:402
int aisDisp
Definition r3types.h:386
double xWind
Definition r3types.h:396
char tidesFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:357
char portFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:353
char dumpRFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:347
char wpGpxFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:360
int gribTimeMax
Definition r3types.h:341
char smtpTo[MAX_SIZE_NAME]
Definition r3types.h:405
int gribTimeStep
Definition r3types.h:340
double staminaVR
Definition r3types.h:363
int rangeCog
Definition r3types.h:326
double constCurrentS
Definition r3types.h:331
int currentDisp
Definition r3types.h:378
char cliHelpFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:351
char imapScript[MAX_SIZE_LINE]
Definition r3types.h:375
char parInfoFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:354
double startTimeInHours
Definition r3types.h:365
char poiFileName[MAX_SIZE_FILE_NAME]
Definition r3types.h:352
int mostRecentGrib
Definition r3types.h:338
int dispDms
Definition r3types.h:376
int shpPointsDisp
Definition r3types.h:387
int windDisp
Definition r3types.h:377
int infoDisp
Definition r3types.h:384
int cogStep
Definition r3types.h:325
Structure for SHP and forbid zones.
Definition r3types.h:88
double lat
Definition r3types.h:89
double lon
Definition r3types.h:90
polar Matrix description
Definition r3types.h:201
char name[MAX_SIZE_NAME]
Definition r3types.h:211
struct PolMat::@9 tSail[MAX_N_SAIL]
size_t nSail
Definition r3types.h:208
int id
Definition r3types.h:173
int father
Definition r3types.h:174
double lat
Definition r3types.h:180
double lon
Definition r3types.h:181
double totLoxoDist
Definition r3types.h:255
double totOrthoDist
Definition r3types.h:254
WayPoint t[MAX_N_WAY_POINT]
Definition r3types.h:256
double lon
Definition r3types.h:219
double lat
Definition r3types.h:218
zone description
Definition r3types.h:140
double latMin
Definition r3types.h:149
double lonRight
Definition r3types.h:152
long dataTime[MAX_N_DATA_TIME]
Definition r3types.h:165
double latMax
Definition r3types.h:150
double lonLeft
Definition r3types.h:151
long dataDate[MAX_N_DATA_DATE]
Definition r3types.h:164