YAC 3.12.0
Yet Another Coupler
Loading...
Searching...
No Matches
test_cell_bnd_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#include "tests.h"
9#include "geometry.h"
10#include "grids/grid_cell.h"
11#include "test_common.h"
12
18double const tol = 1.0e-10;
19
20static void utest_check_latlon_cell(double * coordinates_x, double * coordinates_y);
21static void utest_check_gc_triangle(double * coordinates_x, double * coordinates_y);
22static void utest_check_gc_quad(double * coordinates_x, double * coordinates_y);
23static void utest_check_gc(double * coordinates_x, double * coordinates_y, size_t num_corners);
24// tests whether all corners of cell are within the bounding circle
25static void utest_test_circle(struct yac_grid_cell cell, struct bounding_circle circle);
26// tests whether a point is within the bounding circle
27static unsigned utest_point_in_circle(double point[3], struct bounding_circle circle);
28
29int main (void) {
30
31 { // test without corners
32 struct yac_grid_cell cell = {
33 .coordinates_xyz = NULL,
34 .edge_type = NULL,
35 .num_corners = 0,
36 .array_size = 0
37 };
38
39 struct bounding_circle bnd_circle;
40 yac_get_cell_bounding_circle(cell, &bnd_circle);
41 }
42
43 { // test regular cell
44
45 double coordinates_x[] = {-1.0, 1.0, 1.0, -1.0};
46 double coordinates_y[] = {-1.0, -1.0, 1.0, 1.0};
47 utest_check_latlon_cell(coordinates_x, coordinates_y);
48 }
49
50 { // test regular cell
51
52 double coordinates_x[] = {40.0, 45.0, 45.0, 40.0};
53 double coordinates_y[] = {20.0, 20.0, 25.0, 25.0};
54 utest_check_latlon_cell(coordinates_x, coordinates_y);
55 }
56
57 { // test regular cell
58
59 double coordinates_x[] = { 175.0, -175.0, -175.0, 175.0};
60 double coordinates_y[] = {-5.0, -5.0, 5.0, 5.0};
61 utest_check_latlon_cell(coordinates_x, coordinates_y);
62 }
63
64 { // test regular cell
65
66
67 double coordinates_x[] = {30.0, 40.0, 40.0, 30.0};
68 double coordinates_y[] = {80.0, 80.0, 85.0, 85.0};
69 utest_check_latlon_cell(coordinates_x, coordinates_y);
70 }
71
72 { // test regular cell
73
74 double coordinates_x[] = {30.0, 40.0, 40.0, 30.0};
75 double coordinates_y[] = {80.0, 80.0, 90.0, 90.0};
76 utest_check_latlon_cell(coordinates_x, coordinates_y);
77 }
78
79 { // test regular cell
80
81
82 double coordinates_x[] = {0.0, 1.0, 1.0, 0.0};
83 double coordinates_y[] = {89.0, 89.0, 90.0, 90.0};
84 utest_check_latlon_cell(coordinates_x, coordinates_y);
85 }
86
87 { // test regular cell
88
89
90 double coordinates_x[] = {0.0, 1.0, 0.0, 0.0};
91 double coordinates_y[] = {89.0, 89.0, 90.0, 90.0};
92 utest_check_latlon_cell(coordinates_x, coordinates_y);
93 }
94
95 { // test triangle
96
97 double coordinates_x[] = {-5.0, 5.0, 0.0};
98 double coordinates_y[] = {-5.0, 5.0, -5.0};
99 utest_check_gc_triangle(coordinates_x, coordinates_y);
100 }
101
102 { // test triangle
103
104 double coordinates_x[] = {0.0, 120.0, -120.0};
105 double coordinates_y[] = {85.0, 85.0, 85.0};
106 utest_check_gc_triangle(coordinates_x, coordinates_y);
107 }
108
109 { // test triangle
110
111 double coordinates_x[] = {0.0, 120.0, -120.0};
112 double coordinates_y[] = {-85.0, -85.0, -85.0};
113 utest_check_gc_triangle(coordinates_x, coordinates_y);
114 }
115
116 { // test triangle
117
118 double coordinates_x[] = {-5.0, 5.0, 1.0};
119 double coordinates_y[] = {0.0, 0.0, 1.0};
120 utest_check_gc_triangle(coordinates_x, coordinates_y);
121 }
122
123 { // test triangle
124
125 double coordinates_x[] = {0.0, 170.0, 260.0};
126 double coordinates_y[] = {85.0, 85.0, 89.0};
127 utest_check_gc_triangle(coordinates_x, coordinates_y);
128 }
129
130 { // test great circle quad
131
132 double coordinates_x[] = {-1.0, 1.0, 1.0, -1.0};
133 double coordinates_y[] = {-1.0, -1.0, 1.0, 1.0};
134 utest_check_gc_quad(coordinates_x, coordinates_y);
135 }
136
137 { // test great circle quad
138
139 double coordinates_x[] = {0.0, 90.0, 180.0, 270.0};
140 double coordinates_y[] = {85.0, 85.0, 85.0, 85.0};
141 utest_check_gc_quad(coordinates_x, coordinates_y);
142 }
143
144 { // test great circle quad
145
146 double coordinates_x[] = {0.0, 90.0, 180.0, 270.0};
147 double coordinates_y[] = {-85.0, -85.0, -85.0, -85.0};
148 utest_check_gc_quad(coordinates_x, coordinates_y);
149 }
150
151 { // test great circle quad
152
153
154 double coordinates_x[] = {0.0, 10.0, 0.0, -10.0};
155 double coordinates_y[] = {-10.0, 0.0, 10.0, 0.0};
156 utest_check_gc_quad(coordinates_x, coordinates_y);
157 }
158
159 { // test great circle pentagon
160
161
162 double coordinates_x[] = {-1.0, -0.75, 0.75, 1.0, 0.0};
163 double coordinates_y[] = {0.25, -1.0, -1.0, 0.25, 1.0};
164 utest_check_gc(coordinates_x, coordinates_y, 5);
165 }
166
167 { // test great circle pentagon
168
169
170 double coordinates_x[] = {0.0, 72.0, 144.0, 216.0, 288.0};
171 double coordinates_y[] = {88.0, 88.0, 88.0, 88.0, 88.0};
172 utest_check_gc(coordinates_x, coordinates_y, 5);
173 }
174
175 { // test great circle hexagon
176
177
178 double coordinates_x[] = {-1.0, -0.75, 0.75, 1.0, 0.75, -0.75};
179 double coordinates_y[] = {0.0, -1.0, -1.0, 0.0, 1.0, 1.0};
180 utest_check_gc(coordinates_x, coordinates_y, 6);
181 }
182
183 { // test great circle hexagon
184
185
186 double coordinates_x[] = {0.0, 60.0, 120.0, 180.0, 240.0, 300.0};
187 double coordinates_y[] = {88.0, 88.0, 88.0, 88.0, 88.0, 88.0};
188 utest_check_gc(coordinates_x, coordinates_y, 6);
189 }
190
191 { // test great circle polygon with 7 corners
192
193
194 double coordinates_x[] = {0.0, 52.0, 104.0, 156.0, 208.0, 260.0, 312.0};
195 double coordinates_y[] = {88.0, 88.0, 88.0, 88.0, 88.0, 88.0};
196 utest_check_gc(coordinates_x, coordinates_y, 7);
197 }
198
199 return TEST_EXIT_CODE;
200}
201
202static void utest_check_gc_triangle(double * coordinates_x, double * coordinates_y) {
203
204 enum yac_edge_type edges[] = {
206
207 for (int order = -1; order <= 1; order += 2) {
208
209 for (int start = 0; start < 3; ++start) {
210
211 double temp_coordinates_x[3];
212 double temp_coordinates_y[3];
213 double coords[3][3];
214
215 for (int i = 0; i < 3; ++i) {
216 temp_coordinates_x[i] = coordinates_x[(3+i*order+start)%3];
217 temp_coordinates_y[i] = coordinates_y[(3+i*order+start)%3];
218 LLtoXYZ(temp_coordinates_x[i]*YAC_RAD,
219 temp_coordinates_y[i]*YAC_RAD, coords[i]);
220 }
221
222 struct yac_grid_cell cell =
223 generate_cell_deg(temp_coordinates_x, temp_coordinates_y, edges, 3);
224
225 struct bounding_circle bnd_circle;
226
227 yac_get_cell_bounding_circle(cell, &bnd_circle);
228
229 utest_test_circle(cell, bnd_circle);
230
231 yac_free_grid_cell(&cell);
232 }
233 }
234}
235
236static void utest_check_gc_quad(double * coordinates_x, double * coordinates_y) {
237
240
241 for (unsigned i = 0; i < 4; ++i) {
244 }
245
246 for (int order = -1; order <= 1; order += 2) {
247
248 for (int start = 0; start < 4; ++start) {
249
250 double temp_coordinates_x[4];
251 double temp_coordinates_y[4];
252
253 for (int i = 0; i < 4; ++i) {
254 temp_coordinates_x[i] = coordinates_x[(4+i*order+start)%4];
255 temp_coordinates_y[i] = coordinates_y[(4+i*order+start)%4];
256 }
257
258 struct yac_grid_cell cell =
259 generate_cell_deg(temp_coordinates_x, temp_coordinates_y, edges, 4);
260
261 struct bounding_circle bnd_circle;
262
263 yac_get_cell_bounding_circle(cell, &bnd_circle);
264
265 utest_test_circle(cell, bnd_circle);
266
267 yac_free_grid_cell(&cell);
268 }
269 }
270}
271
272static void utest_check_gc(
273 double * coordinates_x, double * coordinates_y, size_t num_corners) {
274
275 enum yac_edge_type edges[num_corners];
276
277 for (size_t i = 0; i < num_corners; ++i) {
280 edges[i] = YAC_GREAT_CIRCLE_EDGE;
281 }
282
283 for (int order = -1; order <= 1; order += 2) {
284
285 for (size_t start = 0; start < num_corners; ++start) {
286
287 double temp_coordinates_x[num_corners];
288 double temp_coordinates_y[num_corners];
289
290 for (size_t i = 0; i < num_corners; ++i) {
291 temp_coordinates_x[i] =
292 coordinates_x[(num_corners+i*order+start)%num_corners];
293 temp_coordinates_y[i] =
294 coordinates_y[(num_corners+i*order+start)%num_corners];
295 }
296
297 struct yac_grid_cell cell =
299 temp_coordinates_x, temp_coordinates_y, edges, num_corners);
300
301 struct bounding_circle bnd_circle;
302
303 yac_get_cell_bounding_circle(cell, &bnd_circle);
304
305 utest_test_circle(cell, bnd_circle);
306
307 yac_free_grid_cell(&cell);
308 }
309 }
310}
311
312static void utest_check_latlon_cell(double * coordinates_x, double * coordinates_y) {
313
314 for (int order = -1; order <= 1; order += 2) {
315
316 for (int start = 0; start < 4; ++start) {
317
318 double temp_coordinates_x[4];
319 double temp_coordinates_y[4];
320 enum yac_edge_type edges[4];
321 double coords[4][3];
322
323 for (int i = 0; i < 4; ++i) {
324 temp_coordinates_x[i] = coordinates_x[(4+i*order+start)%4];
325 temp_coordinates_y[i] = coordinates_y[(4+i*order+start)%4];
326 LLtoXYZ(temp_coordinates_x[i]*YAC_RAD,
327 temp_coordinates_y[i]*YAC_RAD, coords[i]);
328 }
329
330
331 for (int i = 0; i < 4; ++i) {
332 int temp =
333 fabs(temp_coordinates_y[i] - temp_coordinates_y[(i+3)%4]) > 0.0;
334 edges[i] = (temp)?(YAC_LAT_CIRCLE_EDGE):(YAC_LON_CIRCLE_EDGE);
335 }
336
337 struct yac_grid_cell cell =
338 generate_cell_deg(temp_coordinates_x, temp_coordinates_y, edges, 4);
339
340 struct bounding_circle bnd_circle;
341
342 yac_get_cell_bounding_circle(cell, &bnd_circle);
343
344 utest_test_circle(cell, bnd_circle);
345
346 yac_free_grid_cell(&cell);
347 }
348 }
349}
350
352static inline void normalise_vector_lat(double v[]) {
353
354 double temp = v[0] * v[0] + v[1] * v[1];
355
356 if (fabs(temp) < 1e-9) {
357
358 v[0] = 0.0;
359 v[1] = 0.0;
360 v[2] = copysign(1.0, v[2]);
361
362 } else {
363
364 double norm;
365
366 if (fabs(v[2]) < 1e-9) {
367 norm = 1.0;
368 v[2] = 0.0;
369 } else {
370 norm = 1.0 - v[2] * v[2];
371 }
372
373 norm = sqrt(norm/temp);
374
375 v[0] *= norm;
376 v[1] *= norm;
377 }
378}
379
380static void utest_test_circle(struct yac_grid_cell cell, struct bounding_circle circle) {
381
382 for (size_t i = 0; i < cell.num_corners; ++i) {
383
384 if (!utest_point_in_circle(cell.coordinates_xyz[i], circle))
385 PUT_ERR("point is not in bounding circle\n");
387 PUT_ERR("point is not in bounding circle\n");
388
389 double edge_middle_point[3];
390 size_t j = (i + 1) % cell.num_corners;
391 edge_middle_point[0] =
392 cell.coordinates_xyz[i][0] + cell.coordinates_xyz[j][0];
393 edge_middle_point[1] =
394 cell.coordinates_xyz[i][1] + cell.coordinates_xyz[j][1];
395 edge_middle_point[2] =
396 cell.coordinates_xyz[i][2] + cell.coordinates_xyz[j][2];
397
398 switch (cell.edge_type[i]) {
401 edge_middle_point[2] =
402 cell.coordinates_xyz[i][2] + cell.coordinates_xyz[j][2];
403 normalise_vector(edge_middle_point);
404 break;
406 edge_middle_point[2] = cell.coordinates_xyz[i][2];
407 normalise_vector_lat(edge_middle_point);
408 break;
409 default:
410 PUT_ERR("invalid edge type");
411 continue;
412 }
413
414 if (!utest_point_in_circle(edge_middle_point, circle))
415 PUT_ERR("point is not in bounding circle\n");
416 if (!yac_point_in_bounding_circle_vec(edge_middle_point, &circle))
417 PUT_ERR("point is not in bounding circle\n");
418 }
419}
420
421static unsigned utest_point_in_circle(double point[3], struct bounding_circle circle) {
422
423 // double const tol = 1.0e-12;
424 // double const pi = 3.14159265358979323846;
425
426 struct sin_cos_angle inc_angle =
428 *(struct sin_cos_angle*)&(circle.inc_angle), SIN_COS_TOL);
429
430 // if (circle.inc_angle + tol >= pi) return 1 == 1;
431 if (compare_angles(inc_angle, SIN_COS_M_PI) >= 0) return 1 == 1;
432
433 return
435 get_vector_angle_2(circle.base_vector, point), inc_angle) <= 0;
436}
437
void yac_get_cell_bounding_circle(struct yac_grid_cell cell, struct bounding_circle *bnd_circle)
Definition bnd_circle.c:422
#define YAC_RAD
static struct sin_cos_angle get_vector_angle_2(double const a[3], double const b[3])
Definition geometry.h:361
static const struct sin_cos_angle SIN_COS_M_PI
Definition geometry.h:41
static int yac_point_in_bounding_circle_vec(double point_vector[3], struct bounding_circle *bnd_circle)
Definition geometry.h:197
static struct sin_cos_angle sum_angles_no_check(struct sin_cos_angle a, struct sin_cos_angle b)
Definition geometry.h:470
static const struct sin_cos_angle SIN_COS_TOL
Definition geometry.h:37
static int compare_angles(struct sin_cos_angle a, struct sin_cos_angle b)
Definition geometry.h:374
static void normalise_vector(double v[])
Definition geometry.h:635
void yac_free_grid_cell(struct yac_grid_cell *cell)
Definition grid_cell.c:44
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 sin_cos_angle inc_angle
angle between the middle point and the boundary of the spherical cap
Definition geometry.h:53
double base_vector[3]
Definition geometry.h:51
size_t num_corners
Definition grid_cell.h:21
enum yac_edge_type * edge_type
Definition grid_cell.h:20
double(* coordinates_xyz)[3]
Definition grid_cell.h:19
static void normalise_vector_lat(double v[])
double const tol
struct yac_grid_cell generate_cell_deg(double *lon, double *lat, enum yac_edge_type *edge_type, size_t num_corners)
Definition test_common.c:36
double coordinates_x[]
double coordinates_y[]
#define TEST_EXIT_CODE
Definition tests.h:14
#define PUT_ERR(string)
Definition tests.h:10
static void LLtoXYZ(double lon, double lat, double p_out[])
Definition toy_scrip.c:587