RCube
Rcube Rest Server calculates sail routes based on Grib files and sailing boat polar files
Loading...
Searching...
No Matches
inline.h
Go to the documentation of this file.
1
4#include <math.h>
5#include <time.h>
6
8static inline bool isSea (char * isSeaArray, double lat, double lon) {
9 if (isSeaArray == NULL) return true;
10 int iLon = round (lon * 10 + 1800);
11 int iLat = round (-lat * 10 + 900);
12 return isSeaArray [(iLat * 3601) + iLon];
13}
14
16static inline bool isSeaTolerant (char * isSeaArray, double lat, double lon) {
17 if (isSeaArray == NULL) return true;
18 int iLonInf = floor (lon * 10 + 1800);
19 int iLonSup = ceil (lon * 10 + 1800);
20 int iLatInf = floor (-lat * 10 + 900);
21 int iLatSup = ceil (-lat * 10 + 900);
22 return isSeaArray [(iLatInf * 3601) + iLonInf]
23 || isSeaArray [(iLatInf * 3601) + iLonSup]
24 || isSeaArray [(iLatSup * 3601) + iLonInf]
25 || isSeaArray [(iLatSup * 3601) + iLonSup];
26}
27
29static inline double lonCanonize (double lon) {
30 return remainder (lon, 360.0);
31}
32/* equivalent to:
33 lon = fmod (lon, 360);
34 if (lon > 180) lon -= 360;
35 else if (lon <= -180) lon += 360;
36 return lon;
37*/
38
40static inline double lonNormalize (double lon, bool anteMeridian) {
41 lonCanonize (lon);
42 if (anteMeridian && lon < 0) lon += 360;
43 return lon;
44}
45
47static inline bool isInZone (double lat, double lon, Zone *zone) {
48 return (lat >= zone->latMin) && (lat <= zone->latMax) && (lon >= zone->lonLeft) && (lon <= zone->lonRight);
49}
50
52static inline double fTwd (double u, double v) {
53 double val = 180 + RAD_TO_DEG * atan2 (u, v);
54 return (val > 180) ? val - 360 : val;
55}
56
58static inline double fTws (double u, double v) {
59 return MS_TO_KN * hypot (u, v);
60}
61
64static inline double fTwa (double heading, double twd) {
65 double val = fmod ((twd - heading), 360.0);
66 return (val > 180) ? val - 360 : (val < -180) ? val + 360 : val;
67}
68
70static inline void fAwaAws (double twa, double tws, double sog, double *awa, double *aws) {
71 double a = tws * sin (DEG_TO_RAD * twa);
72 double b = tws * cos (DEG_TO_RAD * twa) + sog;
73 *awa = RAD_TO_DEG * atan2 (a, b);
74 *aws = hypot (a, b);
75}
76
78static inline double interpolate (double x, double x0, double x1, double fx0, double fx1) {
79 if (x1 == x0) return fx0;
80 else return fx0 + (x-x0) * (fx1-fx0) / (x1-x0);
81}
82
84static inline double givry (double lat1, double lon1, double lat2, double lon2) {
85 return (0.5 * (lon1 - lon2)) * sin (0.5 * (lat1 + lat2) * DEG_TO_RAD);
86}
87
89static inline double directCap (double lat1, double lon1, double lat2, double lon2) {
90 return RAD_TO_DEG * atan2 ((lon2 - lon1) * cos (DEG_TO_RAD * 0.5 * (lat1 + lat2)), lat2 - lat1);
91}
92
96static inline double orthoCap (double lat1, double lon1, double lat2, double lon2) {
97 const double avgLat = 0.5 * (lat1 + lat2);
98 const double deltaLat = lat2 - lat1;
99 const double deltaLon = lon2 - lon1;
100 const double avgLatRad = avgLat * DEG_TO_RAD;
101 const double cap = RAD_TO_DEG * atan2 (deltaLon * cos (avgLatRad), deltaLat);
102 const double givryCorrection = -0.5 * deltaLon * sin (avgLatRad); // ou fast_sin(avgLatRad)
103
104 return cap + givryCorrection;
105}
106
108static inline double orthoCap2 (double lat1, double lon1, double lat2, double lon2) {
109 lat1 *= DEG_TO_RAD;
110 lat2 *= DEG_TO_RAD;
111 double delta_lon = (lon2 - lon1) * DEG_TO_RAD;
112 double y = sin(delta_lon) * cos(lat2);
113 double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(delta_lon);
114
115 return fmod(RAD_TO_DEG * atan2(y, x) + 360.0, 360.0);
116}
117
119static inline double loxoDist (double lat1, double lon1, double lat2, double lon2) {
120 // Convert degrees to radians
121 double lat1_rad = DEG_TO_RAD * lat1;
122 double lon1_rad = DEG_TO_RAD * lon1;
123 double lat2_rad = DEG_TO_RAD * lat2;
124 double lon2_rad = DEG_TO_RAD * lon2;
125
126 // Difference in longitude
127 double delta_lon = lon2_rad - lon1_rad;
128
129 // Calculate the change in latitude
130 double delta_lat = lat2_rad - lat1_rad;
131
132 // Calculate the mean latitude
133 double mean_lat = (lat1_rad + lat2_rad) / 2.0;
134
135 // Calculate the rhumb line distance
136 double q = delta_lat / log(tan(G_PI / 4 + lat2_rad / 2) / tan (G_PI / 4 + lat1_rad / 2));
137
138 // Correct for delta_lat being very small
139 if (isnan (q)) q = cos (mean_lat);
140
141 // Distance formula
142 return hypot (delta_lat, q * delta_lon) * EARTH_RADIUS;
143 // return sqrt (delta_lat * delta_lat + (q * delta_lon) * (q * delta_lon)) * EARTH_RADIUS;
144}
145
147static inline double orthoDist(double lat1, double lon1, double lat2, double lon2) {
148 lat1 *= DEG_TO_RAD;
149 lat2 *= DEG_TO_RAD;
150 double theta = (lon1 - lon2) * DEG_TO_RAD;
151
152 double cosDist = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(theta);
153 cosDist = CLAMP (cosDist, -1.0, 1.0); // to avoid NaN on acos()
154
155 double distRad = acos(cosDist);
156 return 60.0 * RAD_TO_DEG * distRad;
157}
158
161static inline double orthoDist2 (double lat1, double lon1, double lat2, double lon2) {
162 lat1 *= DEG_TO_RAD;
163 lat2 *= DEG_TO_RAD;
164 double dLat = lat2 - lat1;
165 double dLon = (lon2 - lon1) * DEG_TO_RAD;
166
167 double a = sin(dLat / 2) * sin(dLat / 2) + cos(lat1) * cos(lat2) * sin(dLon / 2) * sin(dLon / 2);
168 double c = 2 * atan2(sqrt(a), sqrt(1 - a));
169
170 return 60.0 * RAD_TO_DEG * c;
171}
172
174static inline double findPolar (double twa, double w, const PolMat *mat, const PolMat *sailMat, int *sail) {
175 const int nLine = mat->nLine; // local copy for perf
176 const int nCol = mat->nCol;
177 int l, c, lInf, cInf, lSup, cSup;
178 int bestL, bestC; // for sail
179
180 if (twa > 180.0) twa = 360.0 - twa;
181 else if (twa < 0.0) twa = -twa;
182
183 for (l = 1; l < nLine; l++) {
184 if (mat->t [l][0] > twa) break;
185 }
186 lSup = (l < nLine) ? l : nLine - 1;
187 lInf = (l == 1) ? 1 : l - 1;
188
189 for (c = 1; c < nCol; c++) {
190 if (mat->t [0][c] > w) break;
191 }
192 cSup = (c < nCol - 1) ? c : nCol - 1;
193 cInf = (c == 1) ? 1 : c - 1;
194
195 // sail
196 if (sailMat != NULL && sailMat->nLine == nLine && sailMat->nCol == nCol) { // sail requested
197 bestL = ((twa - mat->t [lInf][0]) < (mat->t [lSup][0] - twa)) ? lInf : lSup; // for sail line
198 bestC = ((w - mat->t [0][cInf]) < (mat->t [0][cSup] - w)) ? cInf : cSup; // for sail col
199 *sail = sailMat->t [bestL][bestC]; // sail found
200 }
201 else *sail = 0;
202
203 const double lInf0 = mat->t [lInf][0];
204 const double lSup0 = mat->t [lSup][0];
205 double s0 = interpolate (twa, lInf0, lSup0, mat->t [lInf][cInf], mat->t [lSup][cInf]);
206 double s1 = interpolate (twa, lInf0, lSup0, mat->t [lInf][cSup], mat->t [lSup][cSup]);
207 return interpolate (w, mat->t [0][cInf], mat->t [0][cSup], s0, s1);
208}
209
211static inline int binarySearchTwa (const PolMat *mat, double val) {
212 const int nLine = mat->nLine;
213 int low = 1;
214 int high = nLine; // sentinel: just after last line
215
216 while (low < high) {
217 int mid = low + (high - low) / 2;
218 double midVal = mat->t[mid][0]; // colonne 0
219 if (midVal > val) high = mid;
220 else low = mid + 1;
221 }
222 return low;
223}
224
226static inline int binarySearchW (const double *row0, int nCol, double val) {
227 int low = 1;
228 int high = nCol; // sentinel: just after last col
229
230 while (low < high) {
231 int mid = low + (high - low) / 2;
232 double midVal = row0[mid];
233 if (midVal > val) high = mid;
234 else low = mid + 1;
235 }
236 return low; // in [1..nCol]
237}
238
240/* Version = findPolar, with W dichotomic search */
241static inline double findPolar1 (double twa, double w, const PolMat *mat, const PolMat *sailMat, int *sail) {
242 const int nLine = mat->nLine; // local copy for perf
243 const int nCol = mat->nCol;
244 int l, c, lInf, cInf, lSup, cSup;
245 int bestL, bestC; // for sail
246
247 if (twa > 180.0) twa = 360.0 - twa;
248 else if (twa < 0.0) twa = -twa;
249
250 for (l = 1; l < nLine; l++) {
251 if (mat->t [l][0] > twa) break;
252 }
253 lSup = (l < nLine - 1) ? l : nLine - 1;
254 lInf = (l == 1) ? 1 : l - 1;
255
256 c = binarySearchW (&mat->t [0][0], nCol, w);
257 cSup = (c < nCol - 1) ? c : nCol - 1;
258 cInf = (c == 1) ? 1 : c - 1;
259
260 // sail
261 if (sailMat != NULL && sailMat->nLine == nLine && sailMat->nCol == nCol) { // sail requested
262 bestL = ((twa - mat->t [lInf][0]) < (mat->t [lSup][0] - twa)) ? lInf : lSup; // for sail line
263 bestC = ((w - mat->t [0][cInf]) < (mat->t [0][cSup] - w)) ? cInf : cSup; // for sail col
264 *sail = sailMat->t [bestL][bestC]; // sail found
265 }
266 else *sail = 0;
267
268 const double lInf0 = mat->t [lInf][0];
269 const double lSup0 = mat->t [lSup][0];
270 double s0 = interpolate (twa, lInf0, lSup0, mat->t [lInf][cInf], mat->t [lSup][cInf]);
271 double s1 = interpolate (twa, lInf0, lSup0, mat->t [lInf][cSup], mat->t [lSup][cSup]);
272 return interpolate (w, mat->t [0][cInf], mat->t [0][cSup], s0, s1);
273}
274
276/* Version = findPolar, with both W and TWA dichotomic search */
277static inline double findPolar2 (double twa, double w, const PolMat *mat, const PolMat *sailMat, int *sail) {
278 const int nLine = mat->nLine; // local copy for perf
279 const int nCol = mat->nCol;
280 int l, c, lInf, cInf, lSup, cSup;
281 int bestL, bestC; // for sail
282
283 if (twa > 180.0) twa = 360.0 - twa;
284 else if (twa < 0.0) twa = -twa;
285
286 l = binarySearchTwa(mat, twa); // retourne [1 .. nLine]
287 lSup = (l < nLine - 1) ? l : (nLine - 1);
288 lInf = (l == 1) ? 1 : (l - 1);
289
290 c = binarySearchW(&mat->t[0][0], nCol, w);
291 cSup = (c < nCol - 1) ? c : nCol - 1;
292 cInf = (c == 1) ? 1 : c - 1;
293
294 if (sailMat != NULL && sailMat->nLine == nLine && sailMat->nCol == nCol) { // sail requested
295 bestL = ((twa - mat->t[lInf][0]) < (mat->t[lSup][0] - twa)) ? lInf : lSup; // for sail line
296 bestC = ((w - mat->t[0][cInf]) < (mat->t[0][cSup] - w)) ? cInf : cSup; // for sail col
297 *sail = sailMat->t[bestL][bestC]; // sail found
298 } else *sail = 0;
299
300 double lInf0 = mat->t[lInf][0];
301 double lSup0 = mat->t[lSup][0];
302 double s0 = interpolate (twa, lInf0, lSup0, mat->t [lInf][cInf], mat->t [lSup][cInf]);
303 double s1 = interpolate (twa, lInf0, lSup0, mat->t [lInf][cSup], mat->t [lSup][cSup]);
304 return interpolate (w, mat->t [0][cInf], mat->t [0][cSup], s0, s1);
305}
306
308static inline double maxSpeedInPolarAt (double tws, const PolMat *mat) {
309 double max = 0.0;
310 double s0, s1, speed;
311 const int nCol = mat->nCol;
312 const int nLine = mat->nLine; // local storage
313 const int c = binarySearchW (&mat->t [0][0], nCol, tws);
314 const int cSup = (c < nCol - 1) ? c : nCol - 1;
315 const int cInf = (c == 1) ? 1 : c - 1;
316
317 for (int l = 1; l < nLine; l++) { // for every lines
318 s0 = mat->t[l][cInf];
319 s1 = mat->t[l][cSup];
320 speed = s0 + (tws - mat->t [0][cInf]) * (s1 - s0) / (mat->t [0][cSup] - mat->t [0][cInf]);
321 if (speed > max) max = speed;
322 }
323 return max;
324}
325
343static inline void orthoFindInterPoint(double lat1, double lon1,
344 double lat2, double lon2,
345 double d_nm,
346 double *latR, double *lonR) {
347 if (!latR || !lonR) return;
348
349 /* Total orthodromic distance P1 -> P2 (nautical miles) */
350 double total_nm = orthoDist(lat1, lon1, lat2, lon2);
351
352 /* Degenerate or almost zero distance: return origin */
353 if (total_nm <= 1e-9) {
354 *latR = lat1;
355 *lonR = lon1;
356 return;
357 }
358
359 /* Clamp requested distance into [0, total_nm] */
360 if (d_nm <= 0.0) {
361 *latR = lat1;
362 *lonR = lon1;
363 return;
364 }
365 if (d_nm >= total_nm) {
366 *latR = lat2;
367 *lonR = lon2;
368 return;
369 }
370
371 /* Fraction of the great-circle path */
372 double f = d_nm / total_nm;
373
374 /* Convert endpoints to radians */
375 double phi1 = lat1 * DEG_TO_RAD;
376 double lambda1 = lon1 * DEG_TO_RAD;
377 double phi2 = lat2 * DEG_TO_RAD;
378 double lambda2 = lon2 * DEG_TO_RAD;
379
380 /* Central angle delta between P1 and P2 (radians)
381 * orthoDist uses: dist_nm = delta * (180 / pi) * 60
382 * => delta = dist_nm / (60 * (180 / pi)) = dist_nm / (60 * RAD_TO_DEG)
383 */
384 double delta = total_nm / (60.0 * RAD_TO_DEG);
385 double sin_delta = sin(delta);
386
387 if (fabs(sin_delta) < 1e-15) {
388 /* Numerically unstable (almost no separation) */
389 *latR = lat1;
390 *lonR = lon1;
391 return;
392 }
393
394 /* Spherical linear interpolation on great-circle */
395 double A = sin((1.0 - f) * delta) / sin_delta;
396 double B = sin(f * delta) / sin_delta;
397
398 double cos_phi1 = cos(phi1);
399 double cos_phi2 = cos(phi2);
400
401 double x = A * cos_phi1 * cos(lambda1) + B * cos_phi2 * cos(lambda2);
402 double y = A * cos_phi1 * sin(lambda1) + B * cos_phi2 * sin(lambda2);
403 double z = A * sin(phi1) + B * sin(phi2);
404
405 double phiR = atan2(z, sqrt(x * x + y * y));
406 double lambdaR = atan2(y, x);
407
408 *latR = phiR * RAD_TO_DEG;
409 *lonR = lonCanonize(lambdaR * RAD_TO_DEG);
410}
411
421static inline bool isDay(double t, long dataDate, long dataTime, double lat, double lon) {
422 lon = lonCanonize(lon);
423
424 // Polar case: only beginning og grib considered GRIB
425 int month = (int)((dataDate % 10000) / 100); // 1..12
426
427 if (lat > 75.0) return (month > 4 && month < 10); // 5..9 May to December: day
428 if (lat < -75.0) return !(month > 4 && month < 10);
429
430 // Start GRIB (UTC) – minutes allways 00
431 int hour0 = (int)(dataTime / 100); // ex: 1500 -> 15
432
433 // Theorical local geographic hour: UTC + t + lon/15
434 double localHours = hour0 + t + lon / 15.0;
435
436 // convert to [0, 24)
437 localHours = fmod(localHours, 24.0);
438 if (localHours < 0.0) localHours += 24.0;
439
440 // Say if local hour between 6:00 an 18:00
441 return (localHours >= 6.0) && (localHours <= 18.0);
442}
#define G_PI
Definition glibwrapper.h:4
#define CLAMP(x, lo, hi)
Definition glibwrapper.h:7
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 findPolar2(double twa, double w, const PolMat *mat, const PolMat *sailMat, int *sail)
find in polar boat speed or wave coeff and sail number if sailMat != NULL
Definition inline.h:277
static int binarySearchTwa(const PolMat *mat, double val)
dichotomic search on column 0 (TWA), using rows [1 .
Definition inline.h:211
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 double orthoDist2(double lat1, double lon1, double lat2, double lon2)
return orthodomic distance in nautical miles from origin to destinationi, Haversine formula time cons...
Definition inline.h:161
static double interpolate(double x, double x0, double x1, double fx0, double fx1)
return fx : linear interpolation
Definition inline.h:78
static int binarySearchW(const double *row0, int nCol, double val)
dichotomic search on row 0 (wind speed), using columns [1 .
Definition inline.h:226
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 fTwd(double u, double v)
true wind direction
Definition inline.h:52
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 double findPolar1(double twa, double w, const PolMat *mat, const PolMat *sailMat, int *sail)
find in polar boat speed or wave coeff and sail number if sailMat != NULL
Definition inline.h:241
static double fTws(double u, double v)
true wind speed.
Definition inline.h:58
static double lonNormalize(double lon, bool anteMeridian)
if antemeridian -180 < lon < 360.
Definition inline.h:40
static double givry(double lat1, double lon1, double lat2, double lon2)
return givry correction to apply to direct or loxodromic cap to get orthodromic cap
Definition inline.h:84
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
static double orthoCap2(double lat1, double lon1, double lat2, double lon2)
return initial orthodromic cap from origin to destination, no givry correction
Definition inline.h:108
static void orthoFindInterPoint(double lat1, double lon1, double lat2, double lon2, double d_nm, double *latR, double *lonR)
Compute the intermediate point on the great circle from P1 to P2.
Definition inline.h:343
#define DEG_TO_RAD
Definition r3types.h:28
#define MS_TO_KN
Definition r3types.h:23
#define RAD_TO_DEG
Definition r3types.h:27
#define EARTH_RADIUS
Definition r3types.h:26
Zone zone
geographic zone covered by grib file
Definition r3util.c:64
polar Matrix description
Definition r3types.h:201
double t[MAX_N_POL_MAT_LINES][MAX_N_POL_MAT_COLS]
Definition r3types.h:203
int nLine
Definition r3types.h:205
int nCol
Definition r3types.h:206
zone description
Definition r3types.h:140
double latMin
Definition r3types.h:149
double lonRight
Definition r3types.h:152
double latMax
Definition r3types.h:150
double lonLeft
Definition r3types.h:151