19#define YAC_EARTH_RADIUS (6371.2290)
21static int utest_compare_area(
double a,
double b);
22static void utest_test_area(
struct yac_grid_cell cell,
double ref_area,
36 puts (
"----- calculating area -----\n");
55 (
double[4]){0.0, 0.5, 0.0, -0.5},
gc_edges, 4);
70 (
double[3]){0.0, 0.5, 0.0},
gc_edges, 3);
100 (
double[4]){-0.5, -0.5, 0.5, 0.5},
gc_edges, 4);
121 (
double[3]){-0.5, -0.5, 0.5},
gc_edges, 3);
139 (
double[3]){-60.0, -60.0, -90.0},
gc_edges, 3);
170 (
double[4]){89.5, 89.5, 89.5, 89.5},
gc_edges, 4);
184 (
double[4]){60.0, 60.0, 90.0, 90.0},
gc_edges, 4);
198 (
double[4]){-90.0, -90.0, -60.0, -60.0},
gc_edges, 4);
214 (
double[5]){60.0, 60.0, 90.0, 90.0, 90.0},
gc_edges, 5);
230 (
double[3]){-0.5, -0.5, -0.5},
gc_edges, 3);
241 if ((area < 0.0) || (area > 1e-9))
242 PUT_ERR(
"ERROR in yac_huiliers_area for zero size triangle");
250 (
double[4]){0, 0, 1, 1},
gc_edges, 4);
262 double dx[] = {1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1,
263 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9};
265 for (
size_t i = 0;
i <
sizeof(dx) /
sizeof(dx[0]); ++
i) {
270 (
double[4]){0, 0, 1, 1},
gc_edges, 4);
281 if (utest_compare_area(base_area, partial_area))
282 PUT_ERR(
"yac_huiliers_area computed wrong area\n");
284 printf (
"accuracy check for (base_area - partial_area) %8.1e sqr km for dx %.1e\n",
285 base_area - partial_area, dx[i]);
299 PUT_ERR(
"pole_area computed wrong area\n");
306 PUT_ERR(
"huiliers_area computed wrong area\n");
314 double edge_length_deg = 1.0e-8;
316 printf (
"\n accuracy check for a unit square\n");
317 printf (
" edge length [m] | plain | simple | pole | huiliers\n");
318 printf (
" ----------------+--------------------+--------------------+--------------------+--------------------\n");
319 for (
unsigned i = 1;
i < 11; ++
i ) {
321 double edge_length_m =
326 (
double[4]){0, 0, edge_length_deg, edge_length_deg},
329 double t_area = edge_length_m * edge_length_m;
335 printf (
" %.8e m|%.8e sqr m|%.8e sqr m|%.8e sqr m|%.8e sqr m\n",
336 edge_length_m, p_area, t_area, s_area, h_area);
338 edge_length_deg *= 10.0;
347 for (
int y = -90;
y <= 90;
y += 5) {
351 (
double[2]){(double)y, (
double)
y},
362 if ((y == -90) || (
y == 90) || (y == 0)) {
400 { 0.0, 0.5, 0.5, 0.0}};
402 { 0.0, 0.0, 0.5, 0.5}};
404 for (
int x = 0;
x < 2; ++
x) {
405 for (
int y = 0;
y < 2; ++
y) {
424 (
double[4]){-0.5, -0.5, 0.5, 0.5}, lat_edges, 4);
433 double ref_area = sin(1.0 *
YAC_RAD);
434 ref_area -= sin(0.5 *
YAC_RAD);
438 for (
int i = 0;
i < 2; ++
i) {
442 {-0.5,-0.5,-1.0, -1.0}};
458 double intersections[2][3];
469 double intersections_lon[2], intersections_lat[2];
470 XYZtoLL(intersections[0], &(intersections_lon[0]), &(intersections_lat[0]));
471 XYZtoLL(intersections[1], &(intersections_lon[1]), &(intersections_lat[1]));
476 (
double[]){20.0, intersections_lon[0]/
YAC_RAD,
478 (
double[]){59.0, 60.0, 60.0},
483 if (utest_compare_area(partial_area,
485 PUT_ERR(
"pole_area != huiliers_area for convex cell");
487 double ref_area = 2.0 * partial_area;
495 -intersections_lon[0]/
YAC_RAD, -20.0},
496 (
double[]){59.0, 60.0, 60.0, 60.0, 60.0, 59.0},
507 (
double[]){59.0, 60.0, 60.0, 59.0, 60.0, 60.0},
512 for (
int i = 0;
i < 2; ++
i) {
525 -151.7087167856307133,
526 -150.6174180645230933},
527 (
double[]){ 10.6333746562670566,
531 -153.8786613849353557,
532 -151.6929566531634066},
533 (
double[]){ 13.4512385235805798,
537 -151.6929566531634066,
538 -150.6265735326831532},
539 (
double[]){ 13.4512385235805798,
543 -151.6929566531634066,
544 -152.7627337461449031},
545 (
double[]){ 11.4650630285209161,
549 -152.7627337461449031,
550 -150.5840076321059371},
551 (
double[]){ 11.5568484830228009,
555 -150.6265735326831532,
556 -149.5139953075027108},
557 (
double[]){ 11.5568484830228009,
561 -149.5139953075027108,
562 -150.5840076321059371},
563 (
double[]){ 11.5568484830228009,
566 size_t num_cells =
sizeof(cells) /
sizeof(cells[0]);
568 struct yac_grid_cell overlap_cells[sizeof(cells) / sizeof(cells[0]) - 1];
575 double area_tol = tgt_area * 1e-8;
576 double diff_area = tgt_area;
581 if (fabs(diff_area) > area_tol)
582 PUT_ERR(
"yac_huiliers_area is too inaccurate");
594 (
double[3]){0.0, 0.0, 0.0},
gc_edges, 3);
597 PUT_ERR(
"ERROR in yac_triangle_area");
601 (
double[3]){0.0, 0.0, 0.0},
gc_edges, 3);
604 PUT_ERR(
"ERROR in yac_triangle_area");
608 (
double[3]){0.0, 0.0, 0.0},
gc_edges, 3);
611 PUT_ERR(
"ERROR in yac_triangle_area");
616 double ref_area = 0.0;
617 double ref_barycenter[3] = {0.0, 0.0, 0.0};
622 (
double[]){0.0,1.0,1.0, 0.0},
623 (
double[]){0.0,0.0,1.0, 1.0},
gc_edges, 4);
629 enum {NUM_CORNERS = 6};
630 double coordinates_x[NUM_CORNERS] = {0.0, 1.0, 1.0, 0.0, 1.0, 0.0};
631 double coordinates_y[NUM_CORNERS] = {0.0, 0.0, 1.0, 0.0, 1.0, 1.0};
633 for (
size_t i = 0;
i < NUM_CORNERS; ++
i) {
635 double temp_coordinates_x[NUM_CORNERS];
636 double temp_coordinates_y[NUM_CORNERS];
638 for (
size_t j = 0; j < NUM_CORNERS; ++j) {
642 double area = 0.0, barycenter[3] = {0.0, 0.0, 0.0};
645 temp_coordinates_x, temp_coordinates_y,
gc_edges, NUM_CORNERS);
651 PUT_ERR(
"ERROR in yac_huiliers_area_info (area)");
654 PUT_ERR(
"ERROR in yac_huiliers_area_info (barycenter)");
657 if ((barycenter[0] != barycenter[0]) ||
658 (barycenter[1] != barycenter[1]) ||
659 (barycenter[2] != barycenter[2]))
660 PUT_ERR(
"ERROR in yac_huiliers_area_info (barycenter NAN)");
667 for (
int pole = -1; pole <= 1; pole += 2) {
668 for (
int cell_order_a = 0; cell_order_a < 2; ++cell_order_a) {
669 for (
int cell_order_b = 0; cell_order_b < 2; ++cell_order_b) {
673 double lon[2][3] = {{0.0,0.0,20.0}, {20.0, 20.0, 0.0}};
677 (
double[]){copysign(88.0,(
double)pole),
678 copysign(90.0,(
double)pole),
679 copysign(88.0,(
double)pole)},
gc_edges, 3);
683 (
double[]){copysign(88.0,(
double)pole),
684 copysign(90.0,(
double)pole),
685 copysign(88.0,(
double)pole)}, ll_edges, 3);
687 double gc_barycenter[3] = {0.0, 0.0, 0.0};
690 double ll_barycenter[3] = {0.0, 0.0, 0.0};
696 gc_barycenter[0] = -gc_barycenter[0];
697 gc_barycenter[1] = -gc_barycenter[1];
698 gc_barycenter[2] = -gc_barycenter[2];
704 ll_barycenter[0] = -ll_barycenter[0];
705 ll_barycenter[1] = -ll_barycenter[1];
706 ll_barycenter[2] = -ll_barycenter[2];
712 PUT_ERR(
"ERROR in yac_huiliers_area_info (area)");
716 if (((gc_barycenter[2] - ll_barycenter[2]) * (
double)pole) < 1e-9)
717 PUT_ERR(
"ERROR in yac_huiliers_area_info (barycenter)");
726static void utest_test_area(
struct yac_grid_cell cell,
double ref_area,
729 double mem_dummy_[128][3];
732 .edge_type = edge_dummy,
735 for (
int order = -1; order <= 1; order += 2) {
736 for (
int start = 0; start < (int)(cell.
num_corners); ++start) {
747 double area = area_func(test_cell);
749 if (utest_compare_area(area, ref_area))
PUT_ERR(
"ERROR: wrong area\n");
754static int utest_compare_area(
double a,
double b) {
756 double diff = fabs(a - b);
759 if (diff <
tol)
return 0;
760 else return (a > b) - (a < b);
double yac_huiliers_area(struct yac_grid_cell cell)
Area calculation on a unit sphere taken from ESMF based on L'Huilier's Theorem.
double yac_pole_area(struct yac_grid_cell cell)
Calculate the area of a cell in a 3d plane on a unit sphere.
double yac_planar_3dcell_area(struct yac_grid_cell cell)
Area calculation on a unit sphere of a planar polygon in 3D.
double yac_huiliers_area_info(struct yac_grid_cell cell, double *barycenter, double sign)
double yac_triangle_area(struct yac_grid_cell cell)
Calculate the area of a triangle on a unit sphere.
Structs and interfaces for area calculations.
void yac_cell_clipping(size_t N, struct yac_grid_cell *source_cell, struct yac_grid_cell target_cell, struct yac_grid_cell *overlap_buffer)
cell clipping to get the cells describing the intersections
static void normalise_vector(double v[])
static double get_vector_angle(double const a[3], double const b[3])
void yac_init_grid_cell(struct yac_grid_cell *cell)
void yac_free_grid_cell(struct yac_grid_cell *cell)
@ YAC_GREAT_CIRCLE_EDGE
great circle
@ YAC_LAT_CIRCLE_EDGE
latitude circle
@ YAC_LON_CIRCLE_EDGE
longitude circle
static void XYZtoLL(double const p_in[], double *lon, double *lat)
enum yac_edge_type * edge_type
double(* coordinates_xyz)[3]
struct yac_grid_cell generate_cell_deg(double *lon, double *lat, enum yac_edge_type *edge_type, size_t num_corners)
int intersect(enum yac_edge_type edge_type_a, double lon_a, double lat_a, double lon_b, double lat_b, enum yac_edge_type edge_type_b, double lon_c, double lat_c, double lon_d, double lat_d, double *intersection)
static enum yac_edge_type gc_edges[]