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