YAC 3.7.0
Yet Another Coupler
Loading...
Searching...
No Matches
clipping.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#ifdef HAVE_CONFIG_H
6// Get the definition of the 'restrict' keyword.
7#include "config.h"
8#endif
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <math.h>
14
15#include "geometry.h"
16#include "clipping.h"
17#include "area.h"
18#include "ensure_array_size.h"
19#include "utils_core.h"
20
21//#define YAC_VERBOSE_CLIPPING
22
23static double const tol = 1.0e-12;
24
32
38
39/* internal helper routines for working with linked lists of points */
40
41static void init_point_list(struct point_list * list);
42
43static void reset_point_list(struct point_list * list);
44
45static size_t generate_point_list(
46 struct point_list * list, struct yac_grid_cell cell, int cell_ordering,
47 struct yac_circle * circle_buffer);
48
49static struct point_list_element *
51
52static size_t remove_points(struct point_list * list);
53static size_t remove_zero_length_edges(struct point_list * list);
54
55static void free_point_list(struct point_list * list);
56
57static int get_cell_points_ordering(struct yac_grid_cell cell);
58
59static void generate_cell(struct point_list * list,
60 struct yac_grid_cell * cell);
61
62static enum yac_cell_type get_cell_type(struct yac_grid_cell target_cell);
63
64/* ------------------------- */
65
66static struct yac_grid_cell * overlap_cell_buffer = NULL;
67static size_t overlap_cell_buffer_size = 0;
68
69static inline struct yac_grid_cell * get_overlap_cell_buffer(size_t N) {
70
71 // ensure that there are enough buffer cells
72
74
75 size_t old_overlap_cell_buffer_size = overlap_cell_buffer_size;
76
78
79 for (; old_overlap_cell_buffer_size < overlap_cell_buffer_size;
80 ++old_overlap_cell_buffer_size)
81 yac_init_grid_cell(overlap_cell_buffer + old_overlap_cell_buffer_size);
82 }
83
85}
86
87
96
97/* ------------------------- */
98
99static double get_edge_direction(
100 double * ref_corner, double * corner_a, double * corner_b) {
101
102 double edge_norm[3];
103 crossproduct_kahan(corner_a, corner_b, edge_norm);
104 normalise_vector(edge_norm);
105
106 // sine of the angle between the edge and the reference corner
107 double angle =
108 edge_norm[0] * ref_corner[0] +
109 edge_norm[1] * ref_corner[1] +
110 edge_norm[2] * ref_corner[2];
111
112 // if the reference corner is directly on the edge
113 // (for small angles sin(x)==x)
114 if (fabs(angle) < yac_angle_tol) return 0.0;
115
116 return copysign(1.0, angle);
117}
118
120 struct yac_grid_cell * source_cell,
121 struct yac_grid_cell target_cell,
122 double * overlap_areas,
123 double (*overlap_barycenters)[3]) {
124
126 target_cell.num_corners > 2,
127 "ERROR(yac_compute_overlap_info): "
128 "target cell has too few corners")
129
130 struct yac_grid_cell * overlap_buffer = get_overlap_cell_buffer(N);
131 enum yac_cell_type target_cell_type;
132
133 // initialise barycenter coordinates if available
134 if (overlap_barycenters != NULL)
135 for (size_t i = 0; i < N; ++i)
136 for (int j = 0; j < 3; ++j)
137 overlap_barycenters[i][j] = 0.0;
138
139 // if the target is not a triangle
140 if ( target_cell.num_corners > 3 )
141 target_cell_type = get_cell_type (target_cell);
142
143 // special case: target is a triangle or a lon-lat cell -> no triangulation
144 // of the target is required
145 if ( target_cell.num_corners < 4 || target_cell_type == YAC_LON_LAT_CELL ) {
146 yac_cell_clipping ( N, source_cell, target_cell, overlap_buffer);
147 for (size_t i = 0; i < N; ++i) {
148 if (overlap_buffer[i].num_corners > 1) {
149 if (overlap_barycenters == NULL)
150 overlap_areas[i] = yac_huiliers_area (overlap_buffer[i]);
151 else {
152 overlap_areas[i] =
154 overlap_buffer[i], overlap_barycenters[i], 1.0);
156 (overlap_barycenters[i][0] != 0.0) ||
157 (overlap_barycenters[i][1] != 0.0) ||
158 (overlap_barycenters[i][2] != 0.0),
159 "ERROR(yac_compute_overlap_info): "
160 "overlap was computed, still barycenter is sphere origin");
161 normalise_vector(overlap_barycenters[i]);
162 if (overlap_areas[i] < 0.0) {
163 overlap_areas[i] = -overlap_areas[i];
164 overlap_barycenters[i][0] = -overlap_barycenters[i][0];
165 overlap_barycenters[i][1] = -overlap_barycenters[i][1];
166 overlap_barycenters[i][2] = -overlap_barycenters[i][2];
167 }
168 }
169 } else {
170 overlap_areas[i] = 0.0;
171 }
172 }
173 return;
174 }
175
176 // the triangulation algorithm only works for cells that only have great
177 // circle edges
178 // in order to also support other edge types, additional work would be
179 // required
181 target_cell_type == YAC_GREAT_CIRCLE_CELL,
182 "ERROR(yac_compute_overlap_info): invalid target cell type")
183
184 // data structure to hold the triangles of the target cell
185 struct yac_grid_cell target_partial_cell =
186 {.coordinates_xyz = (double[3][3]){{-1}},
187 .edge_type = (enum yac_edge_type[3]){YAC_GREAT_CIRCLE_EDGE,
190 .num_corners = 3};
191 // common node point to all partial target cells
192 double * base_corner = target_cell.coordinates_xyz[0];
193 target_partial_cell.coordinates_xyz[0][0] = base_corner[0];
194 target_partial_cell.coordinates_xyz[0][1] = base_corner[1];
195 target_partial_cell.coordinates_xyz[0][2] = base_corner[2];
196
197 // initialise overlap areas
198 for ( size_t n = 0; n < N; n++) overlap_areas[n] = 0.0;
199
200 // for all triangles of the target cell
201 // (triangles a formed by first corner of the target cells and each edge of
202 // the cell; the first and last edge of the cell already, contain the
203 // first corner, therefore we can skip them)
204 for ( size_t corner_idx = 1;
205 corner_idx < target_cell.num_corners - 1; ++corner_idx ) {
206
207 double * corner_a = target_cell.coordinates_xyz[corner_idx];
208 double * corner_b = target_cell.coordinates_xyz[corner_idx+1];
209
210 // if the current edge has a length of zero
211 if (points_are_identically(corner_a, corner_b)) continue;
212
213 double edge_direction =
214 get_edge_direction(base_corner, corner_a, corner_b);
215
216 target_partial_cell.coordinates_xyz[1][0] = corner_a[0];
217 target_partial_cell.coordinates_xyz[1][1] = corner_a[1];
218 target_partial_cell.coordinates_xyz[1][2] = corner_a[2];
219 target_partial_cell.coordinates_xyz[2][0] = corner_b[0];
220 target_partial_cell.coordinates_xyz[2][1] = corner_b[1];
221 target_partial_cell.coordinates_xyz[2][2] = corner_b[2];
222
223 // clip the current target cell triangle with all source cells
224 yac_cell_clipping(N, source_cell, target_partial_cell, overlap_buffer);
225
226 // for all source cells
227 for (size_t n = 0; n < N; n++) {
228
229 if (overlap_buffer[n].num_corners == 0) continue;
230
231 if (overlap_barycenters == NULL)
232 overlap_areas[n] +=
233 yac_huiliers_area(overlap_buffer[n]) * edge_direction;
234 else
235 overlap_areas[n] +=
237 overlap_buffer[n], overlap_barycenters[n], edge_direction);
238 }
239 }
240
241 for (size_t n = 0; n < N; n++) {
242
243 if (overlap_areas[n] < 0.0) {
244
245 overlap_areas[n] = -overlap_areas[n];
246
247 if (overlap_barycenters != NULL) {
248 overlap_barycenters[n][0] = -overlap_barycenters[n][0];
249 overlap_barycenters[n][1] = -overlap_barycenters[n][1];
250 overlap_barycenters[n][2] = -overlap_barycenters[n][2];
251 }
252 }
253 }
254
255 if (overlap_barycenters != NULL)
256 for (size_t n = 0; n < N; n++)
257 if ((overlap_areas[n] > 0.0) &&
258 ((overlap_barycenters[n][0] != 0.0) ||
259 (overlap_barycenters[n][1] != 0.0) ||
260 (overlap_barycenters[n][2] != 0.0)))
261 normalise_vector(overlap_barycenters[n]);
262
263#ifdef YAC_VERBOSE_CLIPPING
264 for (size_t n = 0; n < N; n++)
265 printf("overlap area %zu: %lf \n", n, overlap_areas[n]);
266#endif
267}
268
269static inline double dotproduct(double a[], double b[]) {
270
271 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
272}
273
274/* ------------------------- */
275
277 struct yac_grid_cell * source_cell,
278 struct yac_grid_cell target_cell,
279 double * partial_areas) {
280
282 N, source_cell, target_cell, partial_areas, NULL);
283}
284
285/* ------------------------- */
286
287static enum yac_cell_type get_cell_type(struct yac_grid_cell cell) {
288
289 if (cell.num_corners == 0) return YAC_GREAT_CIRCLE_CELL;
290
291 enum yac_cell_type cell_type = YAC_MIXED_CELL;
292
293 // if the cell is a typical lon-lat cell
294 if ((cell.num_corners == 4) &&
295 ((cell.edge_type[0] == YAC_LAT_CIRCLE_EDGE &&
296 cell.edge_type[1] == YAC_LON_CIRCLE_EDGE &&
297 cell.edge_type[2] == YAC_LAT_CIRCLE_EDGE &&
298 cell.edge_type[3] == YAC_LON_CIRCLE_EDGE) ||
299 (cell.edge_type[0] == YAC_LON_CIRCLE_EDGE &&
300 cell.edge_type[1] == YAC_LAT_CIRCLE_EDGE &&
301 cell.edge_type[2] == YAC_LON_CIRCLE_EDGE &&
302 cell.edge_type[3] == YAC_LAT_CIRCLE_EDGE))) {
303
304 cell_type = YAC_LON_LAT_CELL;
305
306 } else {
307
308 size_t count_lat_edges = 0, count_great_circle_edges = 0;
309
310 // count the number of edges for each type
311 // (lon edges are counted as gc ones)
312 for (size_t i = 0; i < cell.num_corners; ++i)
313 if (cell.edge_type[i] == YAC_LON_CIRCLE_EDGE ||
315 count_great_circle_edges++;
316 else
317 count_lat_edges++;
318
319 // if the cell is a lon lat cell with one lat edge having a length of zero
320 // due to being at a pole
321 if ((count_lat_edges == 1) && (count_great_circle_edges == 2)) {
322
323 size_t i;
324 for (i = 0; i < 3; ++i) if (cell.edge_type[i] == YAC_LAT_CIRCLE_EDGE) break;
325 size_t pol_index = (3 + i - 1) % 3;
326 if (fabs(fabs(cell.coordinates_xyz[pol_index][2])-1.0) <
328
329 // if the cell only consists of great circle edges
330 } else if (count_lat_edges == 0) cell_type = YAC_GREAT_CIRCLE_CELL;
331
332 // if the cell only consists of lat circle edges
333 else if (count_great_circle_edges == 0) cell_type = YAC_LAT_CELL;
334 }
335
337 cell_type != YAC_MIXED_CELL,
338 "invalid cell type (cell contains edges consisting "
339 "of great circles and circles of latitude)")
340
341 return cell_type;
342}
343
344int yac_circle_compare(void const * a, void const * b) {
345
346 struct yac_circle const * circle_a = *(struct yac_circle const **)a;
347 struct yac_circle const * circle_b = *(struct yac_circle const **)b;
348
350 ((circle_a->type == GREAT_CIRCLE) ||
351 (circle_a->type == LON_CIRCLE) ||
352 (circle_a->type == LAT_CIRCLE)/* ||
353 (circle_a->type == POINT)*/) &&
354 ((circle_b->type == GREAT_CIRCLE) ||
355 (circle_b->type == LON_CIRCLE) ||
356 (circle_b->type == LAT_CIRCLE)/* ||
357 (circle_b->type == POINT)*/),
358 "ERROR(yac_circle_compare): unsupported circle type")
359
360 // put lat circles to the end
361 int ret = (circle_a->type == LAT_CIRCLE) - (circle_b->type == LAT_CIRCLE);
362 if (!ret) ret = (int)(circle_a->type) - (int)(circle_b->type);
363 if (!ret) {
364 switch (circle_a->type) {
365 default:
366 case (GREAT_CIRCLE):
367 for (int i = 0; !ret && (i < 3); ++i) {
368 ret =
369 (circle_a->data.gc.norm_vector[i] >
370 circle_b->data.gc.norm_vector[i]) -
371 (circle_a->data.gc.norm_vector[i] <
372 circle_b->data.gc.norm_vector[i]);
373 }
374 break;
375 case (LON_CIRCLE):
376 for (int i = 0; !ret && (i < 3); ++i) {
377 ret =
378 (circle_a->data.lon.norm_vector[i] >
379 circle_b->data.lon.norm_vector[i]) -
380 (circle_a->data.lon.norm_vector[i] <
381 circle_b->data.lon.norm_vector[i]);
382 }
383 break;
384 case (LAT_CIRCLE):
385 ret = circle_a->data.lat.north_is_out - circle_b->data.lat.north_is_out;
386 if (!ret)
387 ret = (circle_a->data.lat.z > circle_b->data.lat.z) -
388 (circle_a->data.lat.z < circle_b->data.lat.z);
389 break;
390 // case (POINT):
391 // for (int i = 0; !ret && (i < 3); ++i)
392 // ret = (circle_a->data.p.vec[i] > circle_b->data.p.vec[i]) -
393 // (circle_a->data.p.vec[i] < circle_b->data.p.vec[i]);
394 // break;
395 }
396 }
397
398 return ret;
399}
400
401
403 double const a[3], double const b[3], double norm_vector[3]) {
404
406
407 double scale = 1.0 / sqrt(norm_vector[0] * norm_vector[0] +
408 norm_vector[1] * norm_vector[1] +
409 norm_vector[2] * norm_vector[2]);
410 norm_vector[0] *= scale;
411 norm_vector[1] *= scale;
412 norm_vector[2] *= scale;
413}
414
416 double const * a, double const * b, enum yac_edge_type type,
417 int edge_ordering, struct yac_circle * circle) {
418
419 if (points_are_identically(a, b)) {
420 circle->type = POINT;
421 circle->data.p.vec[0] = a[0];
422 circle->data.p.vec[1] = a[1];
423 circle->data.p.vec[2] = a[2];
424 } else {
425
426 // switch edges to ensure that "inside/outside" of the circle is computed
427 // correctly
428 if (edge_ordering < 0) {
429 double const * temp = a;
430 a = b;
431 b = temp;
432 }
433
438 "ERROR(yac_circle_generate): invalid edge type")
439
440 switch (type) {
441 default:
443 circle->type = GREAT_CIRCLE;
445 break;
447 circle->type = LON_CIRCLE;
449 break;
451 circle->type = LAT_CIRCLE;
452 circle->data.lat.north_is_out = (a[0] * b[1] - a[1] * b[0]) < 0.0;
453 if (circle->data.lat.north_is_out == 1337) exit(EXIT_FAILURE);
454 circle->data.lat.z = a[2];
455 break;
456 }
457 }
458}
459
460static inline struct yac_circle
462
463 struct yac_circle circle = {
464 .type = LAT_CIRCLE,
465 .data.lat.north_is_out = north_is_out,
466 .data.lat.z = z
467 };
468 return circle;
469}
470
472 double const point[3], struct yac_circle * circle) {
473
475 (circle->type == GREAT_CIRCLE) ||
476 (circle->type == LON_CIRCLE) ||
477 (circle->type == LAT_CIRCLE)/* ||
478 (circle->type == POINT)*/,
479 "ERROR(yac_circle_point_is_inside): unsupported circle type")
480
481 switch (circle->type) {
482 default:
483 case (GREAT_CIRCLE): {
484 double dot = point[0] * circle->data.gc.norm_vector[0] +
485 point[1] * circle->data.gc.norm_vector[1] +
486 point[2] * circle->data.gc.norm_vector[2];
487 if (dot < (- yac_angle_tol * 1e-3)) return 0;
488 else if (dot > (+ yac_angle_tol * 1e-3)) return 1;
489 else return 2;
490 }
491 case (LON_CIRCLE): {
492 double dot = point[0] * circle->data.lon.norm_vector[0] +
493 point[1] * circle->data.lon.norm_vector[1] +
494 point[2] * circle->data.lon.norm_vector[2];
495 if (dot < (- yac_angle_tol * 1e-3)) return 0;
496 else if (dot > (+ yac_angle_tol * 1e-3)) return 1;
497 else return 2;
498 }
499 case (LAT_CIRCLE): {
500 double diff_z = circle->data.lat.z - point[2];
501 if (fabs(diff_z) < yac_angle_tol * 1e-3) return 2;
502 else return (diff_z < 0.0) ^ circle->data.lat.north_is_out;
503 }
504 // case (POINT):
505 // return points_are_identically(point, circle->data.p.vec)?2:0;
506 }
507}
508
510 double const a[3], double const b[3], struct yac_circle * circle) {
511
513 (circle->type == GREAT_CIRCLE) ||
514 (circle->type == LON_CIRCLE) ||
515 (circle->type == LAT_CIRCLE) ||
516 (circle->type == POINT),
517 "ERROR(yac_circle_compare_distances): invalid circle type")
518
519 double dist_a, dist_b;
520 switch (circle->type) {
521 default:
522 case(GREAT_CIRCLE): {
523 double norm_vector[3] = {circle->data.gc.norm_vector[0],
524 circle->data.gc.norm_vector[1],
525 circle->data.gc.norm_vector[2]};
526 dist_a = fabs(a[0] * norm_vector[0] +
527 a[1] * norm_vector[1] +
528 a[2] * norm_vector[2]);
529 dist_b = fabs(b[0] * norm_vector[0] +
530 b[1] * norm_vector[1] +
531 b[2] * norm_vector[2]);
532 break;
533 }
534 case(LON_CIRCLE): {
535 double norm_vector[3] = {circle->data.lon.norm_vector[0],
536 circle->data.lon.norm_vector[1],
537 circle->data.lon.norm_vector[2]};
538 dist_a = fabs(a[0] * norm_vector[0] +
539 a[1] * norm_vector[1] +
540 a[2] * norm_vector[2]);
541 dist_b = fabs(b[0] * norm_vector[0] +
542 b[1] * norm_vector[1] +
543 b[2] * norm_vector[2]);
544 break;
545 }
546 case(LAT_CIRCLE): {
547 double circle_lat = acos(circle->data.lat.z);
548 dist_a = fabs(circle_lat - acos(a[2]));
549 dist_b = fabs(circle_lat - acos(b[2]));
550 break;
551 }
552 case(POINT): {
553 dist_a = get_vector_angle(circle->data.p.vec, a);
554 dist_b = get_vector_angle(circle->data.p.vec, b);
555 break;
556 }
557 }
558
559 return (dist_a > dist_b + yac_angle_tol) -
560 (dist_a + yac_angle_tol < dist_b);
561}
562
564
566 (circle->type == GREAT_CIRCLE) ||
567 (circle->type == LAT_CIRCLE) ||
568 (circle->type == LON_CIRCLE),
569 "ERROR(yac_circle_contains_north_pole): circle type has to be either "
570 "GREAT_CIRCLE or LAT_CIRCLE")
571
572 switch (circle->type) {
573 default:
574 case (GREAT_CIRCLE):
575 return circle->data.gc.norm_vector[2] > 0.0;
576 case (LAT_CIRCLE):
577 return !circle->data.lat.north_is_out;
578 case (LON_CIRCLE):
579 return 0;
580 }
581}
582
586static void circle_clipping(
587 struct point_list * cell, size_t num_cell_edges,
588 struct yac_circle ** clipping_circles, size_t num_clipping_circles) {
589
590 // to avoid some problems that can occur close the the pole, we process the
591 // target lat-circle edges at the end
592 qsort(clipping_circles, num_clipping_circles, sizeof(*clipping_circles),
594
595 // for all clipping circles
596 for (size_t i = 0; (i < num_clipping_circles) && (num_cell_edges > 1); ++i) {
597
598 struct point_list_element * cell_edge_start = cell->start;
599 struct point_list_element * cell_edge_end = cell_edge_start->next;
600
601 struct yac_circle * clipping_circle = clipping_circles[i];
602
603 int start_is_inside, first_start_is_inside;
604
605 start_is_inside =
607 cell_edge_start->vec_coords, clipping_circle);
608 first_start_is_inside = start_is_inside;
609
610 // for all edges of the cell
611 for (size_t cell_edge_idx = 0; cell_edge_idx < num_cell_edges;
612 ++cell_edge_idx) {
613
614 int end_is_inside =
615 (cell_edge_idx != num_cell_edges - 1)?
617 cell_edge_end->vec_coords, clipping_circle)):first_start_is_inside;
618
619 double * cell_edge_coords[2] =
620 {cell_edge_start->vec_coords, cell_edge_end->vec_coords};
621 struct yac_circle * cell_edge_circle = cell_edge_start->edge_circle;
622
623 double intersection[2][3];
624 int num_edge_intersections = -1;
625
626 // One intersection between the clipping circle and the cell edge is
627 // possible, if either the start or the end vertex of the current cell
628 // edge is inside and the respective other one is outside.
629 // Two intersections are possible, if either the clipping circle or the
630 // cell edge is a circle of latitude, while this other is not.
631 // Additionally, this is not possible if one of the two cell edge
632 // vertices is inside while the other is not or if both cell edge
633 // vertices are on the plane of the clipping edge.
634 int one_intersect_expected = (end_is_inside + start_is_inside == 1);
635 int two_intersect_possible =
636 ((cell_edge_circle->type == LAT_CIRCLE) ^
637 (clipping_circle->type == LAT_CIRCLE)) &&
638 (end_is_inside + start_is_inside != 1) &&
639 (end_is_inside + start_is_inside != 4);
640
641 // if we need to check for intersections
642 if (one_intersect_expected || two_intersect_possible) {
643
644 // get intersection points between the clipping circle and the circle
645 // of the cell edge
646 int num_circle_intersections =
648 *clipping_circle, *cell_edge_circle,
649 intersection[0], intersection[1]);
650
652 (num_circle_intersections >= -1) && (num_circle_intersections <= 2),
653 "ERROR(circle_clipping): invalid number of intersections")
654
655 // determine the intersections of the clipping circle with the cell
656 // edge based on the circle intersections
657 switch (num_circle_intersections) {
658
659 // special case:
660 // both circles are on the same plane
661 case (-1): {
662
663 // MoHa: this part of the code should not be reachable...but I
664 // leave it just in case...
665 start_is_inside = 2;
666 end_is_inside = 2;
667 num_edge_intersections = 0;
668
669 one_intersect_expected = 0;
670
671 // if this is the first iteration
672 if (cell_edge_idx == 0) first_start_is_inside = 2;
673 break;
674 }
675 // special case:
676 // no intersections between the two circles
677 // (can occure if one of the two circles is a latitude circle while
678 // the other is a great circle)
679 case (0): {
680 num_edge_intersections = 0;
681 break;
682 }
683 // standart case:
684 // two intersections between the two circles
685 // (one intersection between two circles is a special case, but is
686 // being handled here anyway)
687 default:
688 case (1):
689 case (2): {
690
691 // check the relation between the intersection points and the
692 // cell edge
693 int is_on_edge[2] = {
695 intersection[0], cell_edge_coords[0], cell_edge_coords[1],
696 cell_edge_circle->type),
697 (num_circle_intersections == 2)?
699 intersection[1], cell_edge_coords[0], cell_edge_coords[1],
700 cell_edge_circle->type):0};
701
702 // if both intersection points are on the edge
703 if (is_on_edge[0] && is_on_edge[1]) {
704
705 // if only one intersection was expected
707 !one_intersect_expected,
708 "ERROR: two intersections found, even "
709 "though no circle of latitude involed and "
710 "both edge vertices on different sides of "
711 "the cutting plane.\n"
712 "cell edge (%lf %lf %lf) (%lf %lf %lf) (edge type %d)\n"
713 "circle (gc: norm_vec %lf %lf %lf\n"
714 " lon: norm_vec %lf %lf %lf\n"
715 " lat: z %lf north_is_out %d\n"
716 " point: vec %lf %lf %lf) (circle type %d)\n"
717 "intersections points (%lf %lf %lf) (%lf %lf %lf)\n",
718 cell_edge_coords[0][0],
719 cell_edge_coords[0][1],
720 cell_edge_coords[0][2],
721 cell_edge_coords[1][0],
722 cell_edge_coords[1][1],
723 cell_edge_coords[1][2], (int)cell_edge_circle->type,
724 clipping_circle->data.gc.norm_vector[0],
725 clipping_circle->data.gc.norm_vector[1],
726 clipping_circle->data.gc.norm_vector[2],
727 clipping_circle->data.lon.norm_vector[0],
728 clipping_circle->data.lon.norm_vector[1],
729 clipping_circle->data.lon.norm_vector[2],
730 clipping_circle->data.lat.z,
731 clipping_circle->data.lat.north_is_out,
732 clipping_circle->data.p.vec[0],
733 clipping_circle->data.p.vec[1],
734 clipping_circle->data.p.vec[2], (int)(clipping_circle->type),
735 intersection[0][0], intersection[0][1], intersection[0][2],
736 intersection[1][0], intersection[1][1], intersection[1][2])
737
738 // if both cell edge vertices are on the same side of the
739 // clipping edge
740 if (end_is_inside == start_is_inside) {
741
742 // if the two intersection points are basically the same point
743 if (points_are_identically(intersection[0], intersection[1])) {
744
745 num_edge_intersections = 1;
746
747 } else {
748
749 // if the first intersection point is further away from the
750 // cell start edge vertex than the second one ->
751 // switch them
752 if (sq_len_diff_vec(cell_edge_coords[0], intersection[0]) >
753 sq_len_diff_vec(cell_edge_coords[0], intersection[1])) {
754
755 double temp_intersection[3];
756 temp_intersection[0] = intersection[1][0];
757 temp_intersection[1] = intersection[1][1];
758 temp_intersection[2] = intersection[1][2];
759 intersection[1][0] = intersection[0][0];
760 intersection[1][1] = intersection[0][1];
761 intersection[1][2] = intersection[0][2];
762 intersection[0][0] = temp_intersection[0];
763 intersection[0][1] = temp_intersection[1];
764 intersection[0][2] = temp_intersection[2];
765 }
766
767 num_edge_intersections = 2;
768 }
769
770 // one of the two cell edge vertices is on the clipping circle
771 // => one of the two intersection points must be more or less
772 // identical to a vertex of the cell edge
773 } else {
774
775 double * cell_edge_coord = cell_edge_coords[end_is_inside == 2];
776 double distances[2] = {
777 sq_len_diff_vec(cell_edge_coord, intersection[0]),
778 sq_len_diff_vec(cell_edge_coord, intersection[1])};
779
780 // if both intersection points are nearly identical to the cell
781 // edge vertex
782 if ((distances[0] < yac_sq_angle_tol) &&
783 (distances[1] < yac_sq_angle_tol)) {
784
785 num_edge_intersections = 0;
786
787 } else {
788
789 num_edge_intersections = 1;
790
791 // if the fist intersection points is closer than the second
792 if (distances[0] < distances[1]) {
793 intersection[0][0] = intersection[1][0];
794 intersection[0][1] = intersection[1][1];
795 intersection[0][2] = intersection[1][2];
796 }
797 }
798 }
799 // if only one intersection point is on the cell edge
800 } else if (is_on_edge[0] || is_on_edge[1]) {
801
802 // if one of the two cell edge vertices is on the clipping edge
803 if ((end_is_inside == 2) || (start_is_inside == 2)) {
804
805 // we assume that the intersection point is the respective
806 // cell edge vertex, which is on the clipping edge -> we do not
807 // need this intersection point
808 num_edge_intersections = 0;
809
810 } else {
811
812 // if the second intersection point is on the cell edge
813 if (is_on_edge[1]) {
814 intersection[0][0] = intersection[1][0];
815 intersection[0][1] = intersection[1][1];
816 intersection[0][2] = intersection[1][2];
817 }
818
819 num_edge_intersections = 1;
820 }
821
822 // if none of the two intersection points is on the cell edge
823 } else {
824 num_edge_intersections = 0;
825 }
826 break;
827 } // case one or two circle intersections
828 } // switch (num_circle_intersections)
829
830 // If an intersection was expected but none was found, the clipping
831 // circle was most propably to close to an edge vertex. We can now
832 // assume that the respective vertex is directly on the clipping circle.
833 if ((one_intersect_expected) && (num_edge_intersections == 0)) {
834
836 cell_edge_coords[0], cell_edge_coords[1],
837 clipping_circle) <= 0)
838 start_is_inside = 2;
839 else
840 end_is_inside = 2;
841
842 one_intersect_expected = 0;
843
844 // if this is the first iteration
845 if (cell_edge_idx == 0) first_start_is_inside = start_is_inside;
846 }
847 // else -> not edge intersection was excepted
848 } else {
849 num_edge_intersections = 0;
850 }
851
853 num_edge_intersections != -1,
854 "ERROR(circle_clipping): internal error");
855
856 // here we know the number of intersections and their location and we
857 // know the relation of the cell edge vertices to the clipping edge
858 // (start_is_inside and end_is_inside)
859
860 // if the start cell edge vertex is outside -> dump it after clipping
861 // is finished
862 cell_edge_start->to_be_removed = start_is_inside == 0;
863
864 // the easiest case is that we expected one intersection and got one
865 if (one_intersect_expected) {
866
867 // insert an intersection point in the cell point list in the
868 // current edge
869 struct point_list_element * intersect_point =
871 cell_edge_start->next = intersect_point;
872 intersect_point->next = cell_edge_end;
873
874 intersect_point->vec_coords[0] = intersection[0][0];
875 intersect_point->vec_coords[1] = intersection[0][1];
876 intersect_point->vec_coords[2] = intersection[0][2];
877
878 intersect_point->edge_circle =
879 (start_is_inside)?clipping_circle:cell_edge_circle;
880
881 // if the clipping edge goes through both of the two cell edge vertices
882 } else if ((start_is_inside == 2) && (end_is_inside == 2)) {
883
884 // if one of the two edges is a circle of latitude while the other is
885 // not, then we may have to replace the cell edge circle with the
886 // clipping circle
887 if ((cell_edge_circle->type == LAT_CIRCLE) ^
888 (clipping_circle->type == LAT_CIRCLE)) {
889
890 int clipping_circle_contains_north =
891 yac_circle_contains_north_pole(clipping_circle);
892 int same_inside_direction =
893 clipping_circle_contains_north ==
894 yac_circle_contains_north_pole(cell_edge_circle);
895 int cell_edge_is_on_south_hemisphere =
896 (cell_edge_end->vec_coords[2] < 0.0);
897 int clipping_circle_is_lat = clipping_circle->type == LAT_CIRCLE;
898
899 // after generating a truth table with these four logical values
900 // I came up with the following formula to determine whether
901 // the cell edge type should switch to the one of the clipping circle
902 // or not
903 if (same_inside_direction &&
904 (cell_edge_is_on_south_hemisphere ^
905 clipping_circle_contains_north ^
906 clipping_circle_is_lat))
907 cell_edge_start->edge_circle = clipping_circle;
908
909 }
910
911 // if we have no intersection, but the cell edge start vertex
912 // is on the clipping edge
913 } else if ((num_edge_intersections == 0) && (start_is_inside == 2)) {
914
915 // if the end cell edge vertex is outside
916 if (end_is_inside == 0)
917 cell_edge_start->edge_circle = clipping_circle;
918
919 // if we have two intersections (only happens if one of the two edges is
920 // a circle of latitude while the other is not)
921 } else if (num_edge_intersections == 2) {
922
923 struct point_list_element * intersect_points[2] =
926
927 // add two points between the current source edge vertices
928 cell_edge_start->next = intersect_points[0];
929 intersect_points[0]->next = intersect_points[1];
930 intersect_points[1]->next = cell_edge_end;
931
932 intersect_points[0]->vec_coords[0] = intersection[0][0];
933 intersect_points[0]->vec_coords[1] = intersection[0][1];
934 intersect_points[0]->vec_coords[2] = intersection[0][2];
935 intersect_points[1]->vec_coords[0] = intersection[1][0];
936 intersect_points[1]->vec_coords[1] = intersection[1][1];
937 intersect_points[1]->vec_coords[2] = intersection[1][2];
938
940 ((start_is_inside == 0) && (end_is_inside == 0)) ||
941 ((start_is_inside == 1) && (end_is_inside == 1)),
942 "ERROR: one cell edge vertex is on the clipping edge, therefore we "
943 "should not have two intersections.")
944
945 // if a and b are outside
946 if ((start_is_inside == 0) && (end_is_inside == 0)) {
947 intersect_points[0]->edge_circle = cell_edge_circle;
948 intersect_points[1]->edge_circle = clipping_circle;
949
950 // if a and b are inside
951 } else /*if ((start_is_inside == 1) && (end_is_inside == 1))*/ {
952 intersect_points[0]->edge_circle = clipping_circle;
953 intersect_points[1]->edge_circle = cell_edge_circle;
954 }
955
956 // if we have one intersection even though the two cell edge vertices
957 // are not on opposite sides of the clipping edge
958 } else if (two_intersect_possible && (num_edge_intersections == 1)) {
959
960 // ensure that both cell edge vertices are on the same side of the
961 // clipping edge or that at least one cell vertex is directly on
962 // the clipping edge
964 (start_is_inside == end_is_inside) ||
965 ((start_is_inside == 2) || (end_is_inside == 2)),
966 "ERROR: unhandled intersection case")
967
968 switch (MAX(start_is_inside, end_is_inside)) {
969
970 // if both cell edge vertices are outside -> circle of latitude and
971 // greate circle touch at a single vertex
972 default:
973 case (0): {
974 // insert an intersection point in the cell point list in the
975 // current edge
976 struct point_list_element * intersect_point =
978 cell_edge_start->next = intersect_point;
979 intersect_point->next = cell_edge_end;
980
981 intersect_point->vec_coords[0] = intersection[0][0];
982 intersect_point->vec_coords[1] = intersection[0][1];
983 intersect_point->vec_coords[2] = intersection[0][2];
984
985 intersect_point->edge_circle = clipping_circle;
986 break;
987 }
988
989 // if both cell edge vertices are inside -> nothing to be done
990 case (1): break;
991
992 // if one of the two cell edge vertices is on the clipping edge
993 // while the other is either inside or outside
994 case (2): {
995 // insert an intersection point in the cell point list in the
996 // current edge
997 struct point_list_element * intersect_point =
999 cell_edge_start->next = intersect_point;
1000 intersect_point->next = cell_edge_end;
1001
1002 intersect_point->vec_coords[0] = intersection[0][0];
1003 intersect_point->vec_coords[1] = intersection[0][1];
1004 intersect_point->vec_coords[2] = intersection[0][2];
1005
1006 // if the start cell edge vertex is on the clipping edge
1007 if (start_is_inside == 2) {
1008 // if the end cell edge vertex in on the outside
1009 if (end_is_inside == 0) {
1010 // cell_edge_start->edge_circle = cell_edge_circle;
1011 intersect_point->edge_circle = clipping_circle;
1012 } else {
1013 cell_edge_start->edge_circle = clipping_circle;
1014 intersect_point->edge_circle = cell_edge_circle;
1015 }
1016 // if the end cell edge vertex is on the clipping edge
1017 } else {
1018 // if the start cell edge vertex in on the outside
1019 if (start_is_inside == 0) {
1020 cell_edge_start->edge_circle = clipping_circle;
1021 intersect_point->edge_circle = cell_edge_circle;
1022 } else {
1023 // cell_edge_start->edge_circle = cell_edge_circle;
1024 intersect_point->edge_circle = clipping_circle;
1025 }
1026 }
1027 }
1028 }
1029 }
1030
1031 cell_edge_start = cell_edge_end;
1032 cell_edge_end = cell_edge_end->next;
1033 start_is_inside = end_is_inside;
1034
1035 } // for all cell edges
1036
1037 // remove all points that are to be deleted
1038 num_cell_edges = remove_points(cell);
1039 }
1040}
1041
1043 struct point_list * source_list, struct point_list target_list, size_t nct) {
1044
1045 struct yac_circle * clipping_circles[nct];
1046
1047 struct point_list_element * curr_tgt_point = target_list.start;
1048
1049 for (size_t i = 0; i < nct; ++i, curr_tgt_point = curr_tgt_point->next)
1050 clipping_circles[i] = curr_tgt_point->edge_circle;
1051
1052 YAC_ASSERT(
1053 source_list->start != NULL,
1054 "ERROR(point_list_clipping): source cell without corners")
1055
1056 // count the number of edges in the source cell
1057 size_t ncs = 1;
1058 for (struct point_list_element * curr = source_list->start->next,
1059 * end = source_list->start;
1060 curr != end; curr = curr->next, ++ncs);
1061
1062 circle_clipping(source_list, ncs, clipping_circles, nct);
1063}
1064
1065static void copy_point_list(struct point_list in, struct point_list * out) {
1066
1067 reset_point_list(out);
1068
1069 struct point_list_element * curr = in.start;
1070
1071 if (curr == NULL) return;
1072
1073 struct point_list_element * new_point_list = get_free_point_list_element(out);
1074 out->start = new_point_list;
1075 *new_point_list = *curr;
1076 curr = curr->next;
1077
1078 do {
1079
1080 new_point_list->next = get_free_point_list_element(out);
1081 new_point_list = new_point_list->next;
1082 *new_point_list = *curr;
1083 curr = curr->next;
1084
1085 } while (curr != in.start);
1086
1087 new_point_list->next = out->start;
1088}
1089
1090void yac_cell_clipping (size_t N,
1091 struct yac_grid_cell * source_cell,
1092 struct yac_grid_cell target_cell,
1093 struct yac_grid_cell * overlap_buffer) {
1094
1095 if (target_cell.num_corners < 2) {
1096 for (size_t n = 0; n < N; n++ ) overlap_buffer[n].num_corners = 0;
1097 return;
1098 }
1099
1100 enum yac_cell_type tgt_cell_type = get_cell_type(target_cell);
1101
1102 YAC_ASSERT(
1103 tgt_cell_type != YAC_MIXED_CELL,
1104 "invalid target cell type (cell contains edges consisting "
1105 "of great circles and circles of latitude)")
1106
1107 // determine ordering of target cell corners
1108 int target_ordering = get_cell_points_ordering(target_cell);
1109 // if all corners of the target cell are on the same great circle
1110 if (!target_ordering) {
1111 for (size_t n = 0; n < N; n++ ) overlap_buffer[n].num_corners = 0;
1112 return;
1113 }
1114
1115 size_t max_num_src_cell_corners = 0;
1116 for (size_t n = 0; n < N; ++n)
1117 if (source_cell[n].num_corners > max_num_src_cell_corners)
1118 max_num_src_cell_corners = source_cell[n].num_corners;
1119 struct yac_circle * circle_buffer =
1120 xmalloc(
1121 (target_cell.num_corners + max_num_src_cell_corners) *
1122 sizeof(*circle_buffer));
1123 struct yac_circle * src_circle_buffer =
1124 circle_buffer + target_cell.num_corners;
1125
1126 // generate point list for target cell (clip cell)
1127 struct point_list target_list;
1128 init_point_list(&target_list);
1129 size_t nct =
1131 &target_list, target_cell, target_ordering, circle_buffer);
1132
1133 struct point_list source_list, temp_list;
1134 init_point_list(&temp_list);
1135 init_point_list(&source_list);
1136
1137 // for all source cells
1138 for (size_t n = 0; n < N; n++ ) {
1139
1140 overlap_buffer[n].num_corners = 0;
1141
1142 enum yac_cell_type src_cell_type = get_cell_type(source_cell[n]);
1143
1144 YAC_ASSERT(
1145 src_cell_type != YAC_MIXED_CELL,
1146 "invalid source cell type (cell contains edges consisting "
1147 "of great circles and circles of latitude)")
1148
1149 if (source_cell[n].num_corners < 2) continue;
1150
1151 // determine ordering of source cell corners
1152 int source_ordering = get_cell_points_ordering(source_cell[n]);
1153
1154 // if all corners of the source cell are on the same great circle
1155 if (!source_ordering) continue;
1156
1157 // generate point list for current source list
1158 size_t ncs =
1160 &source_list, source_cell[n], source_ordering, src_circle_buffer);
1161
1162 struct point_list * overlap;
1163 double fabs_tgt_coordinate_z = fabs(target_cell.coordinates_xyz[0][2]);
1164 double fabs_src_coordinate_z = fabs(source_cell[n].coordinates_xyz[0][2]);
1165
1166 // in the case that source and target cell are both YAC_LAT_CELL's, than the
1167 // bigger one has to be the target cell
1168 // a similar problem occurs when the target cell is a YAC_LAT_CELL and the
1169 // source is a YAC_GREAT_CIRCLE_CELL which overlaps with the pole that is also
1170 // include in the target cell
1171 if (((tgt_cell_type == YAC_LAT_CELL) && (src_cell_type == YAC_GREAT_CIRCLE_CELL)) ||
1172 ((tgt_cell_type == YAC_LAT_CELL) && (src_cell_type == YAC_LAT_CELL) &&
1173 (fabs_tgt_coordinate_z > fabs_src_coordinate_z))) {
1174
1175 copy_point_list(target_list, &temp_list);
1176
1177 point_list_clipping(&temp_list, source_list, ncs);
1178
1179 overlap = &temp_list;
1180
1181 } else {
1182
1183 point_list_clipping(&source_list, target_list, nct);
1184
1185 overlap = &source_list;
1186 }
1187
1188 generate_cell(overlap, overlap_buffer + n);
1189
1190 }
1191 free(circle_buffer);
1192 free_point_list(&source_list);
1193 free_point_list(&target_list);
1194 free_point_list(&temp_list);
1195}
1196
1198 struct yac_grid_cell * cell, double z_upper_bound, double z_lower_bound,
1199 struct yac_grid_cell * overlap_buffer) {
1200
1201 double cell_upper_bound = cell->coordinates_xyz[0][2];
1202 double cell_lower_bound = cell->coordinates_xyz[2][2];
1203
1204 int upper_idx[2], lower_idx[2];
1205
1206 if (cell_upper_bound < cell_lower_bound) {
1207 double temp = cell_upper_bound;
1208 cell_upper_bound = cell_lower_bound;
1209 cell_lower_bound = temp;
1210 if (cell->edge_type[0] == YAC_LAT_CIRCLE_EDGE) {
1211 upper_idx[0] = 2;
1212 upper_idx[1] = 3;
1213 lower_idx[0] = 1;
1214 lower_idx[1] = 0;
1215 } else {
1216 upper_idx[0] = 2;
1217 upper_idx[1] = 1;
1218 lower_idx[0] = 3;
1219 lower_idx[1] = 0;
1220 }
1221 } else {
1222 if (cell->edge_type[0] == YAC_LAT_CIRCLE_EDGE) {
1223 upper_idx[0] = 0;
1224 upper_idx[1] = 1;
1225 lower_idx[0] = 3;
1226 lower_idx[1] = 2;
1227 } else {
1228 upper_idx[0] = 0;
1229 upper_idx[1] = 3;
1230 lower_idx[0] = 1;
1231 lower_idx[1] = 2;
1232 }
1233 }
1234
1235 // if z_upper_bound and z_lower_bound are identical or
1236 // if cell does not overlap with latitude band
1237 if ((z_upper_bound == z_lower_bound) ||
1238 (cell_upper_bound <= z_lower_bound) ||
1239 (cell_lower_bound >= z_upper_bound)) {
1240 overlap_buffer->num_corners = 0;
1241 return;
1242 }
1243
1244 if (overlap_buffer->array_size < 4) {
1245 overlap_buffer->coordinates_xyz =
1246 xmalloc(4 * sizeof(*(overlap_buffer->coordinates_xyz)));
1247 overlap_buffer->edge_type =
1248 xmalloc(4 * sizeof(*(overlap_buffer->edge_type)));
1249 overlap_buffer->array_size = 4;
1250 }
1251
1252 memcpy(overlap_buffer->coordinates_xyz, cell->coordinates_xyz,
1253 4 * sizeof(*(cell->coordinates_xyz)));
1254 memcpy(overlap_buffer->edge_type, cell->edge_type,
1255 4 * sizeof(*(cell->edge_type)));
1256 overlap_buffer->num_corners = 4;
1257
1258
1259 double tmp_scale;
1260 double * p[2];
1261 if (fabs(cell_lower_bound) < fabs(cell_upper_bound)) {
1262 p[0] = cell->coordinates_xyz[lower_idx[0]];
1263 p[1] = cell->coordinates_xyz[lower_idx[1]];
1264 tmp_scale = cell->coordinates_xyz[lower_idx[0]][0] *
1265 cell->coordinates_xyz[lower_idx[0]][0] +
1266 cell->coordinates_xyz[lower_idx[0]][1] *
1267 cell->coordinates_xyz[lower_idx[0]][1];
1268 } else {
1269 p[0] = cell->coordinates_xyz[upper_idx[0]];
1270 p[1] = cell->coordinates_xyz[upper_idx[1]];
1271 tmp_scale = cell->coordinates_xyz[upper_idx[0]][0] *
1272 cell->coordinates_xyz[upper_idx[0]][0] +
1273 cell->coordinates_xyz[upper_idx[0]][1] *
1274 cell->coordinates_xyz[upper_idx[0]][1];
1275 }
1276
1277 // if upper bound overlaps with cell
1278 if ((z_upper_bound < cell_upper_bound) &&
1279 (z_upper_bound > cell_lower_bound)) {
1280
1281 double scale = sqrt((1.0 - z_upper_bound * z_upper_bound) / tmp_scale);
1282
1283 overlap_buffer->coordinates_xyz[upper_idx[0]][0] = p[0][0] * scale;
1284 overlap_buffer->coordinates_xyz[upper_idx[0]][1] = p[0][1] * scale;
1285 overlap_buffer->coordinates_xyz[upper_idx[0]][2] = z_upper_bound;
1286 overlap_buffer->coordinates_xyz[upper_idx[1]][0] = p[1][0] * scale;
1287 overlap_buffer->coordinates_xyz[upper_idx[1]][1] = p[1][1] * scale;
1288 overlap_buffer->coordinates_xyz[upper_idx[1]][2] = z_upper_bound;
1289 }
1290
1291 // if lower bound overlaps with cell
1292 if ((z_lower_bound < cell_upper_bound) &&
1293 (z_lower_bound > cell_lower_bound)) {
1294
1295 double scale = sqrt((1.0 - z_lower_bound * z_lower_bound) / tmp_scale);
1296
1297 overlap_buffer->coordinates_xyz[lower_idx[0]][0] = p[0][0] * scale;
1298 overlap_buffer->coordinates_xyz[lower_idx[0]][1] = p[0][1] * scale;
1299 overlap_buffer->coordinates_xyz[lower_idx[0]][2] = z_lower_bound;
1300 overlap_buffer->coordinates_xyz[lower_idx[1]][0] = p[1][0] * scale;
1301 overlap_buffer->coordinates_xyz[lower_idx[1]][1] = p[1][1] * scale;
1302 overlap_buffer->coordinates_xyz[lower_idx[1]][2] = z_lower_bound;
1303 }
1304}
1305
1306static double get_closest_pole(struct point_list * cell_list) {
1307
1308 struct point_list_element * curr = cell_list->start;
1309 struct point_list_element * start = cell_list->start;
1310
1311 if (curr == NULL) return 1.0;
1312
1313 double max_z = 0.0;
1314
1315 do {
1316
1317 double curr_z = curr->vec_coords[2];
1318 if (fabs(curr_z) > fabs(max_z)) max_z = curr_z;
1319
1320 curr = curr->next;
1321 } while (curr != start);
1322
1323 return (max_z > 0.0)?1.0:-1.0;
1324}
1325
1326/*this routine is potentially being used in the CDO*/
1328 struct yac_grid_cell * cells,
1329 double lat_bounds[2], // lat in rad
1330 struct yac_grid_cell * overlap_buffer) {
1331
1332 double z_bounds[2] = {sin(lat_bounds[0]), sin(lat_bounds[1])};
1333 int upper_bound_idx = lat_bounds[0] < lat_bounds[1];
1334 int lower_bound_idx = upper_bound_idx ^ 1;
1335 int is_pole[2] = {fabs(fabs(lat_bounds[0]) - M_PI_2) < yac_angle_tol,
1336 fabs(fabs(lat_bounds[1]) - M_PI_2) < yac_angle_tol};
1337 int upper_is_north_pole =
1338 is_pole[upper_bound_idx] && (lat_bounds[upper_bound_idx] > 0.0);
1339 int lower_is_south_pole =
1340 is_pole[lower_bound_idx] && (lat_bounds[lower_bound_idx] < 0.0);
1341
1342 // if both bounds are nearly identical,
1343 // or if the upper bound is the south pole,
1344 // or if the lower bound is the north pole
1345 if ((fabs(lat_bounds[0] - lat_bounds[1]) < yac_angle_tol) ||
1346 (is_pole[upper_bound_idx] ^ upper_is_north_pole) ||
1347 (is_pole[lower_bound_idx] ^ lower_is_south_pole)) {
1348
1349 for (size_t n = 0; n < N; ++n)
1350 overlap_buffer[n].num_corners = 0;
1351 return;
1352 }
1353
1354 struct yac_circle lat_circle_buffer[2];
1355 struct yac_circle * lat_circles[2] =
1356 {&(lat_circle_buffer[0]), &(lat_circle_buffer[1])};
1357 size_t num_lat_circles = 0;
1358 if (!lower_is_south_pole)
1359 lat_circle_buffer[num_lat_circles++] =
1360 generate_lat_circle(z_bounds[lower_bound_idx], 0);
1361 if (!upper_is_north_pole)
1362 lat_circle_buffer[num_lat_circles++] =
1363 generate_lat_circle(z_bounds[upper_bound_idx], 1);
1364
1365 size_t max_num_cell_corners = 0;
1366 for (size_t n = 0; n < N; ++n)
1367 if (cells[n].num_corners > max_num_cell_corners)
1368 max_num_cell_corners = cells[n].num_corners;
1369 struct yac_circle * circle_buffer =
1370 xmalloc(max_num_cell_corners * sizeof(*circle_buffer));
1371
1372 struct point_list cell_list;
1373 init_point_list(&cell_list);
1374
1375 // for all source cells
1376 for (size_t n = 0; n < N; n++) {
1377
1378 if (cells[n].num_corners < 2) continue;
1379
1380 overlap_buffer[n].num_corners = 0;
1381
1382 enum yac_cell_type src_cell_type = get_cell_type(cells[n]);
1383
1384 YAC_ASSERT(
1385 src_cell_type != YAC_MIXED_CELL,
1386 "invalid source cell type (cell contains edges consisting "
1387 "of great circles and circles of latitude)\n")
1388
1389 if (src_cell_type == YAC_LON_LAT_CELL) {
1390
1392 cells + n, z_bounds[upper_bound_idx], z_bounds[lower_bound_idx],
1393 overlap_buffer + n);
1394
1395 } else {
1396
1397 int cell_ordering = get_cell_points_ordering(cells[n]);
1398
1399 // generate point list for current source list
1400 size_t num_corners =
1402 &cell_list, cells[n], cell_ordering, circle_buffer);
1403
1404 // if the cell contains a pole, we need to add this pole
1405 double pole = get_closest_pole(&cell_list);
1407 (double[3]){0.0, 0.0, pole}, cells[n])) {
1408
1409 int flag = 0;
1410
1411 // if the cell contains the north pole
1412 if (pole > 0.0) {
1413 // use lower bound if upper bound is north pole
1414 double z_bound = z_bounds[upper_bound_idx ^ upper_is_north_pole];
1415
1416 for (size_t i = 0; i < num_corners; ++i) {
1417 flag |= (z_bound < cells[n].coordinates_xyz[i][2]);
1418 }
1419 } else {
1420 // use upper bound if lower bound is south pole
1421 double z_bound = z_bounds[lower_bound_idx ^ lower_is_south_pole];
1422
1423 for (size_t i = 0; i < num_corners; ++i) {
1424 flag |= (z_bound > cells[n].coordinates_xyz[i][2]);
1425 }
1426 }
1427
1428 YAC_ASSERT(
1429 flag,
1430 "ERROR(yac_cell_lat_clipping): Latitude bounds are within a cell "
1431 "covering a pole, this is not supported. Increased grid resolution "
1432 "or widen lat bounds may help.")
1433 }
1434
1435 circle_clipping(&cell_list, num_corners, lat_circles, num_lat_circles);
1436
1437 generate_cell(&cell_list, overlap_buffer + n);
1438 }
1439 }
1440
1441 free(circle_buffer);
1442 free_point_list(&cell_list);
1443}
1444
1445/* ---------------------------------------------------- */
1446
1447void yac_correct_weights ( size_t nSourceCells, double * weight ) {
1448
1449 // number of iterations to get better accuracy of the weights
1450 enum {maxIter = 10};
1451
1452 for ( size_t iter = 1; iter < maxIter; iter++ ) {
1453
1454 double weight_sum = 0.0;
1455
1456 for ( size_t n = 0; n < nSourceCells; n++ ) weight_sum += weight[n];
1457
1458 if ( fabs(1.0 - weight_sum) < tol ) break;
1459
1460 double scale = 1.0 / weight_sum;
1461
1462 for ( size_t n = 0; n < nSourceCells; n++ ) weight[n] *= scale;
1463 }
1464}
1465
1466/* ---------------------------------------------------- */
1467
1469
1470 YAC_ASSERT(
1471 cell.num_corners > 2, "ERROR(get_cell_points_ordering): invalid cell")
1472
1473 double edge_norm_vectors[cell.num_corners][3];
1474 double vertices[cell.num_corners][3];
1475 size_t num_corners = 0;
1476
1477 for (size_t i = 0, j = cell.num_corners - 1; i < cell.num_corners; i++) {
1479 cell.coordinates_xyz[j], cell.coordinates_xyz[i])) {
1481 cell.coordinates_xyz[j], cell.coordinates_xyz[i],
1482 edge_norm_vectors[num_corners]);
1483 normalise_vector(edge_norm_vectors[num_corners]);
1484 vertices[num_corners][0] = cell.coordinates_xyz[i][0];
1485 vertices[num_corners][1] = cell.coordinates_xyz[i][1];
1486 vertices[num_corners][2] = cell.coordinates_xyz[i][2];
1487 ++num_corners;
1488 j = i;
1489 }
1490 }
1491
1492 struct sin_cos_angle angle_sum = SIN_COS_ZERO;
1493 int cell_direction = 0;
1494 int valid_angles_count = 0;
1495
1496 for (size_t i = 0, j = num_corners - 1; i < num_corners; j = i++) {
1497
1498 struct sin_cos_angle edge_angle =
1499 get_vector_angle_2(edge_norm_vectors[j], edge_norm_vectors[i]);
1500
1501 // if both edges are on the same plane
1502 if ((edge_angle.cos > 0.0) && (edge_angle.sin < yac_angle_tol))
1503 continue;
1504
1505 valid_angles_count++;
1506
1507 double edge_direction =
1508 edge_norm_vectors[j][0] * vertices[i][0] +
1509 edge_norm_vectors[j][1] * vertices[i][1] +
1510 edge_norm_vectors[j][2] * vertices[i][2];
1511
1512 struct sin_cos_angle temp = angle_sum;
1513 if (edge_direction < 0.0)
1514 cell_direction -= sub_angles(temp, edge_angle, &angle_sum);
1515 else
1516 cell_direction += sum_angles(temp, edge_angle, &angle_sum);
1517 }
1518
1519 if (valid_angles_count == 0) return 0;
1520 return (cell_direction >= 0)?1:-1;
1521}
1522
1523static void init_point_list(struct point_list * list) {
1524
1525 list->start = NULL;
1526 list->free_elements = NULL;
1527}
1528
1529static void reset_point_list(struct point_list * list) {
1530
1531 if (list->start != NULL) {
1532
1533 struct point_list_element * temp = list->start->next;
1534 list->start->next = list->free_elements;
1535 list->free_elements = temp;
1536
1537 list->start = NULL;
1538 }
1539}
1540
1541static size_t remove_points(struct point_list * list) {
1542
1543 struct point_list_element * curr = list->start;
1544 struct point_list_element * start = list->start;
1545 struct point_list_element * prev = NULL;
1546
1547 if (curr == NULL) return 0;
1548
1549 // find the first point that is not to be removed
1550 while(curr->to_be_removed) {
1551 prev = curr;
1552 curr = curr->next;
1553 if (curr == start) break;
1554 };
1555
1556 // there is no point to remain
1557 if (curr->to_be_removed) {
1558 reset_point_list(list);
1559 return 0;
1560 }
1561
1562 list->start = curr;
1563 start = curr;
1564 size_t num_remaining_points = 1;
1565
1566 prev = curr;
1567 curr = curr->next;
1568
1569 while (curr != start) {
1570
1571 if (curr->to_be_removed) {
1572 prev->next = curr->next;
1573 curr->next = list->free_elements;
1574 list->free_elements = curr;
1575 curr = prev;
1576 } else {
1577 num_remaining_points++;
1578 }
1579
1580 prev = curr;
1581 curr = curr->next;
1582
1583 };
1584
1585 if (list->start == list->start->next) {
1586
1587 list->start->next = list->free_elements;
1588 list->free_elements = list->start;
1589 list->start = NULL;
1590 num_remaining_points = 0;
1591 }
1592
1593 return num_remaining_points;
1594}
1595
1597static size_t remove_zero_length_edges(struct point_list * list) {
1598
1599 struct point_list_element * curr = list->start;
1600 struct point_list_element * start = list->start;
1601
1602 do {
1603
1604 if (!curr->to_be_removed) {
1605
1606 // if both points are nearly identical (angle between them is very small)
1607 if (points_are_identically(curr->vec_coords, curr->next->vec_coords)) {
1608 curr->to_be_removed = 1;
1609
1610 // check whether we can merge two lat circle edges
1611 } else if (curr->edge_circle->type == LAT_CIRCLE &&
1612 curr->next->edge_circle->type == LAT_CIRCLE) {
1613 double temp_a = atan2(curr->vec_coords[1], curr->vec_coords[0]);
1614 double temp_b = atan2(curr->next->next->vec_coords[1],
1615 curr->next->next->vec_coords[0]);
1616 if (fabs(get_angle(temp_a, temp_b)) < M_PI_2)
1617 curr->next->to_be_removed = 1;
1618 }
1619 }
1620
1621 curr = curr->next;
1622 } while (curr != start);
1623
1624 return remove_points(list);
1625}
1626
1628 struct point_list * list, struct yac_grid_cell cell, int cell_ordering,
1629 struct yac_circle * circle_buffer) {
1630
1631 reset_point_list(list);
1632
1633 YAC_ASSERT(
1634 cell.num_corners >= 2,
1635 "ERROR(generate_point_list): too few corners in cell");
1636
1637 struct point_list_element * curr = get_free_point_list_element(list);
1638
1639 list->start = curr;
1640
1641 for (size_t i = 0; i < cell.num_corners; ++i, curr = curr->next) {
1642
1643 curr->vec_coords[0] = cell.coordinates_xyz[i][0];
1644 curr->vec_coords[1] = cell.coordinates_xyz[i][1];
1645 curr->vec_coords[2] = cell.coordinates_xyz[i][2];
1647 cell.coordinates_xyz[i], cell.coordinates_xyz[(i+1)%(cell.num_corners)],
1648 cell.edge_type[i], cell_ordering,
1649 ((curr->edge_circle = circle_buffer + i)));
1650 curr->next =
1651 ((i + 1) == cell.num_corners)?
1652 (list->start):get_free_point_list_element(list);
1653 }
1654
1655 return remove_zero_length_edges(list);
1656}
1657
1658static struct point_list_element *
1660
1661 struct point_list_element * element;
1662
1663 if (list->free_elements == NULL) {
1664
1665 for (int i = 0; i < 7; ++i) {
1666
1667 element = (struct point_list_element *)xmalloc(1 * sizeof(*element));
1668
1669 element->next = list->free_elements;
1670 list->free_elements = element;
1671 }
1672
1673 element = (struct point_list_element *)xmalloc(1 * sizeof(*element));
1674
1675 } else {
1676
1677 element = list->free_elements;
1678 list->free_elements = list->free_elements->next;
1679 }
1680
1681 element->next = NULL;
1682 element->to_be_removed = 0;
1683
1684 return element;
1685}
1686
1687static void free_point_list(struct point_list * list) {
1688
1689 struct point_list_element * element;
1690
1691 if (list->start != NULL) {
1692
1693 struct point_list_element * temp = list->free_elements;
1694 list->free_elements = list->start->next;
1695 list->start->next = temp;
1696 }
1697
1698 while (list->free_elements != NULL) {
1699
1700 element = list->free_elements;
1701 list->free_elements = element->next;
1702 free(element);
1703 }
1704
1705 list->start = NULL;
1706 list->free_elements = NULL;
1707}
1708
1709static void compute_norm_vector(double a[], double b[], double norm[]) {
1710
1711 crossproduct_kahan(a, b, norm);
1712
1713 YAC_ASSERT(
1714 (fabs(norm[0]) >= tol) || (fabs(norm[1]) >= tol) || (fabs(norm[2]) >= tol),
1715 "ERROR: a and b are identical -> no norm vector")
1716
1717 normalise_vector(norm);
1718}
1719
1720static int is_empty_gc_cell(struct point_list * list, size_t num_edges) {
1721
1722 if (num_edges < 2) return 0;
1723
1724 // if the polygon only has two vertices
1725 if (num_edges == 2)
1726 // the cell is empty if both edges have the same type
1727 // (lon and gc are counted as the same type)
1728 return !((list->start->edge_circle->type == LAT_CIRCLE) ^
1729 (list->start->next->edge_circle->type == LAT_CIRCLE));
1730
1731 struct point_list_element * curr = list->start;
1732
1733 // if there is at least one lat circle edge, the cell is not empty
1734 for (size_t i = 0; i < num_edges; ++i, curr = curr->next)
1735 if (curr->edge_circle->type == LAT_CIRCLE) return 0;
1736
1737 // compute the norm vector for the first edge
1738 double norm_vec[3];
1739 compute_norm_vector(curr->vec_coords, curr->next->vec_coords, norm_vec);
1740 curr = curr->next->next;
1741
1742 // check whether at least one vertex of the polygon is on a diffent plane
1743 // than the one defined by the first edge of the polygon
1744 for (size_t i = 0; i < num_edges - 2; ++i, curr = curr->next)
1745 if (fabs(dotproduct(norm_vec, curr->vec_coords)) > yac_angle_tol)
1746 return 0;
1747
1748 return 1;
1749}
1750
1752 switch (type) {
1753 default:
1754 case (GREAT_CIRCLE): return YAC_GREAT_CIRCLE_EDGE;
1755 case (LON_CIRCLE): return YAC_LON_CIRCLE_EDGE;
1756 case (LAT_CIRCLE): return YAC_LAT_CIRCLE_EDGE;
1757 }
1758}
1759
1760static void generate_cell(struct point_list * list,
1761 struct yac_grid_cell * cell) {
1762
1763 if (list->start == NULL) {
1764
1765 reset_point_list(list);
1766 cell->num_corners = 0;
1767 return;
1768 }
1769
1770 size_t num_edges = remove_zero_length_edges(list);
1771
1772 if (is_empty_gc_cell(list, num_edges)) {
1773
1774 reset_point_list(list);
1775 cell->num_corners = 0;
1776 return;
1777 }
1778
1779 if (num_edges > cell->array_size) {
1780 free(cell->coordinates_xyz);
1781 free(cell->edge_type);
1782 cell->coordinates_xyz = (double(*)[3])xmalloc(num_edges * sizeof(*cell->coordinates_xyz));
1783 cell->edge_type = (enum yac_edge_type *)xmalloc(num_edges * sizeof(*cell->edge_type));
1784 cell->array_size = num_edges;
1785 }
1786 cell->num_corners = num_edges;
1787
1788 struct point_list_element * curr = list->start;
1789
1790 for (size_t i = 0; i < num_edges; ++i) {
1791
1792 cell->coordinates_xyz[i][0] = curr->vec_coords[0];
1793 cell->coordinates_xyz[i][1] = curr->vec_coords[1];
1794 cell->coordinates_xyz[i][2] = curr->vec_coords[2];
1795 cell->edge_type[i] = circle2edge_type(curr->edge_circle->type);
1796
1797 curr = curr->next;
1798 }
1799}
double yac_huiliers_area(struct yac_grid_cell cell)
Area calculation on a unit sphere taken from ESMF based on L'Huilier's Theorem.
Definition area.c:449
double yac_huiliers_area_info(struct yac_grid_cell cell, double *barycenter, double sign)
Definition area.c:539
Structs and interfaces for area calculations.
static int edge_direction(double *a, double *b)
int yac_point_in_cell(double point_coords[3], struct yac_grid_cell cell)
int yac_circle_point_is_inside(double const point[3], struct yac_circle *circle)
Definition clipping.c:471
static size_t overlap_cell_buffer_size
Definition clipping.c:67
static int is_empty_gc_cell(struct point_list *list, size_t num_edges)
Definition clipping.c:1720
void yac_correct_weights(size_t nSourceCells, double *weight)
correct interpolation weights
Definition clipping.c:1447
static void point_list_clipping(struct point_list *source_list, struct point_list target_list, size_t nct)
Definition clipping.c:1042
static void reset_point_list(struct point_list *list)
Definition clipping.c:1529
static struct yac_grid_cell * overlap_cell_buffer
Definition clipping.c:66
static void copy_point_list(struct point_list in, struct point_list *out)
Definition clipping.c:1065
static struct yac_grid_cell * get_overlap_cell_buffer(size_t N)
Definition clipping.c:69
static void circle_clipping(struct point_list *cell, size_t num_cell_edges, struct yac_circle **clipping_circles, size_t num_clipping_circles)
Definition clipping.c:586
void yac_cell_lat_clipping(size_t N, struct yac_grid_cell *cells, double lat_bounds[2], struct yac_grid_cell *overlap_buffer)
cell clipping to get the cells describing the intersections
Definition clipping.c:1327
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
Definition clipping.c:1090
static size_t remove_points(struct point_list *list)
Definition clipping.c:1541
static struct point_list_element * get_free_point_list_element(struct point_list *list)
Definition clipping.c:1659
void yac_compute_overlap_info(size_t N, struct yac_grid_cell *source_cell, struct yac_grid_cell target_cell, double *overlap_areas, double(*overlap_barycenters)[3])
calculates partial areas for all overlapping parts of the source cells with arbitrary target cells,...
Definition clipping.c:119
static size_t generate_point_list(struct point_list *list, struct yac_grid_cell cell, int cell_ordering, struct yac_circle *circle_buffer)
Definition clipping.c:1627
void yac_compute_overlap_areas(size_t N, struct yac_grid_cell *source_cell, struct yac_grid_cell target_cell, double *partial_areas)
calculates partial areas for all overlapping parts of the source cells with arbitrary target cells,...
Definition clipping.c:276
int yac_circle_compare(void const *a, void const *b)
Definition clipping.c:344
static double dotproduct(double a[], double b[])
Definition clipping.c:269
static void init_point_list(struct point_list *list)
Definition clipping.c:1523
static enum yac_edge_type circle2edge_type(enum yac_circle_type type)
Definition clipping.c:1751
static void free_point_list(struct point_list *list)
Definition clipping.c:1687
static int get_cell_points_ordering(struct yac_grid_cell cell)
Definition clipping.c:1468
static void yac_lon_lat_cell_lat_clipping(struct yac_grid_cell *cell, double z_upper_bound, double z_lower_bound, struct yac_grid_cell *overlap_buffer)
Definition clipping.c:1197
static enum yac_cell_type get_cell_type(struct yac_grid_cell target_cell)
Definition clipping.c:287
static struct yac_circle generate_lat_circle(double z, int north_is_out)
Definition clipping.c:461
static size_t remove_zero_length_edges(struct point_list *list)
returns number of edges/corners
Definition clipping.c:1597
static void compute_norm_vector(double a[], double b[], double norm[])
Definition clipping.c:1709
static void generate_cell(struct point_list *list, struct yac_grid_cell *cell)
Definition clipping.c:1760
int yac_circle_contains_north_pole(struct yac_circle *circle)
Definition clipping.c:563
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:415
static double get_closest_pole(struct point_list *cell_list)
Definition clipping.c:1306
static double const tol
Definition clipping.c:23
static double get_edge_direction(double *ref_corner, double *corner_a, double *corner_b)
Definition clipping.c:99
void yac_compute_overlap_buf_free()
Definition clipping.c:88
int yac_circle_compare_distances(double const a[3], double const b[3], struct yac_circle *circle)
Definition clipping.c:509
static void compute_norm_vector_kahan(double const a[3], double const b[3], double norm_vector[3])
Definition clipping.c:402
#define ENSURE_ARRAY_SIZE(arrayp, curr_array_size, req_size)
static struct sin_cos_angle get_vector_angle_2(double const a[3], double const b[3])
Definition geometry.h:397
static const struct sin_cos_angle SIN_COS_ZERO
Definition geometry.h:44
int yac_circle_intersect(struct yac_circle a, struct yac_circle b, double p[3], double q[3])
static int points_are_identically(double const *a, double const *b)
Definition geometry.h:630
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:201
static void crossproduct_d(const double a[], const double b[], double cross[])
Definition geometry.h:333
static void crossproduct_kahan(double const a[], double const b[], double cross[])
Definition geometry.h:318
#define yac_sq_angle_tol
Definition geometry.h:35
static int sub_angles(struct sin_cos_angle a, struct sin_cos_angle b, struct sin_cos_angle *restrict sub)
Definition geometry.h:540
int yac_point_on_edge(double p[3], double const a[3], double const b[3], enum yac_circle_type circle_type)
#define yac_angle_low_tol
Definition geometry.h:37
#define yac_angle_tol
Definition geometry.h:34
static void normalise_vector(double v[])
Definition geometry.h:671
static double get_angle(double a_lon, double b_lon)
Definition geometry.h:127
static double get_vector_angle(double const a[3], double const b[3])
Definition geometry.h:350
static int sum_angles(struct sin_cos_angle a, struct sin_cos_angle b, struct sin_cos_angle *restrict sum)
Definition geometry.h:516
yac_circle_type
Definition geometry.h:72
@ POINT
Definition geometry.h:76
@ LAT_CIRCLE
Definition geometry.h:74
@ GREAT_CIRCLE
Definition geometry.h:73
@ LON_CIRCLE
Definition geometry.h:75
void yac_init_grid_cell(struct yac_grid_cell *cell)
Definition grid_cell.c:14
void yac_free_grid_cell(struct yac_grid_cell *cell)
Definition grid_cell.c:44
yac_cell_type
Definition grid_cell.h:26
@ YAC_LAT_CELL
Definition grid_cell.h:28
@ YAC_LON_LAT_CELL
Definition grid_cell.h:27
@ YAC_GREAT_CIRCLE_CELL
Definition grid_cell.h:29
@ YAC_MIXED_CELL
Definition grid_cell.h:30
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
enum callback_type type
#define xmalloc(size)
Definition ppm_xfuncs.h:66
struct yac_circle * edge_circle
Definition clipping.c:28
struct point_list_element * next
Definition clipping.c:30
double vec_coords[3]
Definition clipping.c:27
struct point_list_element * free_elements
Definition clipping.c:36
struct point_list_element * start
Definition clipping.c:35
double sin
Definition geometry.h:41
double cos
Definition geometry.h:41
struct yac_circle::@2::@4 lat
struct yac_circle::@2::@3 lon
double z
Definition geometry.h:90
enum yac_circle_type type
Definition geometry.h:82
struct yac_circle::@2::@3 gc
struct yac_circle::@2::@5 p
int north_is_out
Definition geometry.h:89
double norm_vector[3]
Definition geometry.h:86
double vec[3]
Definition geometry.h:93
union yac_circle::@2 data
size_t num_corners
Definition grid_cell.h:21
enum yac_edge_type * edge_type
Definition grid_cell.h:20
size_t array_size
Definition grid_cell.h:22
double(* coordinates_xyz)[3]
Definition grid_cell.h:19
#define MAX(a, b)
#define YAC_ASSERT_F(exp, format,...)
Definition yac_assert.h:19
#define YAC_ASSERT(exp, msg)
Definition yac_assert.h:16