2#define MAX_N_SHIP_TYPE 2
27 {
"Imoca", 1.2, {300, 300, 420}, {660, 660, 600}},
28 {
"Normal", 1.0, {300, 300, 336}, {660, 660, 480}}
39const char *
sailName [] = {
"C0",
"HG",
"Jib",
"LG",
"LJ",
"Spi",
"SS"};
40const char *
colorStr [] = {
"green",
"purple",
"gray",
"blue",
"yellow",
"orange",
"red"};
68char *
fSailName (
int val,
char *str,
size_t maxLen) {
78char *
newFileNameSuffix (
const char *fileName,
const char *suffix,
char *newFileName,
size_t maxLen) {
79 const char *lastDot = strrchr(fileName,
'.');
80 const size_t baseLen = (lastDot == NULL) ? strlen (fileName) : (size_t) (lastDot - fileName);
83 if (baseLen + strlen (suffix) + 1 >= maxLen) {
86 g_strlcpy (newFileName, fileName, baseLen + 1);
87 strlcat (newFileName,
".", maxLen);
88 strlcat (newFileName, suffix, maxLen);
95 if (str == NULL)
return true;
107 const int length = strlen (str);
108 const int nSep = length / 3;
109 const int mod = length % 3;
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++];
119 if (j >= (
int) maxLen) {
125 if (buffer [j - 1] ==
' ') buffer [j - 1] =
'\0';
132 const size_t len = strlen(
name);
133 return name[len - 1] ==
'/';
138bool mostRecentFile (
const char *directory,
const char *pattern0,
const char *pattern1,
char *
name,
size_t maxLen) {
139 DIR *dir = opendir (directory);
141 fprintf (stderr,
"In mostRecentFile, Error opening: %s\n", directory);
145 struct dirent *entry;
147 time_t latestTime = 0;
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)
157 && statbuf.st_mtime > latestTime)) {
159 latestTime = statbuf.st_mtime;
160 if (strlen (entry->d_name) < maxLen)
161 snprintf (
name, maxLen,
"%s/%s", directory, entry->d_name);
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);
170 return (latestTime > 0);
175 return (
name != NULL) && (strpbrk (
name,
"0123456789") != NULL);
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";
184 int sign = (strpbrk (str, neg) == NULL) ? 1 : -1;
188 while (*str && (! (isdigit (*str) || (*str ==
'-') || (*str ==
'+'))))
190 deg = strtod (str, NULL);
191 if (deg < 0) sign = -1;
194 if ((strchr (str,
'\'') != NULL)) {
196 if ((pt = strstr (str,
"°")) != NULL) pt += 2;
198 if ((pt = strpbrk (str, neg)) != NULL) pt += 1;
200 if (pt != NULL) min = strtod (pt, NULL);
203 if (minFound && (strchr (str,
'"') != NULL)) {
204 sec = strtod (strchr (str,
'\'') + 1, NULL);
207 return CLAMP (sign * (deg + min/60.0 + sec/3600.0), minLimit, maxLimit);
231 if (!fileName || !rootName || maxLen == 0)
return NULL;
235 if (fileName [0] ==
'/') n = snprintf(rootName, maxLen,
"%s", fileName);
236 else n = snprintf(rootName, maxLen,
"%s%s%s", workingDir,
hasSlash (workingDir) ?
"" :
"/", fileName);
238 if (n < 0 || (
size_t)n >= maxLen) {
240 if (maxLen) rootName[0] =
'\0';
247char *
epochToStr (time_t t,
bool seconds,
char *str,
size_t maxLen) {
248 struct tm *utc = gmtime (&t);
249 if (!utc)
return NULL;
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);
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);
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;
272 return offsetSeconds;
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);
302 tm0.tm_year = (int)(intDate / 10000) - 1900;
303 tm0.tm_mon = (int)((intDate % 10000) / 100) - 1;
304 tm0.tm_mday = (int)(intDate % 100);
306 int totalMinutes = (int)lround(nHours * 60.0);
307 int days = totalMinutes / (24 * 60);
308 int minutesDay = totalMinutes % (24 * 60);
311 tm0.tm_hour = minutesDay / 60;
312 tm0.tm_min = minutesDay % 60;
316 time_t t = timegm(&tm0);
324 return (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0));
328static bool getYMDHM (
long dataDate,
double nHours,
int *yyyy,
int *mm,
int *dd,
int *hh,
int *min) {
330 fprintf(stderr,
"getYMDHM: nHours must be >= 0 (%.3f)\n", nHours);
333 static const int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
335 int year = (int)(dataDate / 10000);
336 int month = (int)((dataDate % 10000) / 100) - 1;
337 int day = (int)(dataDate % 100);
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);
348 minute = minute % 60;
356 int dim = daysInMonth[month];
358 if (day <= dim)
break;
376char *
otherNewDate (
long dataDate,
double nHours,
char *res,
size_t maxLen) {
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);
386char *
newDate (
long intDate,
double nHours,
char *res,
size_t maxLen) {
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);
396 strftime (res, maxLen,
"%a %H:%M", &tm0);
403 strftime (res, maxLen,
"%A, %b %d at %H:%M UTC", &tm0);
409 struct tm tm_utc = {0};
410 tm_utc.tm_year = (int)(date / 10000) - 1900;
411 tm_utc.tm_mon = (int)((date % 10000) / 100) - 1;
412 tm_utc.tm_mday = (int)(date % 100);
413 tm_utc.tm_hour = (int)(hhmm / 100);
414 tm_utc.tm_min = (int)(hhmm % 100);
416 return timegm(&tm_utc);
422 if (t0 == (time_t)-1)
return NAN;
423 const time_t tStart = timegm(startUtc);
424 if (tStart == (time_t)-1)
return NAN;
425 return difftime(tStart, t0) / 3600.0;
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);
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';
445 if (lat > 90.0 || lat < -90.0) {
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;
454 snprintf (str, maxLen,
"%02d°%02d'%02.0lf\"%c", (
int) fabs (lat), (
int) fabs(mn), fabs(sec), c);
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';
467 if (lon > 180.0 || lon < -180.0) {
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;
476 snprintf (str, maxLen,
"%03d°%02d'%02.0lf\"%c", (
int) fabs (lon), (
int) fabs(mn), fabs(sec), c);
489 if ((f = fopen (fileName,
"r")) == NULL) {
490 fprintf (stderr,
"In readIsSea, Error cannot open: %s\n", fileName);
494 fprintf (stderr,
"In readIsSea, error Malloc");
500 if (c ==
'1') nSea += 1;
516 for (i = 0, j = po->
n - 1; i < po->
n; j = i++) {
535 if (
tIsSea == NULL)
return;
538 const double lon = (i % 3601) / 10 - 180.0;
539 const double lat = 90.0 - (i / (3601 *10));
550 char *latToken, *lonToken;
554 fprintf (stderr,
"In forbidZoneAdd, Error realloc with n = %d\n", n);
559 if (((latToken = strtok (line,
",")) == NULL) || ((lonToken = strtok (NULL,
"]")) == NULL))
return;
563 while ((idx <
MAX_SIZE_FORBID_ZONE) && ((latToken = strtok (NULL,
",")) != NULL) && ((lonToken = strtok (NULL,
"]")) != NULL)) {
574 bool inWp =
false, inForbidZone =
false, inCompetitor =
false;
579 char *pLine = &buffer [0];
580 memset (&
par, 0,
sizeof (
Par));
606 if ((f = fopen (fileName,
"r")) == NULL) {
607 fprintf (stderr,
"In readParam, Error Cannot open: %s\n", fileName);
611 while (fgets (pLine,
sizeof (buffer), f) != NULL ) {
615 if ((!*pLine) || *pLine ==
'#' || *pLine ==
'\n')
continue;
616 if ((pt = strchr (pLine,
'#')) != NULL)
618 if (strncmp (pLine,
"-", 1) != 0) inWp = inForbidZone = inCompetitor =
false;
620 if (strncmp (pLine,
"---", 3) == 0) {}
624 else if (sscanf (pLine,
"ALLWAYS_SEA:%d", &
par.
allwaysSea) > 0);
626 else if (sscanf (pLine,
"POI:%255s", str) > 0)
628 else if (sscanf (pLine,
"PORT:%255s", str) > 0)
631 else if (sscanf(pLine,
"POR: [%63[^,], %63[^]]", strLat, strLon) == 2) {
637 else if (sscanf(pLine,
"PDEST: [%63[^,], %63[^]]", strLat, strLon) == 2) {
643 else if (strstr (pLine,
"WP:") != NULL) inWp =
true;
644 else if (inWp && (sscanf (pLine,
"- [%63[^,], %63[^]]", strLat, strLon) == 2)) {
646 fprintf (stderr,
"In readParam, Error: number of wayPoints exceeded; %d\n",
MAX_N_WAY_POINT);
653 else if (strstr (pLine,
"COMPETITORS:") != NULL) inCompetitor =
true;
654 else if (inCompetitor &&
655 (sscanf (pLine,
"- [%d, %63[^,], %63[^,], %63[^]]",
659 fprintf (stderr,
"In readParam, Error number of competitors exceeded; %d\n",
MAX_N_COMPETITORS);
672 else if (sscanf (pLine,
"POR_NAME:%255s",
par.
pOrName) > 0);
673 else if (sscanf (pLine,
"PDEST_NAME:%255s",
par.
pDestName) > 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;
702 else if (sscanf (pLine,
"VR_STAMINA:%lf", &
par.
staminaVR) > 0);
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) {
717 fprintf (stderr,
"In readParam, Error Number max of SHP files reached: %d\n",
par.
nShpFiles);
719 else if (sscanf (pLine,
"AUTHENT:%d", &
par.
authent) > 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);
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);
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)) {
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);
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);
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);
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);
778 else if (sscanf (pLine,
"GOOGLE_API_KEY:%1024s",
par.
googleApiKey) > 0);
779 else if (sscanf (pLine,
"WINDY_API_KEY:%1024s",
par.
windyApiKey) > 0);
781 else if (strstr (pLine,
"FORBID_ZONES:") != NULL) inForbidZone =
true;
782 else if (inForbidZone && ((pt = strstr (pLine,
"- [[")) != NULL)) {
787 else fprintf (stderr,
"In readParam, MAX_N_FORBID_ZONE: %d\n",
MAX_N_FORBID_ZONE);
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);
800 else fprintf (stderr,
"In readParam, Error Cannot interpret: %s\n", pLine);
816 if (!param || ! *param)
return;
817 fprintf (f, fmt, param);
820 if (param == 0)
return;
821 fprintf (f, fmt, param);
826bool writeParam (
const char *fileName,
bool header,
bool password,
bool yaml) {
830 if ((f = fopen (fileName,
"w")) == NULL) {
831 fprintf (stderr,
"In writeParam, Error Cannot write: %s\n", fileName);
834 if (header) fprintf (f,
"Name Value\n");
835 if (yaml) fprintf (f,
"---\n");
851 fprintf (f,
"WP:\n");
857 fprintf (f,
"COMPETITORS:\n");
895 fprintf (f,
"T_STEP: %.2lf\n",
par.
tStep);
905 fprintf (f,
"X_WIND: %.2lf\n",
par.
xWind);
906 fprintf (f,
"MAX_WIND: %.2lf\n",
par.
maxWind);
963 fprintf (f,
"FORBID_ZONES:\n");
969 fprintf (f,
"[%s, %s]%s", strLat, strLon, j <
forbidZones [i].n - 1 ?
", " :
"");
971 if (yaml) fprintf (f,
"] # yamllint disable-line\n");
972 else fprintf (f,
"]\n");
976 fprintf (f,
"MAIL_PW: %s\n",
par.
mailPw);
977 if (yaml) fprintf (f,
"...\n");
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);
989 const double kPenalty = 0.015;
991 *cStamina = 2.0 - fmin (energy, 100.0) * kPenalty;
994 const double fTws = 50.0 - 50.0 * cos (
G_PI * ((fmax (10.0, fmin (tws, 30.0))-10.0)/(30.0 - 10.0)));
997 if (fullPack) t *= 0.8;
998 return t *
cShip * (*cStamina);
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;
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 :
1015 const double timeToRecupLow = 5.0 * 60.0;
1016 const double timeToRecupHigh = 15.0 * 60.0;
1017 const double fTws = 1.0 - cos (
G_PI * (fmin (tws, 30.0)/30.0));
1018 return timeToRecupLow +
fTws * (timeToRecupHigh - timeToRecupLow) / 2.0;
1024 if (!
par || !out || maxLen == 0)
return NULL;
1032 int n = snprintf(out, maxLen,
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"
1052 free(fileNameCurrent);
1053 free(polarFileName);
1054 free(wavePolarFileName);
1055 free(isSeaFileName);
1057 if (n < 0)
return NULL;
1058 if ((
size_t)n >= maxLen)
return NULL;
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;
1071 double latPort, lonPort;
1073 int id = 0, bestId = 0;
1075 if ((lat < minShomLat) || (lat > maxShomLat) || (lon < minShomLon) || (lon > maxShomLon))
1078 if ((f = fopen (fileName,
"r")) == NULL) {
1079 fprintf (stderr,
"In nearestPort, Error cannot open: %s\n", fileName);
1083 if (sscanf (str,
"%lf,%lf,%63[^,],%d", &latPort, &lonPort, portName, &
id) > 2) {
1084 double d =
orthoDist (lat, lon, latPort, lonPort);
1101 clock_gettime(CLOCK_MONOTONIC, &ts);
1102 return (
double) ts.tv_sec + (double) ts.tv_nsec * 1e-9;
1106char *
readTextFile (
const char *fileName,
char *errMessage,
size_t maxLen) {
1107 FILE *f = fopen(fileName,
"rb");
1109 snprintf(errMessage, maxLen,
"In readFile: Error Cannot open: %s\n", fileName);
1113 if (fstat(fileno(f), &st) != 0) {
1114 snprintf(errMessage, maxLen,
"In readFile: cannot stat %s\n", fileName);
1118 if (st.st_size < 0) {
1119 snprintf(errMessage, maxLen,
"In readFile: negative file size?\n");
1123 size_t fileSize = (size_t)st.st_size;
1124 char *buffer = malloc(fileSize + 1);
1126 snprintf(errMessage, maxLen,
"In readFile: Malloc failed: %zu\n", fileSize + 1);
1130 size_t nread = fread(buffer, 1, fileSize, f);
1131 if (nread != fileSize && ferror(f)) {
1132 snprintf(errMessage, maxLen,
"In readFile: fread error\n");
1137 buffer[nread] =
'\0';
1148 char *what, *
name, *id, *coord0, *coord1, *status, *end, *ptLon;
1149 double lat0 = 0.0, lon0 = 0.0, lat1 = 0.0, lon1 = 0.0;
1152 if ((f = fopen (fileName,
"r")) == NULL) {
1153 snprintf (out, maxLen,
"Error in readMarkCSVToJson: cannot open: %s\n", fileName);
1156 strlcpy (out,
"[\n", maxLen);
1158 while (fgets(buffer,
sizeof buffer, f)) {
1161 if (t == NULL)
continue;
1170 ptLon = coord0 ? strchr (coord0,
'-') : NULL;
1171 if (ptLon) *ptLon =
'\0';
1175 ptLon = coord1 ? strchr (coord1,
'-') : NULL;
1176 if (ptLon) *ptLon =
'\0';
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);
1185 strlcat (out, str, maxLen);
1188 end = strrchr (out,
',');
1190 strlcat (out,
"\n]\n", maxLen);
1199 bool inSpace =
false;
static void g_strfreev(char **strv)
Free array with elements (like GLib g_strfreev)
static bool g_ascii_isspace(unsigned char c)
GLib LIKE ' ', '\t', ' ', '\v', '\f', '\r'.
#define g_strlcpy(dest, src, size)
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.
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
static double fTws(double u, double v)
true wind speed.
#define MAX_N_COMPETITORS
#define MAX_SIZE_FORBID_ZONE
#define MAX_N_FORBID_ZONE
#define MAX_SIZE_DIR_NAME
#define MAX_SIZE_FILE_NAME
#define MAX_SIZE_TEXT_FILE
char * epochToStr(time_t t, bool seconds, char *str, size_t maxLen)
convert epoch time to string with or without seconds
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
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
static void forbidZoneAdd(char *line, int n)
read forbid zone format [[lat, lon], [lat, lon] ...] ...
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
WayPointList wayPoints
list of wayPoint
double fPenalty(int shipIndex, int type, double tws, double energy, double *cStamina, bool fullPack)
for virtual Regatta.
char * lonToStr(double lon, int type, char *str, size_t maxLen)
convert lon to str according to type
bool readParam(const char *fileName, bool initDisp)
read parameter file and build par struct
void updateIsSeaWithForbiddenAreas(void)
complement according to forbidden areas
char * durationToStr(double duration, char *res, size_t maxLen)
convert hours in string with days, hours, minutes
#define MAX_N_SHIP_TYPE
compilation: gcc -c r3util.c
double offsetLocalUTC(void)
return offset Local UTC in seconds
bool readMarkCSVToJson(const char *fileName, char *out, size_t maxLen)
read CSV file marks (Virtual Regatta) if check then polarCheck
double monotonic(void)
return seconds with decimals
static bool isInForbidArea(double lat, double lon)
return true if p is in forbid area
double fPointLoss(int shipIndex, int type, double tws, bool fullPack)
for virtual Regatta.
bool isNumber(const char *name)
true if name contains a number
PolMat wavePolMat
polar matrix for waves
const size_t sailNameSize
sail attributes
char * paramToStrJson(Par *par, char *out, size_t maxLen)
Return JSON formatted subset of parameters into 'out'.
MyPolygon forbidZones[MAX_N_FORBID_ZONE]
forbid ones is a set of polygons
bool hasSlash(const char *name)
true if name terminates with slash
char * buildRootName(const char *fileName, char *rootName, size_t maxLen)
Build root name if not already a root name.
char * tIsSea
table describing if sea or earth
PolMat polMat
polar matrix description
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
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...
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
bool isEmpty(const char *str)
return true if str is empty
static bool isInPolygon(double lat, double lon, const MyPolygon *po)
fill str with polygon information
struct tm gribDateToTm(long intDate, double nHours)
return tm struct equivalent to date hours found in grib (UTC time) struct tm gribDateToTm (long intDa...
bool readIsSea(const char *fileName)
read issea file and fill table tIsSea
static void fprintfNoNull(FILE *f, const char *fmt, const char *param)
double getDepartureTimeInHour(struct tm *startUtc)
calculate difference in hours between departure time in UTC and time 0
PolMat sailPolMat
polar matrix for sails
char * readTextFile(const char *fileName, char *errMessage, size_t maxLen)
read all text file in buffer.
struct @11 shipParam[MAX_N_SHIP_TYPE]
char * formatThousandSep(char *buffer, size_t maxLen, long value)
format big number with thousand sep.
char * fSailName(int val, char *str, size_t maxLen)
return the name of the sail
Zone zone
geographic zone covered by grib file
CompetitorsList competitors
list of competitors
const struct MeteoElmt meteoTab[N_METEO_ADMIN]
dictionnary of meteo services
char * gribDateTimeToStr(long date, long time, char *str, size_t maxLen)
return str representing grib date
double getCoord(const char *str, double minLimit, double maxLimit)
translate str in double for latitude longitude
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.
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
char * latToStr(double lat, int type, char *str, size_t maxLen)
convert lat to str according to type
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" ...
double fTimeToRecupOnePoint(double tws)
for virtual Regatta.
time_t gribDateTimeToEpoch(long date, long hhmm)
convert long date/time from GRIB to time_t (UTC, via timegm)
void normalizeSpaces(char *s)
replace multiple spaces by just one
static void fprintfNoZero(FILE *f, const char *fmt, int param)
static bool bissextile(int year)
retrurn true if year is bissextile
Competitor t[MAX_N_COMPETITORS]
char polarFileName[MAX_SIZE_FILE_NAME]
struct Par::@10 nmea[N_MAX_NMEA_PORTS]
char description[MAX_SIZE_LINE]
char shpFileName[MAX_N_SHP_FILES][MAX_SIZE_FILE_NAME]
char windyApiKey[MAX_SIZE_TEXT]
char pOrName[MAX_SIZE_NAME]
char imapToSeen[MAX_SIZE_LINE]
char imapUserName[MAX_SIZE_NAME]
char smtpScript[MAX_SIZE_LINE]
char portName[MAX_SIZE_NAME]
char gribFileName[MAX_SIZE_FILE_NAME]
char feedbackFileName[MAX_SIZE_FILE_NAME]
char dashboardVR[MAX_SIZE_FILE_NAME]
char isSeaFileName[MAX_SIZE_FILE_NAME]
char marksFileName[MAX_SIZE_FILE_NAME]
char traceFileName[MAX_SIZE_FILE_NAME]
char dumpIFileName[MAX_SIZE_FILE_NAME]
char helpFileName[MAX_SIZE_FILE_NAME]
char imapServer[MAX_SIZE_NAME]
char workingDir[MAX_SIZE_FILE_NAME]
char web[MAX_SIZE_DIR_NAME]
char imapMailBox[MAX_SIZE_NAME]
char wavePolFileName[MAX_SIZE_FILE_NAME]
char smtpServer[MAX_SIZE_NAME]
char pDestName[MAX_SIZE_NAME]
char smtpUserName[MAX_SIZE_NAME]
char logFileName[MAX_SIZE_FILE_NAME]
char midFileName[MAX_SIZE_FILE_NAME]
char googleApiKey[MAX_SIZE_TEXT]
char currentGribFileName[MAX_SIZE_FILE_NAME]
char webkit[MAX_SIZE_NAME]
char mailPw[MAX_SIZE_NAME]
char tidesFileName[MAX_SIZE_FILE_NAME]
char portFileName[MAX_SIZE_FILE_NAME]
char dumpRFileName[MAX_SIZE_FILE_NAME]
char wpGpxFileName[MAX_SIZE_FILE_NAME]
char smtpTo[MAX_SIZE_NAME]
char cliHelpFileName[MAX_SIZE_FILE_NAME]
char imapScript[MAX_SIZE_LINE]
char parInfoFileName[MAX_SIZE_FILE_NAME]
char poiFileName[MAX_SIZE_FILE_NAME]
Structure for SHP and forbid zones.
struct PolMat::@9 tSail[MAX_N_SAIL]
WayPoint t[MAX_N_WAY_POINT]
long dataTime[MAX_N_DATA_TIME]
long dataDate[MAX_N_DATA_DATE]