YAC 3.21.0
Yet Another Coupler
Loading...
Searching...
No Matches
test_circle.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 <stdio.h>
7#include <math.h>
8
9#include "clipping.h"
10#include "geometry.h"
11#include "test_common.h"
12#include "tests.h"
13
20static void utest_check_compare_circles(
21 struct yac_circle * circle_a, int a_is_lat,
22 struct yac_circle * circle_b, int b_is_lat,
23 int are_identical);
24
25int main (void) {
26
27 struct point_2d {double lon, lat;};
28
29 { // test yac_circle_compare and yac_circle_contains_north_pole
30 struct {
31 struct point_2d a, b;
32 enum yac_edge_type edge_type;
33 int edge_ordering;
34 int circle_idx;
35 int contains_north_pole;
36 } test_data[] =
37 {{.a = {.lon = 45.0, .lat = 0.0}, // equator clockwise
38 .b = {.lon = -45.0, .lat = 0.0},
39 .edge_type = YAC_GREAT_CIRCLE_EDGE,
40 .edge_ordering = -1,
41 .circle_idx = 0,
42 .contains_north_pole = 1},
43 {.a = {.lon = -45.0, .lat = 0.0}, // equator clockwise
44 .b = {.lon = 45.0, .lat = 0.0},
45 .edge_type = YAC_GREAT_CIRCLE_EDGE,
46 .edge_ordering = 1,
47 .circle_idx = 0,
48 .contains_north_pole = 1},
49 {.a = {.lon = 45.0, .lat = 0.0}, // equator counter clockwise
50 .b = {.lon = -45.0, .lat = 0.0},
51 .edge_type = YAC_GREAT_CIRCLE_EDGE,
52 .edge_ordering = 1,
53 .circle_idx = 1,
54 .contains_north_pole = 0},
55 {.a = {.lon = -45.0, .lat = 0.0}, // equator counter clockwise
56 .b = {.lon = 45.0, .lat = 0.0},
57 .edge_type = YAC_GREAT_CIRCLE_EDGE,
58 .edge_ordering = -1,
59 .circle_idx = 1,
60 .contains_north_pole = 0},
61 {.a = {.lon = 0.0, .lat = 88.0}, // Prime meridian
62 .b = {.lon = 180.0, .lat = 88.0},
63 .edge_type = YAC_GREAT_CIRCLE_EDGE,
64 .edge_ordering = 1,
65 .circle_idx = 2,
66 .contains_north_pole = 0},
67 {.a = {.lon = 180.0, .lat = 88.0}, // Prime meridian
68 .b = {.lon = 0.0, .lat = 88.0},
69 .edge_type = YAC_GREAT_CIRCLE_EDGE,
70 .edge_ordering = -1,
71 .circle_idx = 2,
72 .contains_north_pole = 0},
73 {.a = {.lon = 0.0, .lat = -1.0}, // Prime meridian (other direction)
74 .b = {.lon = 0.0, .lat = 1.0},
75 .edge_type = YAC_GREAT_CIRCLE_EDGE,
76 .edge_ordering = -1,
77 .circle_idx = 3,
78 .contains_north_pole = 0},
79 {.a = {.lon = 10.0, .lat = 10.0}, // lon circle
80 .b = {.lon = 10.0, .lat = 20.0},
81 .edge_type = YAC_LON_CIRCLE_EDGE,
82 .edge_ordering = -1,
83 .circle_idx = 4,
84 .contains_north_pole = 0},
85 {.a = {.lon = 10.0, .lat = 10.0}, // lon circle
86 .b = {.lon = 10.0, .lat = 20.0},
87 .edge_type = YAC_LON_CIRCLE_EDGE,
88 .edge_ordering = 1,
89 .circle_idx = 5,
90 .contains_north_pole = 0},
91 {.a = {.lon = 45.0, .lat = 89.0}, // lon circle
92 .b = {.lon = 45.0+180.0, .lat = 85.0},
93 .edge_type = YAC_LON_CIRCLE_EDGE,
94 .edge_ordering = 1,
95 .circle_idx = 6,
96 .contains_north_pole = 0},
97 {.a = {.lon = 45.0, .lat = 89.0}, // lon circle
98 .b = {.lon = 45.0+180.0, .lat = 85.0},
99 .edge_type = YAC_LON_CIRCLE_EDGE,
100 .edge_ordering = -1,
101 .circle_idx = 7,
102 .contains_north_pole = 0},
103 {.a = {.lon = 10.0, .lat = 70.0}, // lat circle
104 .b = {.lon = 20.0, .lat = 70.0},
105 .edge_type = YAC_LAT_CIRCLE_EDGE,
106 .edge_ordering = 1,
107 .circle_idx = 8,
108 .contains_north_pole = 1},
109 {.a = {.lon = 10.0, .lat = 70.0}, // lat circle
110 .b = {.lon = 20.0, .lat = 70.0},
111 .edge_type = YAC_LAT_CIRCLE_EDGE,
112 .edge_ordering = -1,
113 .circle_idx = 9,
114 .contains_north_pole = 0},
115 {.a = {.lon = -5.0, .lat = 15.0}, // lat circle
116 .b = {.lon = 5.0, .lat = 15.0},
117 .edge_type = YAC_LAT_CIRCLE_EDGE,
118 .edge_ordering = 1,
119 .circle_idx = 10,
120 .contains_north_pole = 1}};
121 enum {NUM_TESTS = sizeof(test_data) / sizeof(test_data[0])};
122
123 struct yac_circle test_circles[NUM_TESTS];
124
125 for (size_t i = 0; i < NUM_TESTS; ++i) {
126 double a[3], b[3];
127 LLtoXYZ_deg(test_data[i].a.lon, test_data[i].a.lat, a);
128 LLtoXYZ_deg(test_data[i].b.lon, test_data[i].b.lat, b);
130 a, b, test_data[i].edge_type, test_data[i].edge_ordering,
131 &test_circles[i]);
132 }
133 for (size_t i = 0; i < NUM_TESTS; ++i) {
134 if (yac_circle_contains_north_pole(&test_circles[i]) !=
135 test_data[i].contains_north_pole)
136 PUT_ERR("error in yac_circle_contains_north_pole");
137 for (size_t j = 0; j < NUM_TESTS; ++j) {
138 utest_check_compare_circles(
139 &test_circles[i], test_data[i].edge_type == YAC_LAT_CIRCLE_EDGE,
140 &test_circles[j], test_data[j].edge_type == YAC_LAT_CIRCLE_EDGE,
141 test_data[i].circle_idx == test_data[j].circle_idx);
142 }
143 }
144 }
145
146 { // test yac_circle_point_is_inside
147 struct {
148 struct point_2d a, b, point;
149 enum yac_edge_type edge_type;
150 int edge_ordering;
151 int is_inside;
152 } test_data[] =
153 {{.a = {.lon = -45.0, .lat = 0.0},
154 .b = {.lon = 45.0, .lat = 0.0},
155 .point = {.lon = 0.0, .lat = 90.0},
156 .edge_type = YAC_GREAT_CIRCLE_EDGE,
157 .edge_ordering = 1,
158 .is_inside = 1},
159 {.a = {.lon = -45.0, .lat = 0.0},
160 .b = {.lon = 45.0, .lat = 0.0},
161 .point = {.lon = 0.0, .lat = 90.0},
162 .edge_type = YAC_GREAT_CIRCLE_EDGE,
163 .edge_ordering = -1,
164 .is_inside = 0},
165 {.a = {.lon = -45.0, .lat = 0.0},
166 .b = {.lon = 45.0, .lat = 0.0},
167 .point = {.lon = 0.0, .lat = 0.0},
168 .edge_type = YAC_GREAT_CIRCLE_EDGE,
169 .edge_ordering = 1,
170 .is_inside = 2},
171 {.a = {.lon = -45.0, .lat = 0.0},
172 .b = {.lon = 45.0, .lat = 0.0},
173 .point = {.lon = 1.0, .lat = 1.0},
174 .edge_type = YAC_GREAT_CIRCLE_EDGE,
175 .edge_ordering = 1,
176 .is_inside = 1},
177 {.a = {.lon = 15.0, .lat = 25.0},
178 .b = {.lon = 15.0, .lat = 30.0},
179 .point = {.lon = 10.0, .lat = 10.0},
180 .edge_type = YAC_LON_CIRCLE_EDGE,
181 .edge_ordering = 1,
182 .is_inside = 1},
183 {.a = {.lon = 15.0, .lat = 25.0},
184 .b = {.lon = 15.0, .lat = 30.0},
185 .point = {.lon = 10.0, .lat = 10.0},
186 .edge_type = YAC_LON_CIRCLE_EDGE,
187 .edge_ordering = -1,
188 .is_inside = 0},
189 {.a = {.lon = 15.0, .lat = 25.0},
190 .b = {.lon = 15.0, .lat = 30.0},
191 .point = {.lon = 10.0, .lat = 90.0},
192 .edge_type = YAC_LON_CIRCLE_EDGE,
193 .edge_ordering = -1,
194 .is_inside = 2},
195 {.a = {.lon = 15.0, .lat = 25.0},
196 .b = {.lon = 15.0, .lat = 30.0},
197 .point = {.lon = 15.0, .lat = 60.0},
198 .edge_type = YAC_LON_CIRCLE_EDGE,
199 .edge_ordering = -1,
200 .is_inside = 2},
201 {.a = {.lon = 75.0, .lat = 75.0},
202 .b = {.lon = 80.0, .lat = 75.0},
203 .point = {.lon = 15.0, .lat = 80.0},
204 .edge_type = YAC_LAT_CIRCLE_EDGE,
205 .edge_ordering = 1,
206 .is_inside = 1},
207 {.a = {.lon = 75.0, .lat = 75.0},
208 .b = {.lon = 80.0, .lat = 75.0},
209 .point = {.lon = 15.0, .lat = 90.0},
210 .edge_type = YAC_LAT_CIRCLE_EDGE,
211 .edge_ordering = 1,
212 .is_inside = 1},
213 {.a = {.lon = 75.0, .lat = 75.0},
214 .b = {.lon = 80.0, .lat = 75.0},
215 .point = {.lon = 15.0, .lat = 80.0},
216 .edge_type = YAC_LAT_CIRCLE_EDGE,
217 .edge_ordering = -1,
218 .is_inside = 0},
219 {.a = {.lon = 75.0, .lat = 75.0},
220 .b = {.lon = 80.0, .lat = 75.0},
221 .point = {.lon = 15.0, .lat = 90.0},
222 .edge_type = YAC_LAT_CIRCLE_EDGE,
223 .edge_ordering = -1,
224 .is_inside = 0},
225 {.a = {.lon = 75.0, .lat = 75.0},
226 .b = {.lon = 80.0, .lat = 75.0},
227 .point = {.lon = 15.0, .lat = 75.0},
228 .edge_type = YAC_LAT_CIRCLE_EDGE,
229 .edge_ordering = 1,
230 .is_inside = 2},
231 // a circle of latitude very close to a pole and a point on that pole;
232 // the two are 1.0e-6rad apart, which is far outside of the tolerance,
233 // even though their z coordinates only differ by about 5.0e-13
234 {.a = {.lon = 75.0, .lat = 90.0 - 1.0e-6 / YAC_RAD},
235 .b = {.lon = 80.0, .lat = 90.0 - 1.0e-6 / YAC_RAD},
236 .point = {.lon = 15.0, .lat = 90.0},
237 .edge_type = YAC_LAT_CIRCLE_EDGE,
238 .edge_ordering = 1,
239 .is_inside = 1},
240 {.a = {.lon = 75.0, .lat = 90.0 - 1.0e-6 / YAC_RAD},
241 .b = {.lon = 80.0, .lat = 90.0 - 1.0e-6 / YAC_RAD},
242 .point = {.lon = 15.0, .lat = 90.0},
243 .edge_type = YAC_LAT_CIRCLE_EDGE,
244 .edge_ordering = -1,
245 .is_inside = 0},
246 // the same circle of latitude, but with a point on it
247 {.a = {.lon = 75.0, .lat = 90.0 - 1.0e-6 / YAC_RAD},
248 .b = {.lon = 80.0, .lat = 90.0 - 1.0e-6 / YAC_RAD},
249 .point = {.lon = 15.0, .lat = 90.0 - 1.0e-6 / YAC_RAD},
250 .edge_type = YAC_LAT_CIRCLE_EDGE,
251 .edge_ordering = 1,
252 .is_inside = 2},
253 // a point that is within the tolerance of a circle of latitude
254 {.a = {.lon = 75.0, .lat = 75.0},
255 .b = {.lon = 80.0, .lat = 75.0},
256 .point = {.lon = 15.0, .lat = 75.0 + 1.0e-13 / YAC_RAD},
257 .edge_type = YAC_LAT_CIRCLE_EDGE,
258 .edge_ordering = 1,
259 .is_inside = 2},
260 // a circle of latitude close to the south pole and a point on the north
261 // pole (the angle between them is close to PI)
262 {.a = {.lon = 75.0, .lat = -90.0 + 1.0e-6 / YAC_RAD},
263 .b = {.lon = 80.0, .lat = -90.0 + 1.0e-6 / YAC_RAD},
264 .point = {.lon = 15.0, .lat = 90.0},
265 .edge_type = YAC_LAT_CIRCLE_EDGE,
266 .edge_ordering = 1,
267 .is_inside = 1}};
268 enum {NUM_TESTS = sizeof(test_data) / sizeof(test_data[0])};
269
270 for (size_t i = 0; i < NUM_TESTS; ++i) {
271 double point[3];
272 LLtoXYZ_deg(test_data[i].point.lon,
273 test_data[i].point.lat, point);
274 struct yac_circle test_circle;
275 double a[3], b[3];
276 LLtoXYZ_deg(test_data[i].a.lon, test_data[i].a.lat, a);
277 LLtoXYZ_deg(test_data[i].b.lon, test_data[i].b.lat, b);
279 a, b, test_data[i].edge_type, test_data[i].edge_ordering,
280 &test_circle);
281 int is_inside = yac_circle_point_is_inside(point, &test_circle);
282 if (is_inside != test_data[i].is_inside) {
283 fprintf(
284 stderr, "test_data index %zu: is_inside %d (expected %d)\n",
285 i, is_inside, test_data[i].is_inside);
286 PUT_ERR("error in yac_circle_point_is_inside");
287 }
288 }
289 }
290
291 { // test yac_circle_compare_distances
292 struct {
293 struct point_2d a, b, point_a, point_b;
294 enum yac_edge_type edge_type;
295 int compare;
296 } test_data[] =
297 {{.a = {.lon = -1.0, .lat = -1.0},
298 .b = {.lon = 1.0, .lat = 1.0},
299 .point_a = {.lon = -1.0, .lat = 1.0},
300 .point_b = {.lon = -2.0, .lat = 2.0},
301 .edge_type = YAC_GREAT_CIRCLE_EDGE,
302 .compare = -1},
303 {.a = {.lon = -1.0, .lat = -1.0},
304 .b = {.lon = 1.0, .lat = 1.0},
305 .point_a = {.lon = -2.0, .lat = 2.0},
306 .point_b = {.lon = -1.0, .lat = 1.0},
307 .edge_type = YAC_GREAT_CIRCLE_EDGE,
308 .compare = 1},
309 {.a = {.lon = -1.0, .lat = -1.0},
310 .b = {.lon = 1.0, .lat = 1.0},
311 .point_a = {.lon = -2.0, .lat = 2.0},
312 .point_b = {.lon = 2.0, .lat = -2.0},
313 .edge_type = YAC_GREAT_CIRCLE_EDGE,
314 .compare = 0},
315 {.a = {.lon = -1.0, .lat = -1.0},
316 .b = {.lon = 1.0, .lat = 1.0},
317 .point_a = {.lon = 0.0, .lat = 0.0},
318 .point_b = {.lon = 2.0, .lat = -2.0},
319 .edge_type = YAC_GREAT_CIRCLE_EDGE,
320 .compare = -1},
321 {.a = {.lon = -1.0, .lat = -1.0},
322 .b = {.lon = 1.0, .lat = 1.0},
323 .point_a = {.lon = 2.0, .lat = -2.0},
324 .point_b = {.lon = 0.0, .lat = 0.0},
325 .edge_type = YAC_GREAT_CIRCLE_EDGE,
326 .compare = 1},
327 {.a = {.lon = 2.0, .lat = -1.0},
328 .b = {.lon = 2.0, .lat = 1.0},
329 .point_a = {.lon = 1.0, .lat = 1.0},
330 .point_b = {.lon = 4.0, .lat = -1.0},
331 .edge_type = YAC_LON_CIRCLE_EDGE,
332 .compare = -1},
333 {.a = {.lon = 2.0, .lat = -1.0},
334 .b = {.lon = 2.0, .lat = 1.0},
335 .point_a = {.lon = 4.0, .lat = -1.0},
336 .point_b = {.lon = 1.0, .lat = 1.0},
337 .edge_type = YAC_LON_CIRCLE_EDGE,
338 .compare = 1},
339 {.a = {.lon = 2.0, .lat = -1.0},
340 .b = {.lon = 2.0, .lat = 1.0},
341 .point_a = {.lon = 3.0, .lat = -1.0},
342 .point_b = {.lon = 1.0, .lat = 1.0},
343 .edge_type = YAC_LON_CIRCLE_EDGE,
344 .compare = 0},
345 {.a = {.lon = -1.0, .lat = 60.0},
346 .b = {.lon = 1.0, .lat = 60.0},
347 .point_a = {.lon = 7.0, .lat = 59.0},
348 .point_b = {.lon = -13.0, .lat = 62.0},
349 .edge_type = YAC_LAT_CIRCLE_EDGE,
350 .compare = -1},
351 {.a = {.lon = -1.0, .lat = 60.0},
352 .b = {.lon = 1.0, .lat = 60.0},
353 .point_a = {.lon = -13.0, .lat = 62.0},
354 .point_b = {.lon = 7.0, .lat = 59.0},
355 .edge_type = YAC_LAT_CIRCLE_EDGE,
356 .compare = 1},
357 {.a = {.lon = -1.0, .lat = 60.0},
358 .b = {.lon = 1.0, .lat = 60.0},
359 .point_a = {.lon = 7.0, .lat = 59.0},
360 .point_b = {.lon = -13.0, .lat = 61.0},
361 .edge_type = YAC_LAT_CIRCLE_EDGE,
362 .compare = 0},
363 {.a = {.lon = 45.0, .lat = 45.0},
364 .b = {.lon = 45.0, .lat = 45.0},
365 .point_a = {.lon = 46.0, .lat = 46.0},
366 .point_b = {.lon = 47.0, .lat = 47.0},
367 .edge_type = YAC_GREAT_CIRCLE_EDGE,
368 .compare = -1},
369 {.a = {.lon = 45.0, .lat = 45.0},
370 .b = {.lon = 45.0, .lat = 45.0},
371 .point_a = {.lon = 47.0, .lat = 47.0},
372 .point_b = {.lon = 46.0, .lat = 46.0},
373 .edge_type = YAC_GREAT_CIRCLE_EDGE,
374 .compare = 1},
375 {.a = {.lon = 45.0, .lat = 45.0},
376 .b = {.lon = 45.0, .lat = 45.0},
377 .point_a = {.lon = 40.0, .lat = 40.0},
378 .point_b = {.lon = -45.0, .lat = -45.0},
379 .edge_type = YAC_GREAT_CIRCLE_EDGE,
380 .compare = -1},
381 {.a = {.lon = 45.0, .lat = 45.0},
382 .b = {.lon = 45.0, .lat = 45.0},
383 .point_a = {.lon = -45.0, .lat = -45.0},
384 .point_b = {.lon = 40.0, .lat = 40.0},
385 .edge_type = YAC_GREAT_CIRCLE_EDGE,
386 .compare = 1},
387 {.a = {.lon = 45.0, .lat = 45.0},
388 .b = {.lon = 45.0, .lat = 45.0},
389 .point_a = {.lon = 45.0, .lat = 90.0},
390 .point_b = {.lon = 45.0, .lat = 0.0},
391 .edge_type = YAC_GREAT_CIRCLE_EDGE,
392 .compare = 0}};
393 enum {NUM_TESTS = sizeof(test_data) / sizeof(test_data[0])};
394
395 for (size_t i = 0; i < NUM_TESTS; ++i) {
396 double point_a[3], point_b[3];
397 LLtoXYZ_deg(test_data[i].point_a.lon,
398 test_data[i].point_a.lat, point_a);
399 LLtoXYZ_deg(test_data[i].point_b.lon,
400 test_data[i].point_b.lat, point_b);
401 struct yac_circle test_circle;
402 double a[3], b[3];
403 LLtoXYZ_deg(test_data[i].a.lon, test_data[i].a.lat, a);
404 LLtoXYZ_deg(test_data[i].b.lon, test_data[i].b.lat, b);
406 a, b, test_data[i].edge_type, 1, &test_circle);
407 if (yac_circle_compare_distances(point_a, point_b, &test_circle) !=
408 test_data[i].compare)
409 PUT_ERR("error in yac_circle_compare_distances");
410 }
411 }
412
413 { // basic tests for yac_circle_intersect
414 struct {
415 struct {
416 struct point_2d points[2];
417 enum yac_edge_type edge_type;
418 } circles[2];
419 struct point_2d p, q;
420 int ret_value;
421 } test_data[] =
422 {{.circles = {{.points = {{.lon = -1.0, .lat = -1.0},
423 {.lon = 1.0, .lat = 1.0}},
424 .edge_type = YAC_GREAT_CIRCLE_EDGE},
425 {.points = {{.lon = -1.0, .lat = 1.0},
426 {.lon = 1.0, .lat = -1.0}},
427 .edge_type = YAC_GREAT_CIRCLE_EDGE}},
428 .p = {.lon = 0.0, .lat = 0.0},
429 .q = {.lon = 180.0, .lat = 0.0},
430 .ret_value = 2},
431 {.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
432 {.lon = 0.0, .lat = 1.0}},
433 .edge_type = YAC_GREAT_CIRCLE_EDGE},
434 {.points = {{.lon = 180.0, .lat = -2.0},
435 {.lon = 180.0, .lat = 2.0}},
436 .edge_type = YAC_GREAT_CIRCLE_EDGE}},
437 .p = {.lon = 0.0, .lat = 0.0},
438 .q = {.lon = 0.0, .lat = 0.0},
439 .ret_value = -1},
440 {.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
441 {.lon = 0.0, .lat = 1.0}},
442 .edge_type = YAC_GREAT_CIRCLE_EDGE},
443 {.points = {{.lon = 6.0, .lat = 45.0},
444 {.lon = 9.0, .lat = 45.0}},
445 .edge_type = YAC_LAT_CIRCLE_EDGE}},
446 .p = {.lon = 0.0, .lat = 45.0},
447 .q = {.lon = 180.0, .lat = 45.0},
448 .ret_value = 2},
449 {.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
450 {.lon = 0.0, .lat = 1.0}},
451 .edge_type = YAC_GREAT_CIRCLE_EDGE},
452 {.points = {{.lon = 6.0, .lat = 90.0},
453 {.lon = 9.0, .lat = 90.0}},
454 .edge_type = YAC_LAT_CIRCLE_EDGE}},
455 .p = {.lon = 0.0, .lat = 90.0},
456 .q = {.lon = 180.0, .lat = -90.0},
457 .ret_value = 1},
458 {.circles = {{.points = {{.lon = 1.0, .lat = 0.0},
459 {.lon = 2.0, .lat = 0.0}},
460 .edge_type = YAC_GREAT_CIRCLE_EDGE},
461 {.points = {{.lon = 6.0, .lat = 45.0},
462 {.lon = 9.0, .lat = 45.0}},
463 .edge_type = YAC_LAT_CIRCLE_EDGE}},
464 .p = {.lon = 0.0, .lat = 0.0},
465 .q = {.lon = 0.0, .lat = 0.0},
466 .ret_value = 0},
467 {.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
468 {.lon = 0.0, .lat = 1.0}},
469 .edge_type = YAC_LON_CIRCLE_EDGE},
470 {.points = {{.lon = 17.0, .lat = -1.0},
471 {.lon = 17.0, .lat = 1.0}},
472 .edge_type = YAC_LON_CIRCLE_EDGE}},
473 .p = {.lon = 0.0, .lat = 90.0},
474 .q = {.lon = 0.0, .lat = -90.0},
475 .ret_value = 2},
476 {.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
477 {.lon = 0.0, .lat = 1.0}},
478 .edge_type = YAC_LON_CIRCLE_EDGE},
479 {.points = {{.lon = 0.0, .lat = 45.0},
480 {.lon = 0.0, .lat = 50.0}},
481 .edge_type = YAC_LON_CIRCLE_EDGE}},
482 .p = {.lon = 0.0, .lat = 90.0},
483 .q = {.lon = 0.0, .lat = -90.0},
484 .ret_value = -1},
485 {.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
486 {.lon = 0.0, .lat = 1.0}},
487 .edge_type = YAC_LON_CIRCLE_EDGE},
488 {.points = {{.lon = -1.0, .lat = 45.0},
489 {.lon = 1.0, .lat = 45.0}},
490 .edge_type = YAC_LAT_CIRCLE_EDGE}},
491 .p = {.lon = 0.0, .lat = 45.0},
492 .q = {.lon = 180.0, .lat = 45.0},
493 .ret_value = 2},
494 {.circles = {{.points = {{.lon = 0.0, .lat = -1.0},
495 {.lon = 0.0, .lat = 1.0}},
496 .edge_type = YAC_LON_CIRCLE_EDGE},
497 {.points = {{.lon = -1.0, .lat = -90.0},
498 {.lon = 1.0, .lat = -90.0}},
499 .edge_type = YAC_LAT_CIRCLE_EDGE}},
500 .p = {.lon = 0.0, .lat = -90.0},
501 .q = {.lon = 180.0, .lat = 90.0},
502 .ret_value = 1},
503 {.circles = {{.points = {{.lon = 0.0, .lat = 0.0},
504 {.lon = 0.0, .lat = 0.0}},
505 .edge_type = YAC_GREAT_CIRCLE_EDGE}, // point
506 {.points = {{.lon = -1.0, .lat = 0.0},
507 {.lon = 1.0, .lat = 0.0}},
508 .edge_type = YAC_GREAT_CIRCLE_EDGE}},
509 .p = {.lon = 0.0, .lat = 0.0},
510 .q = {.lon = 180.0, .lat = 0.0},
511 .ret_value = 1},
512 {.circles = {{.points = {{.lon = 0.0, .lat = 1.0},
513 {.lon = 0.0, .lat = 1.0}},
514 .edge_type = YAC_GREAT_CIRCLE_EDGE}, // point
515 {.points = {{.lon = -1.0, .lat = 0.0},
516 {.lon = 1.0, .lat = 0.0}},
517 .edge_type = YAC_GREAT_CIRCLE_EDGE}},
518 .p = {.lon = 0.0, .lat = 0.0},
519 .q = {.lon = 180.0, .lat = 0.0},
520 .ret_value = 0},
521 {.circles = {{.points = {{.lon = 0.0, .lat = 45.0},
522 {.lon = 0.0, .lat = 45.0}},
523 .edge_type = YAC_GREAT_CIRCLE_EDGE}, // point
524 {.points = {{.lon = -1.0, .lat = 45.0},
525 {.lon = 1.0, .lat = 45.0}},
526 .edge_type = YAC_LAT_CIRCLE_EDGE}},
527 .p = {.lon = 0.0, .lat = 45.0},
528 .q = {.lon = 180.0, .lat = 45.0},
529 .ret_value = 1},
530 {.circles = {{.points = {{.lon = 0.0, .lat = 0.0},
531 {.lon = 0.0, .lat = 0.0}},
532 .edge_type = YAC_GREAT_CIRCLE_EDGE}, // point
533 {.points = {{.lon = -1.0, .lat = 45.0},
534 {.lon = 1.0, .lat = 45.0}},
535 .edge_type = YAC_LAT_CIRCLE_EDGE}},
536 .p = {.lon = 0.0, .lat = 45.0},
537 .q = {.lon = 180.0, .lat = 45.0},
538 .ret_value = 0},
539 {.circles = {{.points = {{.lon = 5.0, .lat = 5.0},
540 {.lon = 5.0, .lat = 5.0}},
541 .edge_type = YAC_GREAT_CIRCLE_EDGE}, // point
542 {.points = {{.lon = 5.0, .lat = 5.0},
543 {.lon = 5.0, .lat = 5.0}},
544 .edge_type = YAC_GREAT_CIRCLE_EDGE}}, // point
545 .p = {.lon = 5.0, .lat = 5.0},
546 .q = {.lon = 185.0, .lat = -5.0},
547 .ret_value = 1},
548 // two identical circles of latitude
549 {.circles = {{.points = {{.lon = 0.0, .lat = 45.0},
550 {.lon = 10.0, .lat = 45.0}},
551 .edge_type = YAC_LAT_CIRCLE_EDGE},
552 {.points = {{.lon = 20.0, .lat = 45.0},
553 {.lon = 30.0, .lat = 45.0}},
554 .edge_type = YAC_LAT_CIRCLE_EDGE}},
555 .p = {.lon = 0.0, .lat = 0.0},
556 .q = {.lon = 0.0, .lat = 0.0},
557 .ret_value = -1},
558 // two identical circles of latitude on the equator
559 {.circles = {{.points = {{.lon = 0.0, .lat = 0.0},
560 {.lon = 10.0, .lat = 0.0}},
561 .edge_type = YAC_LAT_CIRCLE_EDGE},
562 {.points = {{.lon = 20.0, .lat = 0.0},
563 {.lon = 30.0, .lat = 0.0}},
564 .edge_type = YAC_LAT_CIRCLE_EDGE}},
565 .p = {.lon = 0.0, .lat = 0.0},
566 .q = {.lon = 0.0, .lat = 0.0},
567 .ret_value = -1},
568 // two circles of latitude whose latitudes add up to 90 degree
569 {.circles = {{.points = {{.lon = 0.0, .lat = 30.0},
570 {.lon = 10.0, .lat = 30.0}},
571 .edge_type = YAC_LAT_CIRCLE_EDGE},
572 {.points = {{.lon = 20.0, .lat = 60.0},
573 {.lon = 30.0, .lat = 60.0}},
574 .edge_type = YAC_LAT_CIRCLE_EDGE}},
575 .p = {.lon = 0.0, .lat = 0.0},
576 .q = {.lon = 0.0, .lat = 0.0},
577 .ret_value = 0},
578 // two circles of latitude mirrored at the equator
579 {.circles = {{.points = {{.lon = 0.0, .lat = -45.0},
580 {.lon = 10.0, .lat = -45.0}},
581 .edge_type = YAC_LAT_CIRCLE_EDGE},
582 {.points = {{.lon = 20.0, .lat = 45.0},
583 {.lon = 30.0, .lat = 45.0}},
584 .edge_type = YAC_LAT_CIRCLE_EDGE}},
585 .p = {.lon = 0.0, .lat = 0.0},
586 .q = {.lon = 0.0, .lat = 0.0},
587 .ret_value = 0},
588 // two distinct circles of latitude
589 {.circles = {{.points = {{.lon = 0.0, .lat = 10.0},
590 {.lon = 10.0, .lat = 10.0}},
591 .edge_type = YAC_LAT_CIRCLE_EDGE},
592 {.points = {{.lon = 20.0, .lat = 20.0},
593 {.lon = 30.0, .lat = 20.0}},
594 .edge_type = YAC_LAT_CIRCLE_EDGE}},
595 .p = {.lon = 0.0, .lat = 0.0},
596 .q = {.lon = 0.0, .lat = 0.0},
597 .ret_value = 0},
598 // two circles of latitude very close to each other, but still further
599 // apart than the tolerance
600 {.circles = {{.points = {{.lon = 0.0, .lat = 45.0},
601 {.lon = 10.0, .lat = 45.0}},
602 .edge_type = YAC_LAT_CIRCLE_EDGE},
603 {.points = {{.lon = 20.0,
604 .lat = 45.0 + 1.0e-7 / YAC_RAD},
605 {.lon = 30.0,
606 .lat = 45.0 + 1.0e-7 / YAC_RAD}},
607 .edge_type = YAC_LAT_CIRCLE_EDGE}},
608 .p = {.lon = 0.0, .lat = 0.0},
609 .q = {.lon = 0.0, .lat = 0.0},
610 .ret_value = 0},
611 // two circles of latitude closer to each other than the tolerance
612 {.circles = {{.points = {{.lon = 0.0, .lat = 45.0},
613 {.lon = 10.0, .lat = 45.0}},
614 .edge_type = YAC_LAT_CIRCLE_EDGE},
615 {.points = {{.lon = 20.0,
616 .lat = 45.0 + 1.0e-11 / YAC_RAD},
617 {.lon = 30.0,
618 .lat = 45.0 + 1.0e-11 / YAC_RAD}},
619 .edge_type = YAC_LAT_CIRCLE_EDGE}},
620 .p = {.lon = 0.0, .lat = 0.0},
621 .q = {.lon = 0.0, .lat = 0.0},
622 .ret_value = -1}};
623 enum {NUM_TESTS = sizeof(test_data) / sizeof(test_data[0])};
624
625 for (size_t i = 0; i < NUM_TESTS; ++i) {
626 struct yac_circle test_circles[2];
627 for (int j = 0; j < 2; ++j) {
628 double points_3d[2][3];
629 for (int k = 0; k < 2; ++k)
631 test_data[i].circles[j].points[k].lon,
632 test_data[i].circles[j].points[k].lat, points_3d[k]);
634 points_3d[0], points_3d[1], test_data[i].circles[j].edge_type,
635 1, &test_circles[j]);
636 }
637 double ref_p[3], ref_q[3], p[3], q[3];
638 LLtoXYZ_deg(test_data[i].p.lon, test_data[i].p.lat, ref_p);
639 LLtoXYZ_deg(test_data[i].q.lon, test_data[i].q.lat, ref_q);
640 for (int j = 0; j < 2; ++j) {
642 test_circles[j], test_circles[j^1], p, q) !=
643 test_data[i].ret_value)
644 PUT_ERR("error in yac_circle_intersect");
645 if (test_data[i].ret_value > 0)
646 if (!(((get_vector_angle(p, ref_p) < yac_angle_tol) &&
647 (get_vector_angle(q, ref_q) < yac_angle_tol)) ||
648 ((get_vector_angle(q, ref_p) < yac_angle_tol) &&
649 (get_vector_angle(p, ref_q) < yac_angle_tol))))
650 PUT_ERR("error in yac_circle_intersect");
651 }
652 }
653 }
654
655 return TEST_EXIT_CODE;
656}
657
658static void utest_check_compare_circles(struct yac_circle * circle_a, int a_is_lat,
659 struct yac_circle * circle_b, int b_is_lat,
660 int are_identical) {
661
662 int ret_a = yac_circle_compare(&circle_a, &circle_b);
663 int ret_b = yac_circle_compare(&circle_b, &circle_a);
664 if ((are_identical && (ret_a || ret_b)) ||
665 (!are_identical &&
666 ((!ret_a || !ret_b) ||
667 (ret_a != - ret_b) ||
668 ((a_is_lat != b_is_lat) &&
669 ((ret_a > ret_b) ^ a_is_lat)))))
670 PUT_ERR("error in yac_circle_compare");
671}
int yac_circle_compare(void const *a, void const *b)
Definition clipping.c:339
int yac_circle_contains_north_pole(struct yac_circle const *circle)
Definition clipping.c:595
int yac_circle_point_is_inside(double const point[3], struct yac_circle const *circle)
Definition clipping.c:492
void yac_circle_generate(double const *a, double const *b, enum yac_edge_type type, int edge_ordering, struct yac_circle *circle)
Definition clipping.c:407
int yac_circle_compare_distances(double const a[3], double const b[3], struct yac_circle const *circle)
Definition clipping.c:542
#define YAC_RAD
int yac_circle_intersect(struct yac_circle a, struct yac_circle b, double p[3], double q[3])
static void LLtoXYZ_deg(double lon, double lat, double p_out[])
Definition geometry.h:278
#define yac_angle_tol
Definition geometry.h:26
static double get_vector_angle(double const a[3], double const b[3])
Definition geometry.h:472
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
struct yac_circle::@8::@10 lat
struct yac_circle::@8::@11 p
struct yac_circle::@8::@9 lon
#define NUM_TESTS
#define TEST_EXIT_CODE
Definition tests.h:15
#define PUT_ERR(string)
Definition tests.h:10
double(* p)(double lon, double lat)
Definition toy_scrip.c:119