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