YAC 3.8.0
Yet Another Coupler
Loading...
Searching...
No Matches
intersection.c
Go to the documentation of this file.
1// Copyright (c) 2024 The YAC Authors
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5#include <stdlib.h>
6#include <math.h>
7#include <stdio.h>
8
9#include "utils_core.h"
10#include "geometry.h"
11
12// angle tolerance
13static double const tol = 1.0e-12;
14
15enum {
16 p_on_a = 1,
17 q_on_a = 2,
18 p_on_b = 4,
19 q_on_b = 8,
21};
22
23enum {
29};
30
39static int gcxgc(
40 double const norm_vector_a[3], double const norm_vector_b[3],
41 double p[3], double q[3]) {
42
43 // compute p and q
44 // p' = (a X b) X (c X d)
45 // p = p' / length(p')
46 // q = -p
47 double temp_p[3];
48 crossproduct_kahan(norm_vector_a, norm_vector_b, temp_p);
49
50 double sq_sin_plane_angle =
51 temp_p[0] * temp_p[0] + temp_p[1] * temp_p[1] + temp_p[2] * temp_p[2];
52
53 // if both circles are on the same plane
54 if (sq_sin_plane_angle <= yac_sq_angle_tol) return -1;
55
56 double scale = 1.0 / sqrt(sq_sin_plane_angle);
57 p[0] = (temp_p[0] * scale);
58 p[1] = (temp_p[1] * scale);
59 p[2] = (temp_p[2] * scale);
60 q[0] = -p[0], q[1] = -p[1], q[2] = -p[2];
61
62 return 2;
63}
64
65#if defined __INTEL_COMPILER
66#pragma intel optimization_level 0
67#elif defined _CRAYC
68#pragma _CRI noopt
69#endif
70
71static int loncxlatc(
72 double const gc_norm_vector[3], double const z,
73 double p[3], double q[3]) {
74
75 // based on gcxlatc with some optimisations for circles of longitude
76
77 // square of z of lat circle
78 double sq_z = z * z;
79
80 double b = sqrt(MAX(1.0 - sq_z,0.0));
81 double b_n0 = b * gc_norm_vector[0];
82 double b_n1 = b * gc_norm_vector[1];
83
84 p[0] = b_n1;
85 p[1] = -b_n0;
86 p[2] = z;
87 q[0] = -p[0];
88 q[1] = -p[1];
89 q[2] = z;
90
91 return 2;
92}
93
94static int gcxlatc(
95 double const gc_norm_vector[3], double const z,
96 double p[3], double q[3]) {
97
98/* How to compute intersection point(s) between great circle (given by its
99 * norm vector) and a circle of latitude (give by z coordinate):
100 *
101 * n = norm vector of great circle
102 * x = vector to intersection point(s)
103 * z = cos(lat) // where lat is the latitude of the circle of latitude
104 *
105 * I. n * x = 0 // intersection is orthogonal to the norm vector
106 * II. x * x = 1 // intersection vector has a length of 1
107 * III. x_2 = z // z-coordinate of intersection point is z
108 *
109 * from I we can derive:
110 * x_1=-(n_0*x_0+n_2*z)/n_1
111 *
112 * x_1 and x_2 in II:
113 * x_0^2+(n_0*x_0+n_2*z)^2/n_1^2+z^2=1
114 * x_0^2+(2*n_0*n_2*z)/(n_0^2+n_1^2)*x_0+
115 * (n_2^2*z^2+n_1^2*z^2-n_1^2)/(n_0^2+n_1^2)=0
116 *
117 * with M = n_0^2+n_1^2:
118 * x_0^2 + (2*n_0*n_2*z)/M*x_0 + (n_2^2*z^2+n_1^2*z^2-n_1^2)/M = 0
119 *
120 * x_0 = -(n_0*n_2*z)/M
121 * +- sqrt((n_0*n_2*z)^2/M^2 - (n_2^2*z^2+n_1^2*z^2-n_1^2)/M)
122 * = -(*n_2*z/M)*n_0 +- sqrt(M-z^2)/M*n_1
123 *
124 * with a = -n_2*z/M and b = sqrt(M-z^2)/M:
125 * x_0 = a * n_0 +- b * n_1
126 * x_1 = a * n_1 -+ b * n_0
127 */
128
129 // if the great circle is a circle of longitude
130 if (fabsl(gc_norm_vector[2]) < yac_angle_low_tol)
131 return loncxlatc(gc_norm_vector, z, p, q);
132
133 double sq_n[3] = {gc_norm_vector[0] * gc_norm_vector[0],
134 gc_norm_vector[1] * gc_norm_vector[1],
135 gc_norm_vector[2] * gc_norm_vector[2]};
136
137 // square of highest z-value of great circle
138 double max_sq_gc_z = sq_n[0] + sq_n[1];
139
140 // square of z of lat circle
141 double sq_z = z * z;
142
143 // if both circles are the equator -> identical circles
144 if ((max_sq_gc_z < yac_sq_angle_tol) && (sq_z < yac_sq_angle_tol)) return -1;
145
146 // determine number of intersections
147 int num_intersections =
148 ((max_sq_gc_z > (sq_z - tol)) - (max_sq_gc_z < (sq_z + tol))) + 1;
149
150 switch (num_intersections) {
151
152 // if no intersection is possible
153 case (0): break;
154
155 // the great circles touches the circle of latitude in a single point
156 // ==> (b = 0)
157 case (1): {
158
159 double a = -(gc_norm_vector[2] * z) / max_sq_gc_z;
160
161 p[0] = ((q[0] = gc_norm_vector[0] * a));
162 p[1] = ((q[1] = gc_norm_vector[1] * a));
163 p[2] = z, q[2] = z;
164 break;
165 }
166
167 default:
168 case (2): {
169
170 double a = -(gc_norm_vector[2] * z) / max_sq_gc_z;
171 double b = sqrt(max_sq_gc_z - sq_z)/max_sq_gc_z;
172 double a_n0 = a * gc_norm_vector[0];
173 double a_n1 = a * gc_norm_vector[1];
174 double b_n0 = b * gc_norm_vector[0];
175 double b_n1 = b * gc_norm_vector[1];
176
177 p[0] = a_n0 + b_n1;
178 p[1] = a_n1 - b_n0;
179 p[2] = z;
180 q[0] = a_n0 - b_n1;
181 q[1] = a_n1 + b_n0;
182 q[2] = z;
183 break;
184 }
185 }
186
187 return num_intersections;
188}
189
190#if defined _CRAYC
191#pragma _CRI opt
192#endif
193
194static int loncxlonc(
195 double const norm_vector_a[3], double const norm_vector_b[3],
196 double p[3], double q[3]) {
197
198 double sq_plane_diff =
199 MIN((norm_vector_a[0] - norm_vector_b[0]) *
200 (norm_vector_a[0] - norm_vector_b[0]) +
201 (norm_vector_a[1] - norm_vector_b[1]) *
202 (norm_vector_a[1] - norm_vector_b[1]),
203 (norm_vector_a[0] + norm_vector_b[0]) *
204 (norm_vector_a[0] + norm_vector_b[0]) +
205 (norm_vector_a[1] + norm_vector_b[1]) *
206 (norm_vector_a[1] + norm_vector_b[1]));
207
208 // if both circles are on the same circle of longitude
209 if (sq_plane_diff < yac_sq_angle_tol) return -1;
210
211 // the intersection points of the two circles of longitude are the poles
212 p[0] = 0, p[1] = 0; p[2] = 1;
213 q[0] = 0, q[1] = 0; q[2] = -1;
214
215 return 2;
216}
217
218static int pxgc(
219 double const vec[3], double const norm_vector[3], double p[3], double q[3]) {
220
221 // compute the angle between the point vector and the norm vector
222 // we use kahan summation to increase precision
223 double dot = vec[0] * norm_vector[0];
224 double err = fma(vec[0], norm_vector[0], -dot);
225 dot = fma(vec[1], norm_vector[1], dot);
226 err += fma(vec[1], norm_vector[1], -vec[1]*norm_vector[1]);
227 dot = fma(vec[2], norm_vector[2], dot);
228 err += fma(vec[2], norm_vector[2], -vec[2]*norm_vector[2]);
229 dot += err;
230
231 // if the point is not on the plane
232 if (fabsl(dot) > yac_angle_tol) return 0;
233
234 q[0] = -((p[0] = vec[0]));
235 q[1] = -((p[1] = vec[1]));
236 q[2] = -((p[2] = vec[2]));
237 return 1;
238}
239
240static int pxlatc(
241 double const vec[3], double z, double p[3], double q[3]) {
242
243 // if the point is not on the plane of the circle of latitude
244 if (fabs(vec[2] - z) > tol) return 0;
245
246 q[0] = -((p[0] = vec[0]));
247 q[1] = -((p[1] = vec[1]));
248 q[2] = ((p[2] = vec[2]));
249 return 1;
250}
251
252static int pxp(
253 double const vec_a[3], double const vec_b[3], double p[3], double q[3]) {
254
255 // if the points are identical
256 if (points_are_identically(vec_a, vec_b)) {
257 q[0] = -((p[0] = vec_a[0]));
258 q[1] = -((p[1] = vec_a[1]));
259 q[2] = -((p[2] = vec_a[2]));
260 return 1;
261 } else {
262 return 0;
263 }
264}
265
267 struct yac_circle a, struct yac_circle b, double p[3], double q[3]) {
268
270 ((a.type == GREAT_CIRCLE) ||
271 (a.type == LON_CIRCLE) ||
272 (a.type == LAT_CIRCLE) ||
273 (a.type == POINT)) &&
274 ((b.type == LON_CIRCLE) ||
275 (b.type == GREAT_CIRCLE) ||
276 (b.type == LAT_CIRCLE) ||
277 (b.type == POINT)),
278 "ERROR(yac_circle_intersect): unknown circle type.")
279
280 if (((a.type == GREAT_CIRCLE) && (b.type == GREAT_CIRCLE)) ||
281 ((a.type == GREAT_CIRCLE) && (b.type == LON_CIRCLE)) ||
282 ((a.type == LON_CIRCLE) && (b.type == GREAT_CIRCLE))) {
283 return gcxgc(a.data.gc.norm_vector, b.data.gc.norm_vector, p, q);
284 } else if (((a.type == GREAT_CIRCLE) && (b.type == LAT_CIRCLE))) {
285 return gcxlatc(a.data.gc.norm_vector, b.data.lat.z, p, q);
286 } else if (((a.type == LAT_CIRCLE) && (b.type == GREAT_CIRCLE))) {
287 return gcxlatc(b.data.gc.norm_vector, a.data.lat.z, p, q);
288 } else if ((a.type == LON_CIRCLE) && (b.type == LON_CIRCLE)) {
290 } else if ((a.type == LON_CIRCLE) && (b.type == LAT_CIRCLE)) {
291 return loncxlatc(a.data.lon.norm_vector, b.data.lat.z, p, q);
292 } else if ((a.type == LAT_CIRCLE) && (b.type == LON_CIRCLE)) {
293 return loncxlatc(b.data.lon.norm_vector, a.data.lat.z, p, q);
294 } else if ((a.type == POINT) && (b.type == GREAT_CIRCLE)) {
295 return pxgc(a.data.p.vec, b.data.gc.norm_vector, p, q);
296 } else if ((a.type == POINT) && (b.type == LON_CIRCLE)) {
297 return pxgc(a.data.p.vec, b.data.gc.norm_vector, p, q);
298 } else if ((a.type == POINT) && (b.type == LAT_CIRCLE)) {
299 return pxlatc(a.data.p.vec, b.data.lat.z, p, q);
300 } else if ((a.type == POINT) && (b.type == POINT)) {
301 return pxp(a.data.p.vec, b.data.p.vec, p, q);
302 } else if ((a.type == GREAT_CIRCLE) && (b.type == POINT)) {
303 return pxgc(b.data.p.vec, a.data.gc.norm_vector, p, q);
304 } else if ((a.type == LON_CIRCLE) && (b.type == POINT)) {
305 return pxgc(b.data.p.vec, a.data.gc.norm_vector, p, q);
306 } else /*if ((a.type == LAT_CIRCLE) && (b.type == POINT))*/ {
307 return pxlatc(b.data.p.vec, a.data.lat.z, p, q);
308 }
309}
310
315static inline int vector_is_between (
316 double const a[], double const b[], double const p[],
317 double sq_len_diff_ab) {
318
319 // In case the angle between the vectors a and b is 180 degree, the angle
320 // between the vectors pa and pb is exactly 90 degree (Pythagorean theorem).
321 // In all other cases the angle between pa and pb must be bigger than 90
322 // degree for p to be between a and b
323 // from this we can deduce:
324 // ||ab||^2 >= ||ap||^2 + ||bp||^2 => (Pythagorean theorem)
325
326 // the tol is required in case p is very close to a or b
327 double sq_len_diff_vec_ap = sq_len_diff_vec(a,p);
328 double sq_len_diff_vec_bp = sq_len_diff_vec(b,p);
329 return sq_len_diff_ab + tol >= sq_len_diff_vec_ap + sq_len_diff_vec_bp;
330}
331
333 double const a[], double const b[], double const p[]) {
334
335/* determines whether p is between a and b
336 (a, b, p have the same latitude)*/
337
338/* I. a_0 * alpha + b_0 * beta = p_0
339 II. a_1 * alpha + b_1 * beta = p_1
340
341 if alpha > 0 and beta > 0 -> p is between a and b */
342
343 if (fabs(fabs(a[2]) - 1.0) < tol) return 1;
344
345 double fabs_a[2] = {fabs(a[0]), fabs(a[1])};
346 int flag = fabs_a[0] > fabs_a[1];
347 double a_0 = a[flag], a_1 = a[flag^1];
348 double b_0 = b[flag], b_1 = b[flag^1];
349 double p_0 = p[flag], p_1 = p[flag^1];
350
351 double temp = b_0 - (b_1 * a_0) / a_1;
352
353 // if a and b are nearly identical
354 if (fabs(temp) < tol)
355 return (fabs(a_0 - p_0) < tol) && (fabs(a_1 - p_1) < tol);
356
357 double beta = (p_0 - (p_1 * a_0) / a_1) / temp;
358
359 if (beta < -tol) return 0;
360
361 double alpha = (p_1 - b_1 * beta) / a_1;
362
363 return alpha > -tol;
364}
365
367 enum yac_edge_type edge_type, double const a[3], double const b[3],
368 double middle[3]) {
369
371 (edge_type == YAC_GREAT_CIRCLE_EDGE) ||
372 (edge_type == YAC_LAT_CIRCLE_EDGE) ||
373 (edge_type == YAC_LON_CIRCLE_EDGE),
374 "ERROR(compute_edge_middle_point_vec): invalide edge_type")
375
376 if (edge_type == YAC_LAT_CIRCLE_EDGE) {
377 middle[0] = a[0]+b[0], middle[1] = a[1]+b[1], middle[2] = a[2];
378 double temp = middle[0]*middle[0] + middle[1]*middle[1];
379 double scale = sqrt((1.0 - middle[2] * middle[2])/temp);
380 middle[0] *= scale;
381 middle[1] *= scale;
382 } else {
383 middle[0] = a[0]+b[0], middle[1] = a[1]+b[1], middle[2] = a[2]+b[2];
384 normalise_vector(middle);
385 }
386}
387
389 enum yac_edge_type edge_type, double const a[3], double const b[3],
390 double const c[3], double const d[3], double p[3], double q[3],
391 int intersection_type) {
392
394 (intersection_type == no_intersection) ||
395 (intersection_type == a_between_cd + b_between_cd) ||
396 (intersection_type == a_between_cd + b_between_cd + c_between_ab) ||
397 (intersection_type == a_between_cd + b_between_cd + d_between_ab) ||
398 (intersection_type == a_between_cd + c_between_ab) ||
399 (intersection_type == a_between_cd + c_between_ab + d_between_ab) ||
400 (intersection_type == a_between_cd + d_between_ab) ||
401 (intersection_type == b_between_cd + c_between_ab) ||
402 (intersection_type == b_between_cd + c_between_ab + d_between_ab) ||
403 (intersection_type == b_between_cd + d_between_ab) ||
404 (intersection_type == c_between_ab + d_between_ab) ||
405 (intersection_type == a_between_cd + b_between_cd +
407 "internal error")
408
409 switch (intersection_type) {
410 default:
411
412 // edges do not intersect
413 case (no_intersection):
414 // use middle points of both edges as intersection points
415 compute_edge_middle_point_vec(edge_type, a, b, p);
416 compute_edge_middle_point_vec(edge_type, c, d, q);
418
419 // both vertices of first edge overlap with the second edge or
420 // edges are identical
422 case (a_between_cd + b_between_cd):
425 p[0] = a[0], p[1] = a[1], p[2] = a[2];
426 q[0] = b[0], q[1] = b[1], q[2] = b[2];
427 break;
428
429 // both edges of the second edge overlap with the first edge
430 case (c_between_ab + d_between_ab):
433 p[0] = c[0], p[1] = c[1], p[2] = c[2];
434 q[0] = d[0], q[1] = d[1], q[2] = d[2];
435 break;
436
437 // only one vertex of each edge overlaps with the other edge
438 case (a_between_cd + c_between_ab):
439 p[0] = a[0], p[1] = a[1], p[2] = a[2];
440 q[0] = c[0], q[1] = c[1], q[2] = c[2];
441 break;
442 case (a_between_cd + d_between_ab):
443 p[0] = a[0], p[1] = a[1], p[2] = a[2];
444 q[0] = d[0], q[1] = d[1], q[2] = d[2];
445 break;
446 case (b_between_cd + c_between_ab):
447 p[0] = b[0], p[1] = b[1], p[2] = b[2];
448 q[0] = c[0], q[1] = c[1], q[2] = c[2];
449 break;
450 case (b_between_cd + d_between_ab):
451 p[0] = b[0], p[1] = b[1], p[2] = b[2];
452 q[0] = d[0], q[1] = d[1], q[2] = d[2];
453 break;
454 }
456}
457
458// computes intersection of great circle edges that are on
459// the same great circle
461 double const a[3], double const b[3], double const c[3], double const d[3],
462 double p[3], double q[3]) {
463
464 double sq_len_diff_ab = sq_len_diff_vec(a, b);
465 double sq_len_diff_cd = sq_len_diff_vec(c, d);
466
467 return
469 YAC_GREAT_CIRCLE_EDGE, a, b, c, d, p, q,
470 (vector_is_between(c, d, a, sq_len_diff_cd) << 0) +
471 (vector_is_between(c, d, b, sq_len_diff_cd) << 1) +
472 (vector_is_between(a, b, c, sq_len_diff_ab) << 2) +
473 (vector_is_between(a, b, d, sq_len_diff_ab) << 3));
474}
475
476// determines the return value for the provided intersection points p and q
478 double const a[3], double const b[3], double const c[3], double const d[3],
479 double const p[3], double const q[3]) {
480
481 // square of the Euclidean distance between the vertices of the two edges
482 double sq_len_diff_ab = sq_len_diff_vec(a, b);
483 double sq_len_diff_cd = sq_len_diff_vec(c, d);
484
485 return (vector_is_between(a, b, p, sq_len_diff_ab) << 0) +
486 (vector_is_between(a, b, q, sq_len_diff_ab) << 1) +
487 (vector_is_between(c, d, p, sq_len_diff_cd) << 2) +
488 (vector_is_between(c, d, q, sq_len_diff_cd) << 3);
489}
490
492 double const a[3], double const b[3], double norm_vector[3]) {
493
494 norm_vector[0] = a[1] * b[2] - a[2] * b[1];
495 norm_vector[1] = a[2] * b[0] - a[0] * b[2];
496 norm_vector[2] = a[0] * b[1] - a[1] * b[0];
497
498 double scale = 1.0 / sqrt(norm_vector[0] * norm_vector[0] +
499 norm_vector[1] * norm_vector[1] +
500 norm_vector[2] * norm_vector[2]);
501 norm_vector[0] *= scale;
502 norm_vector[1] *= scale;
503 norm_vector[2] *= scale;
504}
505
524static int yac_gcxgc_vec(
525 double const a[3], double const b[3], double const c[3], double const d[3],
526 double p[3], double q[3]) {
527
528 double norm_vector_ab[3], norm_vector_cd[3];
529
530 compute_norm_vector(a, b, norm_vector_ab);
531 compute_norm_vector(c, d, norm_vector_cd);
532
533 switch (gcxgc(norm_vector_ab, norm_vector_cd, p, q)) {
534 default:
535 case(2):
536 return yac_check_pq_gcxgc(a, b, c, d, p, q);
537 case(-1):
538 return yac_identical_gcxgc_vec(a, b, c, d, p, q);
539 };
540}
541
557 double const a[3], double const b[3], double const c[3], double const d[3],
558 double p[3], double q[3]) {
559
560 // two circles of latitude can only intersect if they are on the same latitude
561 if (fabs(a[2] - c[2]) > tol) return -1;
562 else
563 return
565 YAC_LAT_CIRCLE_EDGE, a, b, c, d, p, q,
566 (vector_is_between_lat(c, d, a) << 0) +
567 (vector_is_between_lat(c, d, b) << 1) +
568 (vector_is_between_lat(a, b, c) << 2) +
569 (vector_is_between_lat(a, b, d) << 3));
570}
571
573 double const a[3], double const b[3], double norm_vector[3]) {
574
575 norm_vector[0] = a[1] * b[2] - a[2] * b[1];
576 norm_vector[1] = a[2] * b[0] - a[0] * b[2];
577 norm_vector[2] = 0.0;
578
579 double scale = 1.0 / sqrt(norm_vector[0] * norm_vector[0] +
580 norm_vector[1] * norm_vector[1]);
581 norm_vector[0] *= scale;
582 norm_vector[1] *= scale;
583}
584
600 double const a[3], double const b[3], double const c[3], double const d[3],
601 double p[3], double q[3]) {
602
603 double norm_vector_ab[3], norm_vector_cd[3];
604 compute_lon_norm_vector(a, b, norm_vector_ab);
605 compute_lon_norm_vector(c, d, norm_vector_cd);
606
607 switch(loncxlonc(norm_vector_ab, norm_vector_cd, p, q)) {
608
609 default:
610 case(2):
611 return yac_check_pq_gcxgc(a, b, c, d, p, q);
612 case(-1):
613 return yac_identical_gcxgc_vec(a, b, c, d, p, q);
614 };
615}
616
617// determines the return value for the provided intersection points p and q
619 double const a[3], double const b[3], double const c[3], double const d[3],
620 double const p[3], double const q[3]) {
621
622 // square of the Euclidean distance between the vertices of the two edges
623 double sq_len_diff_ab = sq_len_diff_vec(a, b);
624
625 return
626 (vector_is_between(a, b, p, sq_len_diff_ab) << 0) +
627 (vector_is_between(a, b, q, sq_len_diff_ab) << 1) +
628 (vector_is_between_lat(c, d, p) << 2) +
629 (vector_is_between_lat(c, d, q) << 3);
630}
631
647 double const a[3], double const b[3], double const c[3], double const d[3],
648 double p[3], double q[3]) {
649
650 double norm_vector_ab[3];
651 compute_lon_norm_vector(a, b, norm_vector_ab);
652
653 int num_intersections = loncxlatc(norm_vector_ab, c[2], p, q);
654 YAC_ASSERT(num_intersections == 2, "ERROR(yac_loncxlatc_vec): internal error")
655
656 return yac_check_pq_gcxlatc(a, b, c, d, p, q);
657}
658
679#if defined __INTEL_COMPILER
680#pragma intel optimization_level 0
681#elif defined _CRAYC
682#pragma _CRI noopt
683#endif
684
686 double const a[3], double const b[3], double const c[3], double const d[3],
687 double p[3], double q[3]) {
688
689 double norm_vector_ab[3];
690 compute_norm_vector(a, b, norm_vector_ab);
691
692 int num_intersections = gcxlatc(norm_vector_ab, c[2], p, q);
693
694 switch (num_intersections) {
695 default:
696 case(2):
697 case(1):
698 return yac_check_pq_gcxlatc(a, b, c, d, p, q);
699 case(0):
700 return -1;
701 case(-1):
702 return yac_latcxlatc_vec(a, b, c, d, p, q);
703 }
704}
705
706#if defined _CRAYC
707#pragma _CRI opt
708#endif
709
710static int yac_pxp_vec(
711 double const a[3], double const b[3], double p[3], double q[3]) {
712
713 return (pxp(a, b, p, q))?(p_on_a + p_on_b):-1;
714}
715
716static int yac_pxgc_vec(
717 double const point[3], double const a[3], double const b[3],
718 double p[3], double q[3]) {
719
720 // compute norm vector for the plane of ab
721 double norm_ab[3];
722 compute_norm_vector(a, b, norm_ab);
723
724 // if the point is on the plane of ab
725 if (pxgc(point, norm_ab, p, q)) {
726
727 int ret_value = p_on_a;
728 double sq_len_diff_ab = sq_len_diff_vec(a, b);
729
730 if (vector_is_between(a, b, p, sq_len_diff_ab)) ret_value |= p_on_b;
731 else if (vector_is_between(a, b, q, sq_len_diff_ab)) ret_value |= q_on_b;
732
733 return ret_value;
734
735 } else {
736 return -1;
737 }
738}
739
740static int yac_pxlat_vec(
741 double const point[3], double const a[3], double const b[3],
742 double p[3], double q[3]) {
743
744 if (pxlatc(point, a[2], p, q)) {
745
746 int ret_value = p_on_a;
747
748 if (vector_is_between_lat(a, b, p)) ret_value |= p_on_b;
749 else if (vector_is_between_lat(a, b, q)) ret_value |= q_on_b;
750
751 return ret_value;
752 } else {
753 return -1;
754 }
755}
756
757static inline int adjust_ret_value(int ret_value) {
758 return (ret_value & (~(1 + 2 + 4 + 8))) +
759 ((ret_value & (1 + 2)) << 2) +
760 ((ret_value & (4 + 8)) >> 2);
761}
762
764 enum yac_edge_type edge_type_a, double const a[3], double const b[3],
765 enum yac_edge_type edge_type_b, double const c[3], double const d[3],
766 double p[3], double q[3]) {
767
769 ((edge_type_a == YAC_LON_CIRCLE_EDGE) ||
770 (edge_type_a == YAC_LAT_CIRCLE_EDGE) ||
771 (edge_type_a == YAC_GREAT_CIRCLE_EDGE)) &&
772 ((edge_type_b == YAC_LON_CIRCLE_EDGE) ||
773 (edge_type_b == YAC_LAT_CIRCLE_EDGE) ||
774 (edge_type_b == YAC_GREAT_CIRCLE_EDGE)), "ERROR: unknown edge type.")
775
776 int edge_a_is_point = points_are_identically(a, b);
777 int edge_b_is_point = points_are_identically(c, d);
778
779 // if both edges are points
780 if (edge_a_is_point && edge_b_is_point) {
781
782 return yac_pxp_vec(a, c, p, q);
783
784 // if one edge is a point
785 } else if (edge_a_is_point || edge_b_is_point) {
786
787 enum yac_edge_type edge_type[2] = {edge_type_a, edge_type_b};
788 double const * edge[2][2] = {{a,b}, {c,d}};
789 double const * point[2] = {c,a};
790
791 int ret_value;
792 switch (edge_type[edge_a_is_point]) {
793 case (YAC_LAT_CIRCLE_EDGE):
794 ret_value =
796 point[edge_a_is_point],
797 edge[edge_a_is_point][0], edge[edge_a_is_point][1], p, q);
798 break;
799 default:
800 case (YAC_LON_CIRCLE_EDGE):
802 ret_value =
804 point[edge_a_is_point],
805 edge[edge_a_is_point][0], edge[edge_a_is_point][1], p, q);
806 break;
807 }
808
809 if (edge_a_is_point) return ret_value;
810 else return adjust_ret_value(ret_value);
811
812 // if both edges are on circles of latitude
813 } else if (edge_type_a == YAC_LAT_CIRCLE_EDGE &&
814 edge_type_b == YAC_LAT_CIRCLE_EDGE) {
815
816 return yac_latcxlatc_vec(a, b, c, d, p, q);
817
818 // if both edges are on circle of longitude
819 } else if (edge_type_a == YAC_LON_CIRCLE_EDGE &&
820 edge_type_b == YAC_LON_CIRCLE_EDGE) {
821
822 return yac_loncxlonc_vec(a, b, c, d, p, q);
823
824 // if both edges are on great circles
825 } else if ((edge_type_a == YAC_GREAT_CIRCLE_EDGE &&
826 edge_type_b == YAC_GREAT_CIRCLE_EDGE) ||
827 (edge_type_a == YAC_LON_CIRCLE_EDGE &&
828 edge_type_b == YAC_GREAT_CIRCLE_EDGE) ||
829 (edge_type_a == YAC_GREAT_CIRCLE_EDGE &&
830 edge_type_b == YAC_LON_CIRCLE_EDGE)) {
831
832 return yac_gcxgc_vec(a, b, c, d, p, q);
833
834 // if one edge a is on a great circle and edge b on a circle of latitude
835 } else if (edge_type_a == YAC_GREAT_CIRCLE_EDGE &&
836 edge_type_b == YAC_LAT_CIRCLE_EDGE) {
837
838 return yac_gcxlatc_vec(a, b, c, d, p, q);
839
840 // if one edge a is on a circle of latitude and edge b on a great circle
841 } else if (edge_type_a == YAC_LAT_CIRCLE_EDGE &&
842 edge_type_b == YAC_GREAT_CIRCLE_EDGE ) {
843
844 return adjust_ret_value(yac_gcxlatc_vec(c, d, a, b, p, q));
845
846 // if one edge a is on a circle of longitude and edge b on a circle of latitude
847 } else if (edge_type_a == YAC_LON_CIRCLE_EDGE &&
848 edge_type_b == YAC_LAT_CIRCLE_EDGE) {
849
850 return yac_loncxlatc_vec(a, b, c, d, p, q);
851
852 // if one edge a is on a circle of latitude and edge b on a circle of longitude
853 } else /* if (edge_type_a == YAC_LAT_CIRCLE_EDGE &&
854 edge_type_b == YAC_LON_CIRCLE_EDGE )*/ {
855
856 return adjust_ret_value(yac_loncxlatc_vec(c, d, a, b, p, q));
857 }
858}
859
861 double p[3], double const a[3], double const b[3],
862 enum yac_circle_type circle_type) {
863
865 (circle_type == LON_CIRCLE) ||
866 (circle_type == LAT_CIRCLE) ||
867 (circle_type == GREAT_CIRCLE) ||
868 (circle_type == POINT),
869 "ERROR(yac_point_on_edge): unknown edge type.")
870
872 (circle_type != LAT_CIRCLE) || (fabs(a[2] - b[2]) < tol),
873 "ERROR(yac_point_on_edge): "
874 "LAT_CIRCLE but edge vertices do not have the same latitude");
875
876 switch (circle_type) {
877 default:
878 case (GREAT_CIRCLE):
879 case (LON_CIRCLE):
880 return vector_is_between(a, b, p, sq_len_diff_vec(a, b));
881 case (LAT_CIRCLE):
882 if (fabs(p[2] - a[2]) < tol) return vector_is_between_lat(a, b, p);
883 return 0;
884 case(POINT):
885 return points_are_identically(p, a);
886 }
887}
#define YAC_ASSERT(exp, msg)
static int points_are_identically(double const *a, double const *b)
Definition geometry.h:609
static double sq_len_diff_vec(double const a[3], double const b[3])
computes square of the lenght of the vector ab
Definition geometry.h:180
static void crossproduct_kahan(double const a[], double const b[], double cross[])
Definition geometry.h:297
#define yac_sq_angle_tol
Definition geometry.h:27
#define yac_angle_low_tol
Definition geometry.h:29
#define yac_angle_tol
Definition geometry.h:26
static void normalise_vector(double v[])
Definition geometry.h:650
yac_circle_type
Definition geometry.h:59
@ POINT
Definition geometry.h:63
@ LAT_CIRCLE
Definition geometry.h:61
@ GREAT_CIRCLE
Definition geometry.h:60
@ LON_CIRCLE
Definition geometry.h:62
yac_edge_type
Definition grid_cell.h:12
@ YAC_GREAT_CIRCLE_EDGE
great circle
Definition grid_cell.h:13
@ YAC_LAT_CIRCLE_EDGE
latitude circle
Definition grid_cell.h:14
@ YAC_LON_CIRCLE_EDGE
longitude circle
Definition grid_cell.h:15
static int yac_pxlat_vec(double const point[3], double const a[3], double const b[3], double p[3], double q[3])
static int yac_check_pq_gcxlatc(double const a[3], double const b[3], double const c[3], double const d[3], double const p[3], double const q[3])
static int yac_latcxlatc_vec(double const a[3], double const b[3], double const c[3], double const d[3], double p[3], double q[3])
compute the intersection point two circles of latitude
static int gcxgc(double const norm_vector_a[3], double const norm_vector_b[3], double p[3], double q[3])
int yac_circle_intersect(struct yac_circle a, struct yac_circle b, double p[3], double q[3])
static int yac_identical_gcxgc_vec(double const a[3], double const b[3], double const c[3], double const d[3], double p[3], double q[3])
static int vector_is_between(double const a[], double const b[], double const p[], double sq_len_diff_ab)
static int yac_pxgc_vec(double const point[3], double const a[3], double const b[3], double p[3], double q[3])
static void compute_edge_middle_point_vec(enum yac_edge_type edge_type, double const a[3], double const b[3], double middle[3])
static int gcxlatc(double const gc_norm_vector[3], double const z, double p[3], double q[3])
static int vector_is_between_lat(double const a[], double const b[], double const p[])
static int yac_check_pq_gcxgc(double const a[3], double const b[3], double const c[3], double const d[3], double const p[3], double const q[3])
static int pxgc(double const vec[3], double const norm_vector[3], double p[3], double q[3])
static int adjust_ret_value(int ret_value)
static void compute_norm_vector(double const a[3], double const b[3], double norm_vector[3])
static int yac_gcxgc_vec(double const a[3], double const b[3], double const c[3], double const d[3], double p[3], double q[3])
static int loncxlonc(double const norm_vector_a[3], double const norm_vector_b[3], double p[3], double q[3])
static int yac_loncxlatc_vec(double const a[3], double const b[3], double const c[3], double const d[3], double p[3], double q[3])
compute the intersection point of a meridian and a parallel
int yac_intersect_vec(enum yac_edge_type edge_type_a, double const a[3], double const b[3], enum yac_edge_type edge_type_b, double const c[3], double const d[3], double p[3], double q[3])
int yac_point_on_edge(double p[3], double const a[3], double const b[3], enum yac_circle_type circle_type)
static int pxlatc(double const vec[3], double z, double p[3], double q[3])
static int yac_gcxlatc_vec(double const a[3], double const b[3], double const c[3], double const d[3], double p[3], double q[3])
compute the intersection of a great circle with the parallel
static int yac_pxp_vec(double const a[3], double const b[3], double p[3], double q[3])
static int yac_loncxlonc_vec(double const a[3], double const b[3], double const c[3], double const d[3], double p[3], double q[3])
compute the intersection point two circles of longitude
static double const tol
static int yac_identical_circles_vec(enum yac_edge_type edge_type, double const a[3], double const b[3], double const c[3], double const d[3], double p[3], double q[3], int intersection_type)
static void compute_lon_norm_vector(double const a[3], double const b[3], double norm_vector[3])
static int loncxlatc(double const gc_norm_vector[3], double const z, double p[3], double q[3])
@ p_on_a
@ q_on_b
@ q_on_a
@ circles_are_identical
@ p_on_b
static int pxp(double const vec_a[3], double const vec_b[3], double p[3], double q[3])
@ c_between_ab
@ a_between_cd
@ no_intersection
@ d_between_ab
@ b_between_cd
double z
Definition geometry.h:77
struct yac_circle::@9::@12 p
enum yac_circle_type type
Definition geometry.h:69
struct yac_circle::@9::@10 gc
struct yac_circle::@9::@11 lat
union yac_circle::@9 data
double norm_vector[3]
Definition geometry.h:73
struct yac_circle::@9::@10 lon
double vec[3]
Definition geometry.h:80
#define MIN(a, b)
Definition toy_common.h:29
double(* p)(double lon, double lat)
Definition toy_scrip.c:119
#define MAX(a, b)