1 /**
2 * @file sphere_part.c
3 *
4 * @copyright Copyright (C) 2014 Moritz Hanke <hanke@dkrz.de>
5 * Thomas Jahns <jahns@dkrz.de>
6 *
7 * @version 1.0
8 * @author Moritz Hanke <hanke@dkrz.de>
9 * Thomas Jahns <jahns@dkrz.de>
10 */
11 /*
12 * Keywords:
13 * Maintainer: Moritz Hanke <hanke@dkrz.de>
14 * Rene Redler <rene.redler@mpimet.mpg.de>
15 * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yac/
16 *
17 * This file is part of YAC.
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions are
21 * met:
22 *
23 * Redistributions of source code must retain the above copyright notice,
24 * this list of conditions and the following disclaimer.
25 *
26 * Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 *
30 * Neither the name of the DKRZ GmbH nor the names of its contributors
31 * may be used to endorse or promote products derived from this software
32 * without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
35 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
36 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
37 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
38 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
39 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
41 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
42 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
43 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
44 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 */
46
47 #ifdef HAVE_CONFIG_H
48 // Get the definition of the 'restrict' keyword.
49 #include "config.h"
50 #endif
51
52 #include <assert.h>
53 #include <stdlib.h>
54 #include <math.h>
55 #include <string.h>
56 #include <stdint.h>
57
58 #include "sphere_part.h"
59 #include "geometry.h"
60 #include "grid.h"
61 #include "interval_tree.h"
62 #include "utils.h"
63 #include "ensure_array_size.h"
64
65 union I_list {
66 struct {
67 struct interval_node * head_node;
68 size_t num_nodes;
69 } ivt;
70 size_t *list;
71 };
72
73 enum {
74 I_list_tree_min_size = 2, //!< make I list into tree when list is
75 //!< larger than this
76 };
77 enum {
78 U_FLAG = 1,
79 T_FLAG = 2,
80 };
81
82 enum yac_node_flags {
83 U_IS_LEAF = 1,
84 T_IS_LEAF = 2,
85 I_IS_INTERVAL_TREE = 4,
86 };
87
88 struct sphere_part_node {
89
90 int flags;
91
92 union I_list I;
93 void * U, * T;
94
95 size_t I_size, U_size, T_size;
96
97 struct sin_cos_angle I_angle;
98
99 double gc_norm_vector[3];
100 };
101
102 struct bnd_sphere_part_search {
103 struct sphere_part_node base_node;
104 size_t * ids;
105 };
106
107 enum node_type {
108 I_NODE = 0,
109 U_NODE = 1,
110 T_NODE = 2,
111 };
112
113 struct temp_partition_data {
114 size_t local_id;
115 struct bounding_circle bnd_circle;
116 int node_type;
117 };
118
119 struct point_id_xyz {
120 size_t idx; // index of the point in the coordinates array passed to
121 // the constructor
122 double coordinates_xyz[3];
123 };
124
125 struct point_id_xyz_angle {
126 size_t idx; // index of the point in the coordinates array passed to
127 // the constructor
128 double coordinates_xyz[3];
129 double cos_angle;
130 };
131
132 struct point_sphere_part_node {
133
134 int flags;
135
136 void * U, * T;
137
138 size_t U_size, T_size;
139
140 double gc_norm_vector[3];
141 };
142
143 struct point_sphere_part_search {
144
145 struct point_sphere_part_node base_node;
146 struct point_id_xyz * points;
147 size_t max_tree_depth;
148 };
149
150 struct point_id_xyz_int32 {
151 size_t idx;
152 int32_t coordinate_xyz[3];
153 };
154
init_sphere_part_node(struct sphere_part_node * node)155 static void init_sphere_part_node(struct sphere_part_node * node) {
156
157 node->flags = 0;
158 node->I_size = 0;
159 node->U_size = 0;
160 node->T_size = 0;
161 node->gc_norm_vector[0] = 0;
162 node->gc_norm_vector[1] = 0;
163 node->gc_norm_vector[2] = 1;
164 }
165
get_sphere_part_node()166 static struct sphere_part_node * get_sphere_part_node() {
167
168 struct sphere_part_node * node = xmalloc(1 * sizeof(*node));
169
170 init_sphere_part_node(node);
171
172 return node;
173 }
174
compare_temp_partition_data(const void * a,const void * b)175 static int compare_temp_partition_data(const void * a, const void * b) {
176
177 return ((const struct temp_partition_data *)a)->node_type -
178 ((const struct temp_partition_data *)b)->node_type;
179 }
180
partition_data(size_t * local_cell_ids,struct temp_partition_data * part_data,size_t num_cell_ids,size_t threshold,struct sphere_part_node * parent_node,double prev_gc_norm_vector[])181 static void partition_data (
182 size_t * local_cell_ids, struct temp_partition_data * part_data,
183 size_t num_cell_ids, size_t threshold, struct sphere_part_node * parent_node,
184 double prev_gc_norm_vector[]) {
185
186 if (num_cell_ids == 0) {
187 parent_node->flags = U_IS_LEAF + T_IS_LEAF;
188 return;
189 }
190
191 double balance_point[3] = {0.0,0.0,0.0};
192
193 // compute balance point
194 for (size_t i = 0; i < num_cell_ids; ++i) {
195
196 balance_point[0] += part_data[i].bnd_circle.base_vector[0];
197 balance_point[1] += part_data[i].bnd_circle.base_vector[1];
198 balance_point[2] += part_data[i].bnd_circle.base_vector[2];
199 }
200
201 normalise_vector(balance_point);
202
203 // compute the great circle that partitions the data in half (more or less)
204
205 crossproduct_ld(
206 balance_point, prev_gc_norm_vector, parent_node->gc_norm_vector);
207 normalise_vector(parent_node->gc_norm_vector);
208
209 // partition data into cells that overlap with the great circle and cells
210 // that are on side of the circle
211
212 size_t I_size = 0;
213 size_t U_size = 0;
214 size_t T_size = 0;
215
216 struct sin_cos_angle max_inc_angle = SIN_COS_ZERO;
217
218 for (size_t i = 0; i < num_cell_ids; ++i) {
219
220 struct bounding_circle curr_bnd_circle = part_data[i].bnd_circle;
221
222 // get angle between the norm vector of the great circle and the base
223 // point of the bounding circle
224 struct sin_cos_angle angle =
225 get_vector_angle_2(
226 curr_bnd_circle.base_vector, parent_node->gc_norm_vector);
227
228 // get the angle between between the plane of the great circle and base
229 // point of the bounding circle
230 struct sin_cos_angle diff_angle_gc =
231 sin_cos_angle_new(fabs(angle.cos), angle.sin);
232
233 // if the point intersects with the great circle
234 if (compare_angles(diff_angle_gc, curr_bnd_circle.inc_angle) <= 0) {
235
236 // set node type for current cell
237 part_data[i].node_type = I_NODE;
238 I_size++;
239
240 struct sin_cos_angle inc_angle =
241 sum_angles_no_check(diff_angle_gc, curr_bnd_circle.inc_angle);
242
243 if (compare_angles(max_inc_angle, inc_angle) < 0)
244 max_inc_angle = inc_angle;
245
246 // angle > M_PI_2
247 } else if (angle.cos < 0.0) {
248
249 // set node type for current cell
250 part_data[i].node_type = U_NODE;
251 U_size++;
252
253 } else {
254
255 // set node type for current cell
256 part_data[i].node_type = T_NODE;
257 T_size++;
258 }
259 }
260
261 qsort(
262 part_data, num_cell_ids, sizeof(*part_data), compare_temp_partition_data);
263
264 parent_node->I_size = I_size;
265 parent_node->U_size = U_size;
266 parent_node->T_size = T_size;
267
268 // if max_inc_angle > PI/2
269 if (compare_angles(max_inc_angle, SIN_COS_M_PI_2) >= 0) {
270 parent_node->I_angle = SIN_COS_M_PI_2;
271 } else {
272 parent_node->I_angle = max_inc_angle;
273 }
274
275 if (I_size > 0) {
276
277 if (I_size > I_list_tree_min_size) {
278
279 assert(sizeof(struct interval_node) > sizeof(size_t));
280 struct interval_node * head_node = xmalloc(I_size * sizeof(*head_node));
281 parent_node->I.ivt.head_node = head_node;
282 parent_node->I.ivt.num_nodes = I_size;
283
284 for (size_t i = 0; i < I_size; ++i) {
285
286 struct sin_cos_angle base_angle, corrected_inc_angle;
287 int big_sum, neg;
288 double GCp[3], bVp[3];
289 struct bounding_circle curr_bnd_circle = part_data[i].bnd_circle;
290
291 crossproduct_ld(parent_node->gc_norm_vector,
292 curr_bnd_circle.base_vector, GCp);
293 crossproduct_ld(GCp, parent_node->gc_norm_vector, bVp);
294 normalise_vector(bVp);
295 base_angle = get_vector_angle_2(bVp, prev_gc_norm_vector);
296 big_sum =
297 sum_angles(curr_bnd_circle.inc_angle,
298 get_vector_angle_2(bVp, curr_bnd_circle.base_vector),
299 &corrected_inc_angle);
300
301 // if the angle is bigger then PI
302 if ((big_sum) || (corrected_inc_angle.sin < 0.0))
303 corrected_inc_angle = SIN_COS_M_PI;
304
305 struct sin_cos_angle left, right;
306 // base_angle - corrected_inc_angle
307 neg = sub_angles(base_angle, corrected_inc_angle, &left);
308 // base_angle + corrected_inc_angle
309 big_sum = sum_angles(base_angle, corrected_inc_angle, &right);
310
311 head_node[i].range.left = compute_angle(left) - (neg?2.0*M_PI:0.0);
312 head_node[i].range.right = compute_angle(right) +
313 (big_sum?2.0*M_PI:0.0);
314 head_node[i].value = part_data[i].local_id;
315 }
316
317 yac_generate_interval_tree(head_node, I_size);
318 parent_node->flags |= I_IS_INTERVAL_TREE;
319 } else {
320 for (size_t i = 0; i < I_size; ++i)
321 local_cell_ids[i] = part_data[i].local_id;
322 parent_node->I.list = (void*)local_cell_ids;
323 }
324 } else
325 parent_node->I.list = NULL;
326
327 part_data += I_size;
328 local_cell_ids += I_size;
329
330 // check whether the lists are small enough (if not -> partition again)
331 if (U_size <= threshold) {
332
333 for (size_t i = 0; i < U_size; ++i)
334 local_cell_ids[i] = part_data[i].local_id;
335 parent_node->U = (void*)local_cell_ids;
336 parent_node->flags |= U_IS_LEAF;
337
338 } else {
339
340 parent_node->U = get_sphere_part_node();
341 partition_data(local_cell_ids, part_data, U_size, threshold,
342 parent_node->U, parent_node->gc_norm_vector);
343 }
344 local_cell_ids += U_size;
345 part_data += U_size;
346
347 if (T_size <= threshold) {
348
349 for (size_t i = 0; i < T_size; ++i)
350 local_cell_ids[i] = part_data[i].local_id;
351 parent_node->T = (void*)local_cell_ids;
352 parent_node->flags |= T_IS_LEAF;
353 local_cell_ids += T_size;
354
355 } else {
356
357 parent_node->T = get_sphere_part_node();
358 partition_data(local_cell_ids, part_data, T_size, threshold,
359 parent_node->T, parent_node->gc_norm_vector);
360 }
361 }
362
compare_point_idx_xyz(void const * a,void const * b)363 static int compare_point_idx_xyz(void const * a, void const * b) {
364 return (((struct point_id_xyz *)a)->idx > ((struct point_id_xyz *)b)->idx) -
365 (((struct point_id_xyz *)a)->idx < ((struct point_id_xyz *)b)->idx);
366 }
367
partition_point_data(struct point_id_xyz * points,size_t num_points,size_t threshold,double prev_gc_norm_vector[],size_t curr_tree_depth,size_t * max_tree_depth)368 static struct point_sphere_part_node * partition_point_data (
369 struct point_id_xyz * points, size_t num_points, size_t threshold,
370 double prev_gc_norm_vector[], size_t curr_tree_depth,
371 size_t * max_tree_depth) {
372
373 if (curr_tree_depth > *max_tree_depth) *max_tree_depth = curr_tree_depth;
374
375 struct point_sphere_part_node * node = xmalloc(1 * sizeof(*node));
376
377 double balance_point[3] = {0.0,0.0,0.0};
378
379 // compute balance point
380
381 for (size_t i = 0; i < num_points; ++i) {
382
383 double * curr_coordinates_xyz = &(points[i].coordinates_xyz[0]);
384 balance_point[0] += curr_coordinates_xyz[0];
385 balance_point[1] += curr_coordinates_xyz[1];
386 balance_point[2] += curr_coordinates_xyz[2];
387 }
388
389 normalise_vector(balance_point);
390
391 // compute the great circle that partitions the data in half (more or less)
392
393 double * gc_norm_vector = &(node->gc_norm_vector[0]);
394 crossproduct_ld(balance_point, prev_gc_norm_vector, gc_norm_vector);
395 normalise_vector(gc_norm_vector);
396
397 // angle between a point and the great circle plane
398 // acos(dot(gc_norm_vector, point_xyz)) = angle(gc_norm_vector, point_xyz)
399 // acos(dot(gc_norm_vector, point_xyz)) - PI/2 = angle(gc_plane, point_xyz)
400 // dot <= 0.0 -> U list
401 // dot > 0.0 -> T list
402
403 struct point_id_xyz * left = points, * right = points + num_points - 1;
404
405 // sort such that all points for the U list come first, followed by the
406 // elements of the T list
407 while (1) {
408 // find element that does not belong into U-list
409 while (left <= right) {
410 double * curr_coordinates_xyz = &(left->coordinates_xyz[0]);
411 double dot = curr_coordinates_xyz[0] * gc_norm_vector[0] +
412 curr_coordinates_xyz[1] * gc_norm_vector[1] +
413 curr_coordinates_xyz[2] * gc_norm_vector[2];
414
415 // if (angle < M_PI_2)
416 if (dot > 0.0) break;
417 ++left;
418 };
419
420 // find element that does not belong into T-list
421 while (left < right) {
422 double * curr_coordinates_xyz = &(right->coordinates_xyz[0]);
423 double dot = curr_coordinates_xyz[0] * gc_norm_vector[0] +
424 curr_coordinates_xyz[1] * gc_norm_vector[1] +
425 curr_coordinates_xyz[2] * gc_norm_vector[2];
426
427 // if (angle >= M_PI_2)
428 if (dot <= 0.0) break;
429 --right;
430 }
431
432 if (left < right) {
433 struct point_id_xyz tmp_point = *left;
434 *left = *right;
435 *right = tmp_point;
436 ++left;
437 --right;
438 } else {
439 break;
440 }
441 }
442
443 size_t U_size = left - points;
444 size_t T_size = num_points - U_size;
445
446 node->U_size = U_size;
447 node->T_size = T_size;
448 node->flags = 0;
449
450 // check whether the lists are small enough (if not -> partition again)
451 if ((U_size <= threshold) ||(U_size == num_points)) {
452
453 node->U = points;
454 node->flags |= U_IS_LEAF;
455 qsort(points, U_size, sizeof(*points), compare_point_idx_xyz);
456
457 } else {
458
459 node->U = partition_point_data(points, U_size, threshold, gc_norm_vector,
460 curr_tree_depth + 1, max_tree_depth);
461 }
462
463 if ((T_size <= threshold) || (T_size == num_points)) {
464
465 node->T = points + U_size;
466 node->flags |= T_IS_LEAF;
467 qsort(points + U_size, T_size, sizeof(*points), compare_point_idx_xyz);
468
469 } else {
470
471 node->T =
472 partition_point_data(points + U_size, T_size, threshold, gc_norm_vector,
473 curr_tree_depth + 1, max_tree_depth);
474 }
475
476 return node;
477 }
478
yac_bnd_sphere_part_search_new(struct bounding_circle * circles,size_t num_circles)479 struct bnd_sphere_part_search * yac_bnd_sphere_part_search_new(
480 struct bounding_circle * circles, size_t num_circles) {
481
482 struct bnd_sphere_part_search * search = xmalloc(1 * sizeof(*search));
483
484 double gc_norm_vector[3] = {0.0,0.0,1.0};
485
486 init_sphere_part_node(&(search->base_node));
487
488 size_t * ids = xmalloc(num_circles * sizeof(*ids));
489 search->ids = ids;
490
491 struct temp_partition_data * part_data =
492 xmalloc(num_circles * sizeof(*part_data));
493 for (size_t i = 0; i < num_circles; ++i) {
494 part_data[i].bnd_circle = circles[i];
495 part_data[i].local_id = i;
496 }
497
498 partition_data(ids, part_data, num_circles, I_list_tree_min_size,
499 &(search->base_node), gc_norm_vector);
500
501 free(part_data);
502
503 return search;
504 }
505
compare_points_int32_coord(const void * a,const void * b)506 static inline int compare_points_int32_coord(
507 const void * a,const void * b) {
508
509 struct point_id_xyz_int32 * point_a = (struct point_id_xyz_int32 *)a;
510 struct point_id_xyz_int32 * point_b = (struct point_id_xyz_int32 *)b;
511
512 int ret;
513
514 for (int i = 0; i < 3; ++i)
515 if ((ret = (point_a->coordinate_xyz[i] > point_b->coordinate_xyz[i]) -
516 (point_a->coordinate_xyz[i] < point_b->coordinate_xyz[i])))
517 return ret;
518 return 0;
519 }
520
521 static struct point_id_xyz *
get_unique_points(size_t * num_points,coordinate_pointer coordinates_xyz,yac_int const * ids,int const * mask)522 get_unique_points(
523 size_t * num_points, coordinate_pointer coordinates_xyz,
524 yac_int const * ids, int const * mask) {
525
526 struct point_id_xyz_int32 * points_int32 =
527 xmalloc(*num_points * sizeof(*points_int32));
528
529 double const scale = (double)(2 << 21);
530
531 size_t num_unmasked_points;
532
533 if (mask == NULL) {
534 num_unmasked_points = *num_points;
535 for (size_t i = 0; i < num_unmasked_points; ++i) {
536
537 points_int32[i].idx = i;
538 for (size_t j = 0; j < 3; ++j)
539 points_int32[i].coordinate_xyz[j] =
540 (int32_t)round(coordinates_xyz[i][j] * scale);
541 }
542 } else {
543 num_unmasked_points = 0;
544 for (size_t i = 0; i < *num_points; ++i) {
545
546 if (!mask[i]) continue;
547 points_int32[num_unmasked_points].idx = i;
548 for (size_t j = 0; j < 3; ++j)
549 points_int32[num_unmasked_points].coordinate_xyz[j] =
550 (int32_t)round(coordinates_xyz[i][j] * scale);
551 num_unmasked_points++;
552 }
553 }
554
555 // sort points
556 qsort(points_int32, num_unmasked_points,
557 sizeof(*points_int32), compare_points_int32_coord);
558
559 struct point_id_xyz_int32 dummy;
560 dummy.idx = SIZE_MAX;
561 dummy.coordinate_xyz[0] = INT32_MAX;
562 dummy.coordinate_xyz[1] = INT32_MAX;
563 dummy.coordinate_xyz[2] = INT32_MAX;
564 struct point_id_xyz_int32 * prev = &dummy, * curr = points_int32;
565 yac_int prev_id = XT_INT_MAX;
566 size_t new_num_points = 0;
567 for (size_t i = 0; i < num_unmasked_points; ++i, ++curr) {
568
569 size_t curr_idx = curr->idx;
570 if (compare_points_int32_coord(prev, curr)) {
571 prev = points_int32 + new_num_points++;
572 if (prev != curr) *prev = *curr;
573 prev_id = ids[curr_idx];
574 } else {
575 yac_int curr_id = ids[curr_idx];
576 if (curr_id > prev_id) {
577 prev_id = curr_id;
578 prev->idx = curr_idx;
579 }
580 }
581 }
582
583 struct point_id_xyz * points = xmalloc(new_num_points * sizeof(*points));
584 for (size_t i = 0; i < new_num_points; ++i) {
585 size_t curr_idx = points_int32[i].idx;
586 points[i].idx = curr_idx;
587 memcpy(
588 points[i].coordinates_xyz, coordinates_xyz[curr_idx], 3 * sizeof(double));
589 }
590 *num_points = new_num_points;
591 free(points_int32);
592 return points;
593 }
594
yac_point_sphere_part_search_new(size_t num_points,coordinate_pointer coordinates_xyz,yac_int const * ids)595 struct point_sphere_part_search * yac_point_sphere_part_search_new (
596 size_t num_points, coordinate_pointer coordinates_xyz, yac_int const * ids) {
597
598 if (num_points == 0) return NULL;
599
600 struct point_sphere_part_search * search = xmalloc(1 * sizeof(*search));
601 struct point_id_xyz * points =
602 get_unique_points(&num_points, coordinates_xyz, ids, NULL);
603 search->points = points;
604
605 size_t max_tree_depth = 0;
606
607 // emperical measurements have given a threshold for the leaf size of 2
608 struct point_sphere_part_node * tmp_node =
609 partition_point_data(
610 points, num_points, I_list_tree_min_size, (double[3]){0.0,0.0,1.0},
611 1, &max_tree_depth);
612
613 search->base_node = *tmp_node;
614 search->max_tree_depth = max_tree_depth;
615 free(tmp_node);
616
617 return search;
618 }
619
yac_point_sphere_part_search_mask_new(size_t num_points,coordinate_pointer coordinates_xyz,yac_int const * ids,int const * mask)620 struct point_sphere_part_search * yac_point_sphere_part_search_mask_new (
621 size_t num_points, coordinate_pointer coordinates_xyz,
622 yac_int const * ids, int const * mask) {
623
624 if (num_points == 0) return NULL;
625
626 struct point_id_xyz * points =
627 get_unique_points(&num_points, coordinates_xyz, ids, mask);
628
629 if (num_points == 0) {
630 free(points);
631 return NULL;
632 }
633
634 struct point_sphere_part_search * search = xmalloc(1 * sizeof(*search));
635 search->points = xrealloc(points, num_points * sizeof(*points));
636
637 size_t max_tree_depth = 0;
638
639 // emperical measurements have given a threshold for the leaf size of 2
640 struct point_sphere_part_node * tmp_node =
641 partition_point_data(
642 search->points, num_points, I_list_tree_min_size,
643 (double[3]){0.0,0.0,1.0}, 1, &max_tree_depth);
644
645 search->base_node = *tmp_node;
646 search->max_tree_depth = max_tree_depth;
647 free(tmp_node);
648
649 return search;
650 }
651
search_bnd_circle_I_node(struct sphere_part_node * node,struct bounding_circle bnd_circle,size_t ** restrict overlap_cells,size_t * overlap_cells_array_size,size_t * restrict num_overlap_cells,struct overlaps * search_interval_tree_buffer,double prev_gc_norm_vector[])652 static void search_bnd_circle_I_node(
653 struct sphere_part_node * node, struct bounding_circle bnd_circle,
654 size_t ** restrict overlap_cells, size_t * overlap_cells_array_size,
655 size_t * restrict num_overlap_cells,
656 struct overlaps * search_interval_tree_buffer, double prev_gc_norm_vector[]) {
657
658 if (node->flags & I_IS_INTERVAL_TREE) {
659
660 struct sin_cos_angle base_angle, corrected_inc_angle;
661 int big_sum, neg;
662 double GCp[3], bVp[3];
663 crossproduct_ld(node->gc_norm_vector,
664 bnd_circle.base_vector, GCp);
665 crossproduct_ld(GCp, node->gc_norm_vector, bVp);
666 normalise_vector(bVp);
667 base_angle = get_vector_angle_2(bVp, prev_gc_norm_vector);
668 big_sum =
669 sum_angles(
670 bnd_circle.inc_angle, get_vector_angle_2(bVp, bnd_circle.base_vector),
671 &corrected_inc_angle);
672
673 // if the angle is bigger then PI
674 if ((big_sum) || (corrected_inc_angle.sin < 0.0))
675 corrected_inc_angle = SIN_COS_M_PI;
676
677 struct sin_cos_angle left, right;
678 // base_angle - corrected_inc_angle
679 neg = sub_angles(base_angle, corrected_inc_angle, &left);
680 // base_angle + corrected_inc_angle
681 big_sum = sum_angles(base_angle, corrected_inc_angle, &right);
682
683 search_interval_tree_buffer->num_overlaps = 0;
684
685 yac_search_interval_tree(
686 node->I.ivt.head_node, node->I.ivt.num_nodes,
687 (struct interval){
688 .left = compute_angle(left) - (neg?2.0*M_PI:0.0),
689 .right = compute_angle(right) + (big_sum?2.0*M_PI:0.0)},
690 search_interval_tree_buffer);
691
692 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
693 *num_overlap_cells +
694 search_interval_tree_buffer->num_overlaps);
695
696 for (size_t i = 0; i < search_interval_tree_buffer->num_overlaps;
697 ++i) {
698 (*overlap_cells)[(*num_overlap_cells)+i] =
699 node->I.ivt.head_node[
700 search_interval_tree_buffer->overlap_iv[i]].value;
701 }
702
703 *num_overlap_cells += search_interval_tree_buffer->num_overlaps;
704
705 } else {
706
707 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
708 *num_overlap_cells + node->I_size);
709 memcpy(*overlap_cells + *num_overlap_cells, node->I.list,
710 node->I_size * sizeof(**overlap_cells));
711 *num_overlap_cells += node->I_size;
712 }
713 }
714
715 //! TODO change to iterative implementation and allocate overlap_cells first
search_big_bnd_circle(struct sphere_part_node * node,struct bounding_circle bnd_circle,size_t ** restrict overlap_cells,size_t * overlap_cells_array_size,size_t * restrict num_overlap_cells,struct overlaps * search_interval_tree_buffer,double prev_gc_norm_vector[])716 static void search_big_bnd_circle(
717 struct sphere_part_node * node, struct bounding_circle bnd_circle,
718 size_t ** restrict overlap_cells, size_t * overlap_cells_array_size,
719 size_t * restrict num_overlap_cells,
720 struct overlaps * search_interval_tree_buffer, double prev_gc_norm_vector[]) {
721
722 if (node->flags & T_IS_LEAF) {
723
724 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
725 *num_overlap_cells + node->T_size);
726 memcpy(*overlap_cells + *num_overlap_cells, node->T,
727 node->T_size * sizeof(**overlap_cells));
728 *num_overlap_cells += node->T_size;
729
730 } else {
731 search_big_bnd_circle(
732 node->T, bnd_circle, overlap_cells, overlap_cells_array_size,
733 num_overlap_cells, search_interval_tree_buffer, node->gc_norm_vector);
734 }
735
736 if (node->flags & U_IS_LEAF) {
737
738 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
739 *num_overlap_cells + node->U_size);
740 memcpy(*overlap_cells + *num_overlap_cells, node->U,
741 node->U_size * sizeof(**overlap_cells));
742 *num_overlap_cells += node->U_size;
743
744 } else {
745 search_big_bnd_circle(
746 node->U, bnd_circle, overlap_cells, overlap_cells_array_size,
747 num_overlap_cells, search_interval_tree_buffer, node->gc_norm_vector);
748 }
749
750 search_bnd_circle_I_node(
751 node, bnd_circle, overlap_cells, overlap_cells_array_size,
752 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
753 }
754
search_small_bnd_circle(struct sphere_part_node * node,struct bounding_circle bnd_circle,size_t ** restrict overlap_cells,size_t * overlap_cells_array_size,size_t * restrict num_overlap_cells,struct overlaps * search_interval_tree_buffer,double prev_gc_norm_vector[])755 static void search_small_bnd_circle(
756 struct sphere_part_node * node, struct bounding_circle bnd_circle,
757 size_t ** restrict overlap_cells, size_t * overlap_cells_array_size,
758 size_t * restrict num_overlap_cells,
759 struct overlaps * search_interval_tree_buffer, double prev_gc_norm_vector[]) {
760
761 double dot = bnd_circle.base_vector[0] * node->gc_norm_vector[0] +
762 bnd_circle.base_vector[1] * node->gc_norm_vector[1] +
763 bnd_circle.base_vector[2] * node->gc_norm_vector[2];
764
765 // angle < M_PI_2 + bnd_circle.inc_angle
766 if (dot > - bnd_circle.inc_angle.sin) {
767
768 if (node->flags & T_IS_LEAF) {
769
770 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
771 *num_overlap_cells + node->T_size);
772 memcpy(*overlap_cells + *num_overlap_cells, node->T,
773 node->T_size * sizeof(**overlap_cells));
774 *num_overlap_cells += node->T_size;
775
776 } else {
777 search_small_bnd_circle(
778 node->T, bnd_circle, overlap_cells, overlap_cells_array_size,
779 num_overlap_cells, search_interval_tree_buffer,
780 node->gc_norm_vector);
781 }
782 }
783
784 // angle > M_PI_2 - bnd_circle.inc_angle
785 if (dot < bnd_circle.inc_angle.sin) {
786
787 if (node->flags & U_IS_LEAF) {
788
789 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
790 *num_overlap_cells + node->U_size);
791 memcpy(*overlap_cells + *num_overlap_cells, node->U,
792 node->U_size * sizeof(**overlap_cells));
793 *num_overlap_cells += node->U_size;
794
795 } else {
796 search_small_bnd_circle(
797 node->U, bnd_circle, overlap_cells, overlap_cells_array_size,
798 num_overlap_cells, search_interval_tree_buffer,
799 node->gc_norm_vector);
800 }
801 }
802
803 struct sin_cos_angle angle_sum =
804 sum_angles_no_check(node->I_angle, bnd_circle.inc_angle);
805
806 // if (I_angle + inc_angle > PI/2) ||
807 // (fabs(angle - M_PI_2) <= (I_angle + inc_angle))
808 //
809 // assumtion:
810 // I_angle >= 0 && I_angle <= PI/2
811 // inc_angle >= 0 && inc_angle <= PI/2
812 // angle >= 0 && angle <= PI
813 //
814 // => I_angle + inc_angle >= 0 && I_angle + inc_angle <= PI
815 //
816 // I_angle + inc_angle >= PI/2
817 //
818 // fabs(angle - M_PI_2) <= (I_angle + inc_angle)
819 // => sin(fabs(angle - M_PI_2)) <= sin(I_angle + inc_angle)
820 // this is wrong for (I_angle + inc_angle) > PI/2, however that case is
821 // already covered by the first condition
822 // => fabs(cos(angle)) <= sin(I_angle + inc_angle)
823 if (((angle_sum.sin < 0.0) || (angle_sum.cos <= 0.0)) ||
824 (fabs(dot) <= angle_sum.sin)) {
825 search_bnd_circle_I_node(
826 node, bnd_circle, overlap_cells, overlap_cells_array_size,
827 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
828 }
829 }
830
search_bnd_circle(struct sphere_part_node * node,struct bounding_circle bnd_circle,size_t ** restrict overlap_cells,size_t * overlap_cells_array_size,size_t * restrict num_overlap_cells,struct overlaps * search_interval_tree_buffer,double prev_gc_norm_vector[])831 static void search_bnd_circle(struct sphere_part_node * node,
832 struct bounding_circle bnd_circle,
833 size_t ** restrict overlap_cells,
834 size_t * overlap_cells_array_size,
835 size_t * restrict num_overlap_cells,
836 struct overlaps * search_interval_tree_buffer,
837 double prev_gc_norm_vector[]) {
838
839 // if the bounding circle has an angle in the range of [0;PI/2[
840 if (bnd_circle.inc_angle.cos > 0.0)
841 search_small_bnd_circle(
842 node, bnd_circle, overlap_cells, overlap_cells_array_size,
843 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
844 else
845 search_big_bnd_circle(
846 node, bnd_circle, overlap_cells, overlap_cells_array_size,
847 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
848 }
849
check_leaf_NN(struct point_id_xyz * points,size_t num_points,double * point_coordinates_xyz,struct sin_cos_angle * best_angle,double (** result_coordinates_xyz)[3],size_t * result_coordinates_xyz_array_size,size_t ** local_point_ids,size_t * local_point_ids_array_size,size_t total_num_local_point_ids,size_t * num_local_point_ids)850 static inline void check_leaf_NN(
851 struct point_id_xyz * points, size_t num_points,
852 double * point_coordinates_xyz, struct sin_cos_angle * best_angle,
853 double (**result_coordinates_xyz)[3],
854 size_t * result_coordinates_xyz_array_size, size_t ** local_point_ids,
855 size_t * local_point_ids_array_size, size_t total_num_local_point_ids,
856 size_t * num_local_point_ids) {
857
858 size_t * local_point_ids_ = *local_point_ids;
859 size_t local_point_ids_array_size_ = *local_point_ids_array_size;
860 double (*result_coordinates_xyz_)[3];
861 size_t result_coordinates_xyz_array_size_;
862 size_t num_local_point_ids_ = *num_local_point_ids;
863
864 if (result_coordinates_xyz != NULL) {
865 result_coordinates_xyz_ = *result_coordinates_xyz;
866 result_coordinates_xyz_array_size_ = *result_coordinates_xyz_array_size;
867 ENSURE_ARRAY_SIZE(
868 result_coordinates_xyz_, result_coordinates_xyz_array_size_,
869 total_num_local_point_ids + num_local_point_ids_ + num_points);
870 *result_coordinates_xyz = result_coordinates_xyz_;
871 *result_coordinates_xyz_array_size = result_coordinates_xyz_array_size_;
872 result_coordinates_xyz_ += total_num_local_point_ids;
873 }
874 ENSURE_ARRAY_SIZE(
875 local_point_ids_, local_point_ids_array_size_,
876 total_num_local_point_ids + num_local_point_ids_ + num_points);
877 *local_point_ids = local_point_ids_;
878 *local_point_ids_array_size = local_point_ids_array_size_;
879 local_point_ids_ += total_num_local_point_ids;
880
881
882 // check leaf for results
883 for (size_t i = 0; i < num_points; ++i) {
884
885 struct sin_cos_angle curr_angle =
886 get_vector_angle_2(
887 points[i].coordinates_xyz, point_coordinates_xyz);
888 int compare = compare_angles(curr_angle, *best_angle);
889
890 // if the point is worse than the currently best point
891 if (compare > 0) continue;
892
893 // if we found a better point
894 if (compare < 0) {
895
896 *best_angle = curr_angle;
897 num_local_point_ids_ = 1;
898 if (result_coordinates_xyz != NULL) {
899 result_coordinates_xyz_[0][0] = points[i].coordinates_xyz[0];
900 result_coordinates_xyz_[0][1] = points[i].coordinates_xyz[1];
901 result_coordinates_xyz_[0][2] = points[i].coordinates_xyz[2];
902 }
903 local_point_ids_[0] = points[i].idx;
904
905 } else {
906
907 if (result_coordinates_xyz != NULL) {
908 result_coordinates_xyz_[num_local_point_ids_][0] =
909 points[i].coordinates_xyz[0];
910 result_coordinates_xyz_[num_local_point_ids_][1] =
911 points[i].coordinates_xyz[1];
912 result_coordinates_xyz_[num_local_point_ids_][2] =
913 points[i].coordinates_xyz[2];
914 }
915 local_point_ids_[num_local_point_ids_] = points[i].idx;
916 num_local_point_ids_++;
917 }
918 }
919
920 *num_local_point_ids = num_local_point_ids_;
921 }
922
point_search_NN(struct bounding_circle * bnd_circle,double (** result_coordinates_xyz)[3],size_t * result_coordinates_xyz_array_size,size_t ** local_point_ids,size_t * local_point_ids_array_size,size_t total_num_local_point_ids,size_t * num_local_point_ids,double * dot_stack,struct point_sphere_part_node ** node_stack,int * flags,size_t curr_tree_depth)923 static void point_search_NN(
924 struct bounding_circle * bnd_circle, double (**result_coordinates_xyz)[3],
925 size_t * result_coordinates_xyz_array_size, size_t ** local_point_ids,
926 size_t * local_point_ids_array_size, size_t total_num_local_point_ids,
927 size_t * num_local_point_ids, double * dot_stack,
928 struct point_sphere_part_node ** node_stack,
929 int * flags, size_t curr_tree_depth) {
930
931 double * point_coordinates_xyz = bnd_circle->base_vector;
932 struct sin_cos_angle best_angle = bnd_circle->inc_angle;
933
934 double dot = dot_stack[curr_tree_depth];
935 struct point_sphere_part_node * node = node_stack[curr_tree_depth];
936 int skip_U = flags[curr_tree_depth] & U_FLAG;
937 int skip_T = flags[curr_tree_depth] & T_FLAG;
938
939 do {
940
941 if (!skip_U) {
942
943 flags[curr_tree_depth] |= U_FLAG;
944
945 // angle + inc_angle >= M_PI_2
946 if ((dot < best_angle.sin) | (best_angle.cos <= 0.0)) {
947
948 if (node->flags & U_IS_LEAF) {
949
950 check_leaf_NN(
951 (struct point_id_xyz *)(node->U), node->U_size,
952 point_coordinates_xyz, &best_angle, result_coordinates_xyz,
953 result_coordinates_xyz_array_size, local_point_ids,
954 local_point_ids_array_size, total_num_local_point_ids,
955 num_local_point_ids);
956
957 } else {
958
959 // traverse down one level
960 ++curr_tree_depth;
961 node = (struct point_sphere_part_node *)(node->U);
962 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
963 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
964 node->gc_norm_vector[2] * point_coordinates_xyz[2];
965 dot_stack[curr_tree_depth] = dot;
966 node_stack[curr_tree_depth] = node;
967 flags[curr_tree_depth] = 0;
968 skip_U = 0;
969 skip_T = 0;
970 continue;
971 }
972 }
973 }
974
975 if (!skip_T) {
976
977 flags[curr_tree_depth] = U_FLAG + T_FLAG;
978
979 // angle - inc_angle < M_PI_2
980 if ((dot > - best_angle.sin) || (best_angle.cos <= 0.0)) {
981
982 if (node->flags & T_IS_LEAF) {
983
984 check_leaf_NN(
985 (struct point_id_xyz *)(node->T), node->T_size,
986 point_coordinates_xyz, &best_angle, result_coordinates_xyz,
987 result_coordinates_xyz_array_size, local_point_ids,
988 local_point_ids_array_size, total_num_local_point_ids,
989 num_local_point_ids);
990
991 } else {
992
993 // traverse down one level
994 ++curr_tree_depth;
995 node = (struct point_sphere_part_node *)(node->T);
996 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
997 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
998 node->gc_norm_vector[2] * point_coordinates_xyz[2];
999 dot_stack[curr_tree_depth] = dot;
1000 node_stack[curr_tree_depth] = node;
1001 flags[curr_tree_depth] = 0;
1002 skip_U = 0;
1003 skip_T = 0;
1004 continue;
1005 }
1006 }
1007 }
1008
1009 if (curr_tree_depth == 0) break;
1010
1011 // go up one level in the tree
1012
1013 curr_tree_depth--;
1014 dot = dot_stack[curr_tree_depth];
1015 node = node_stack[curr_tree_depth];
1016 skip_U = flags[curr_tree_depth] & U_FLAG;
1017 skip_T = flags[curr_tree_depth] & T_FLAG;
1018
1019 } while (1);
1020
1021 bnd_circle->inc_angle = best_angle;
1022 }
1023
point_check_bnd_circle(struct point_sphere_part_node * node,struct bounding_circle bnd_circle)1024 static int point_check_bnd_circle(
1025 struct point_sphere_part_node * node, struct bounding_circle bnd_circle) {
1026
1027 double dot = node->gc_norm_vector[0]*bnd_circle.base_vector[0] +
1028 node->gc_norm_vector[1]*bnd_circle.base_vector[1] +
1029 node->gc_norm_vector[2]*bnd_circle.base_vector[2];
1030
1031 int ret = 0;
1032
1033 // angle + inc_angle >= M_PI_2
1034 if (dot <= bnd_circle.inc_angle.sin) {
1035
1036 if (node->flags & U_IS_LEAF) {
1037
1038 struct point_id_xyz * U = (struct point_id_xyz *)(node->U);
1039 size_t U_size = node->U_size;
1040 for (size_t i = 0; i < U_size; ++i) {
1041 double cos_angle =
1042 U[i].coordinates_xyz[0] * bnd_circle.base_vector[0] +
1043 U[i].coordinates_xyz[1] * bnd_circle.base_vector[1] +
1044 U[i].coordinates_xyz[2] * bnd_circle.base_vector[2];
1045 if (cos_angle > bnd_circle.inc_angle.cos) return 1;
1046 }
1047
1048 } else {
1049 ret = point_check_bnd_circle(node->U, bnd_circle);
1050 }
1051 }
1052
1053 // angle - inc_angle < M_PI_2
1054 if ((!ret) && (dot > - bnd_circle.inc_angle.sin)) {
1055
1056 if (node->flags & T_IS_LEAF) {
1057
1058 struct point_id_xyz * T = (struct point_id_xyz *)(node->T);
1059 size_t T_size = node->T_size;
1060 for (size_t i = 0; i < T_size; ++i) {
1061 double cos_angle =
1062 T[i].coordinates_xyz[0] * bnd_circle.base_vector[0] +
1063 T[i].coordinates_xyz[1] * bnd_circle.base_vector[1] +
1064 T[i].coordinates_xyz[2] * bnd_circle.base_vector[2];
1065 if (cos_angle > bnd_circle.inc_angle.cos) return 1;
1066 }
1067
1068 } else {
1069 ret = point_check_bnd_circle(node->T, bnd_circle);
1070 }
1071 }
1072
1073 return ret;
1074 }
1075
leaf_contains_matching_points(struct point_id_xyz * points,size_t num_points,double coordinate_xyz[3],size_t ** local_point_ids,size_t * local_point_ids_array_size,double (** result_coordinates_xyz)[3],size_t * result_coordinates_xyz_array_size,size_t total_num_local_point_ids,size_t * num_local_point_ids)1076 static inline int leaf_contains_matching_points(
1077 struct point_id_xyz * points, size_t num_points, double coordinate_xyz[3],
1078 size_t ** local_point_ids, size_t * local_point_ids_array_size,
1079 double (**result_coordinates_xyz)[3],
1080 size_t * result_coordinates_xyz_array_size,
1081 size_t total_num_local_point_ids, size_t * num_local_point_ids) {
1082
1083 for (size_t i = 0; i < num_points; ++i) {
1084
1085 // if the points are nearly identical
1086 if ((fabs(points[i].coordinates_xyz[0] - coordinate_xyz[0]) < yac_angle_tol) &&
1087 (fabs(points[i].coordinates_xyz[1] - coordinate_xyz[1]) < yac_angle_tol) &&
1088 (fabs(points[i].coordinates_xyz[2] - coordinate_xyz[2]) < yac_angle_tol)) {
1089
1090 ENSURE_ARRAY_SIZE(*local_point_ids, *local_point_ids_array_size,
1091 total_num_local_point_ids + num_points - i);
1092 size_t * local_point_ids_ =
1093 (*local_point_ids) + total_num_local_point_ids;
1094
1095 double (*result_coordinates_xyz_)[3];
1096
1097 if (result_coordinates_xyz != NULL) {
1098 ENSURE_ARRAY_SIZE(*result_coordinates_xyz,
1099 *result_coordinates_xyz_array_size,
1100 total_num_local_point_ids + num_points - i);
1101 result_coordinates_xyz_ =
1102 (*result_coordinates_xyz) + total_num_local_point_ids;
1103 } else {
1104 result_coordinates_xyz_ = NULL;
1105 }
1106
1107 local_point_ids_[0] = points[i].idx;
1108 if (result_coordinates_xyz_ != NULL) {
1109 result_coordinates_xyz_[0][0] = points[i].coordinates_xyz[0];
1110 result_coordinates_xyz_[0][1] = points[i].coordinates_xyz[1];
1111 result_coordinates_xyz_[0][2] = points[i].coordinates_xyz[2];
1112 }
1113
1114 size_t num_local_point_ids_ = 1;
1115
1116 for (i += 1; i < num_points; ++i) {
1117 // if the points are nearly identical
1118 if ((fabs(points[i].coordinates_xyz[0] - coordinate_xyz[0]) < yac_angle_tol) &&
1119 (fabs(points[i].coordinates_xyz[1] - coordinate_xyz[1]) < yac_angle_tol) &&
1120 (fabs(points[i].coordinates_xyz[2] - coordinate_xyz[2]) < yac_angle_tol)) {
1121
1122 local_point_ids_[num_local_point_ids_] = points[i].idx;
1123 if (result_coordinates_xyz_ != NULL) {
1124 result_coordinates_xyz_[num_local_point_ids_][0] =
1125 points[i].coordinates_xyz[0];
1126 result_coordinates_xyz_[num_local_point_ids_][1] =
1127 points[i].coordinates_xyz[1];
1128 result_coordinates_xyz_[num_local_point_ids_][2] =
1129 points[i].coordinates_xyz[2];
1130 }
1131 ++num_local_point_ids_;
1132 }
1133 }
1134
1135 *num_local_point_ids = num_local_point_ids_;
1136
1137 return 1;
1138 }
1139 }
1140
1141 return 0;
1142 }
1143
yac_point_sphere_part_search_NN(struct point_sphere_part_search * search,size_t num_points,double (* coordinates_xyz)[3],double * cos_angles,double (** result_coordinates_xyz)[3],size_t * result_coordinates_xyz_array_size,size_t ** local_point_ids,size_t * local_point_ids_array_size,size_t * num_local_point_ids)1144 void yac_point_sphere_part_search_NN(struct point_sphere_part_search * search,
1145 size_t num_points,
1146 double (*coordinates_xyz)[3],
1147 double * cos_angles,
1148 double (**result_coordinates_xyz)[3],
1149 size_t * result_coordinates_xyz_array_size,
1150 size_t ** local_point_ids,
1151 size_t * local_point_ids_array_size,
1152 size_t * num_local_point_ids) {
1153
1154 memset(num_local_point_ids, 0, num_points * sizeof(*num_local_point_ids));
1155
1156 if (search == NULL) return;
1157
1158 struct point_sphere_part_node * base_node = &(search->base_node);
1159
1160 size_t total_num_local_point_ids = 0;
1161
1162 double * dot_stack = xmalloc(search->max_tree_depth * sizeof(*dot_stack));
1163 struct point_sphere_part_node ** node_stack =
1164 xmalloc(search->max_tree_depth * sizeof(*node_stack));
1165 int * flags = xmalloc(search->max_tree_depth * sizeof(*flags));
1166
1167 for (size_t i = 0; i < num_points; ++i) {
1168
1169 struct point_sphere_part_node * curr_node = base_node;
1170
1171 double * curr_coordinates_xyz = coordinates_xyz[i];
1172
1173 size_t curr_tree_depth = 0;
1174 struct point_id_xyz * points = NULL;
1175 size_t curr_num_points = 0;
1176
1177 // get the matching leaf for the current point
1178 do {
1179
1180 double dot = curr_node->gc_norm_vector[0]*curr_coordinates_xyz[0] +
1181 curr_node->gc_norm_vector[1]*curr_coordinates_xyz[1] +
1182 curr_node->gc_norm_vector[2]*curr_coordinates_xyz[2];
1183
1184 dot_stack[curr_tree_depth] = dot;
1185 node_stack[curr_tree_depth] = curr_node;
1186 flags[curr_tree_depth] = 0;
1187
1188 // angle > M_PI_2
1189 if (dot < yac_angle_tol) {
1190
1191 flags[curr_tree_depth] = U_FLAG;
1192
1193 if (curr_node->flags & U_IS_LEAF) {
1194 if (curr_node->U_size > 0) {
1195 points = (struct point_id_xyz*)(curr_node->U);
1196 curr_num_points = curr_node->U_size;
1197 break;
1198 } else {
1199 flags[curr_tree_depth] = T_FLAG;
1200 if (curr_node->flags & T_IS_LEAF) {
1201 points = (struct point_id_xyz*)(curr_node->T);
1202 curr_num_points = curr_node->T_size;
1203 break;
1204 } else {
1205 curr_node = curr_node->T;
1206 }
1207 }
1208 } else curr_node = curr_node->U;
1209
1210 // angle < M_PI_2
1211 } else if (dot > -yac_angle_tol) {
1212
1213 flags[curr_tree_depth] = T_FLAG;
1214
1215 if (curr_node->flags & T_IS_LEAF) {
1216 if (curr_node->T_size > 0) {
1217 points = (struct point_id_xyz*)(curr_node->T);
1218 curr_num_points = curr_node->T_size;
1219 break;
1220 } else {
1221 flags[curr_tree_depth] = U_FLAG;
1222 if (curr_node->flags & U_IS_LEAF) {
1223 points = (struct point_id_xyz*)(curr_node->U);
1224 curr_num_points = curr_node->U_size;
1225 break;
1226 } else {
1227 curr_node = curr_node->U;
1228 }
1229 }
1230 } else curr_node = curr_node->T;
1231 }
1232
1233 curr_tree_depth++;
1234 } while (1);
1235
1236 // if we do not have to do a finer search
1237 if (leaf_contains_matching_points(
1238 points, curr_num_points, curr_coordinates_xyz, local_point_ids,
1239 local_point_ids_array_size, result_coordinates_xyz,
1240 result_coordinates_xyz_array_size, total_num_local_point_ids,
1241 num_local_point_ids + i)) {
1242
1243 if (cos_angles != NULL) cos_angles[i] = 1.0;
1244
1245 } else {
1246
1247 struct bounding_circle bnd_circle;
1248 bnd_circle.base_vector[0] = curr_coordinates_xyz[0];
1249 bnd_circle.base_vector[1] = curr_coordinates_xyz[1];
1250 bnd_circle.base_vector[2] = curr_coordinates_xyz[2];
1251 bnd_circle.inc_angle = SIN_COS_M_PI;
1252
1253 check_leaf_NN(
1254 points, curr_num_points, curr_coordinates_xyz, &(bnd_circle.inc_angle),
1255 result_coordinates_xyz, result_coordinates_xyz_array_size,
1256 local_point_ids, local_point_ids_array_size, total_num_local_point_ids,
1257 num_local_point_ids + i);
1258
1259 // get best result points
1260 point_search_NN(
1261 &bnd_circle, result_coordinates_xyz, result_coordinates_xyz_array_size,
1262 local_point_ids, local_point_ids_array_size, total_num_local_point_ids,
1263 num_local_point_ids + i, dot_stack, node_stack, flags, curr_tree_depth);
1264
1265 if (cos_angles != NULL) cos_angles[i] = bnd_circle.inc_angle.cos;
1266 }
1267
1268 total_num_local_point_ids += num_local_point_ids[i];
1269 }
1270
1271 free(flags);
1272 free(node_stack);
1273 free(dot_stack);
1274 }
1275
compare_point_id_xyz_angle(const void * a,const void * b)1276 static inline int compare_point_id_xyz_angle(const void * a, const void * b) {
1277
1278 const struct point_id_xyz_angle * p_a = (const struct point_id_xyz_angle *)a;
1279 const struct point_id_xyz_angle * p_b = (const struct point_id_xyz_angle *)b;
1280
1281 int ret = (p_a->cos_angle < p_b->cos_angle) -
1282 (p_a->cos_angle > p_b->cos_angle);
1283
1284 if (ret != 0) return ret;
1285
1286 return (p_a->idx > p_b->idx) - (p_a->idx < p_b->idx);
1287 }
1288
initial_point_bnd_search_NNN(size_t n,struct point_id_xyz * points,size_t num_points,double * point_coordinates_xyz,struct point_id_xyz_angle ** results,size_t * results_array_size)1289 static size_t initial_point_bnd_search_NNN(
1290 size_t n, struct point_id_xyz * points, size_t num_points,
1291 double * point_coordinates_xyz, struct point_id_xyz_angle ** results,
1292 size_t * results_array_size) {
1293
1294 assert(num_points > 0);
1295
1296 ENSURE_ARRAY_SIZE(*results, *results_array_size, num_points);
1297 struct point_id_xyz_angle * results_ = *results;
1298
1299 for (size_t i = 0; i < num_points; ++i) {
1300
1301 *(struct point_id_xyz*)(results_ + i) = points[i];
1302 results_[i].cos_angle = clamp_abs_one(
1303 points[i].coordinates_xyz[0] * point_coordinates_xyz[0] +
1304 points[i].coordinates_xyz[1] * point_coordinates_xyz[1] +
1305 points[i].coordinates_xyz[2] * point_coordinates_xyz[2]);
1306 }
1307
1308 qsort(results_, num_points, sizeof(*results_), compare_point_id_xyz_angle);
1309
1310 if (num_points <= n) return num_points;
1311
1312 size_t num_results;
1313 double min_cos_angle = results_[n - 1].cos_angle;
1314
1315 for (num_results = n;
1316 (num_results < num_points) &&
1317 !(fabs(min_cos_angle - results_[num_results].cos_angle) > 0.0);
1318 ++num_results);
1319
1320 return num_results;
1321 }
1322
check_leaf_NNN(size_t n,double * point_coordinates_xyz,struct point_id_xyz * points,size_t num_points,struct point_id_xyz_angle ** results,size_t * results_array_size,size_t * num_results,struct sin_cos_angle curr_angle)1323 static inline struct sin_cos_angle check_leaf_NNN(
1324 size_t n, double * point_coordinates_xyz,
1325 struct point_id_xyz * points, size_t num_points,
1326 struct point_id_xyz_angle ** results, size_t * results_array_size,
1327 size_t * num_results, struct sin_cos_angle curr_angle) {
1328
1329 size_t num_results_ = *num_results;
1330 ENSURE_ARRAY_SIZE(*results, *results_array_size, num_results_ + num_points);
1331 struct point_id_xyz_angle * results_ = *results;
1332
1333 int flag = 0;
1334
1335 double min_cos_angle = results_[num_results_-1].cos_angle;
1336
1337 // check leaf for results
1338 for (size_t i = 0; i < num_points; ++i) {
1339
1340 double curr_cos_angle =
1341 points[i].coordinates_xyz[0] * point_coordinates_xyz[0] +
1342 points[i].coordinates_xyz[1] * point_coordinates_xyz[1] +
1343 points[i].coordinates_xyz[2] * point_coordinates_xyz[2];
1344
1345 // if the point is worse than the currently best point
1346 if (curr_cos_angle < min_cos_angle) continue;
1347
1348 struct point_id_xyz_angle point;
1349 *(struct point_id_xyz*)(&point) = points[i];
1350 point.cos_angle = curr_cos_angle;
1351
1352 // insert point
1353 size_t j;
1354 for (j = 0; j < num_results_; ++j) {
1355
1356 if (compare_point_id_xyz_angle(
1357 &point, results_ + num_results_ - j - 1) < 0) {
1358 results_[num_results_ - j] = results_[num_results_ - j - 1];
1359 } else {
1360 break;
1361 }
1362 }
1363 results_[num_results_ - j] = point;
1364
1365 ++num_results_;
1366 flag = 1;
1367 }
1368
1369 if (flag) {
1370
1371 if (num_results_ > n) {
1372
1373 size_t new_num_results;
1374 min_cos_angle = results_[n - 1].cos_angle;
1375
1376 for (new_num_results = n;
1377 (new_num_results < num_results_) &&
1378 !(fabs(min_cos_angle - results_[new_num_results].cos_angle) > 0.0);
1379 ++new_num_results);
1380 num_results_ = new_num_results;
1381 }
1382 *num_results = num_results_;
1383
1384 return
1385 get_vector_angle_2(
1386 results_[num_results_-1].coordinates_xyz, point_coordinates_xyz);
1387 } else return curr_angle;
1388 }
1389
point_search_NNN(size_t n,double * point_coordinates_xyz,struct point_id_xyz_angle ** results,size_t * results_array_size,size_t * num_results,double * dot_stack,struct point_sphere_part_node ** node_stack,int * flags,size_t curr_tree_depth)1390 static void point_search_NNN(
1391 size_t n, double * point_coordinates_xyz,
1392 struct point_id_xyz_angle ** results, size_t * results_array_size,
1393 size_t * num_results, double * dot_stack,
1394 struct point_sphere_part_node ** node_stack, int * flags,
1395 size_t curr_tree_depth) {
1396
1397 struct sin_cos_angle angle =
1398 get_vector_angle_2(
1399 (*results)[(*num_results)-1].coordinates_xyz, point_coordinates_xyz);
1400
1401 // if we have already found at least n exactly matching points
1402 if ((*num_results >= n) && (angle.sin <= yac_angle_tol)) return;
1403
1404 double dot = dot_stack[curr_tree_depth];
1405 struct point_sphere_part_node * node = node_stack[curr_tree_depth];
1406 int skip_U = flags[curr_tree_depth] & U_FLAG;
1407 int skip_T = flags[curr_tree_depth] & T_FLAG;
1408
1409 do {
1410
1411 if (!skip_U) {
1412
1413 flags[curr_tree_depth] |= U_FLAG;
1414
1415 // angle + inc_angle >= M_PI_2
1416 if ((dot < angle.sin) | (angle.cos <= 0.0)) {
1417
1418 if (node->flags & U_IS_LEAF) {
1419
1420 angle = check_leaf_NNN(
1421 n, point_coordinates_xyz, (struct point_id_xyz *)(node->U),
1422 node->U_size, results, results_array_size, num_results, angle);
1423
1424 } else {
1425
1426 // traverse down one level
1427 ++curr_tree_depth;
1428 node = (struct point_sphere_part_node *)(node->U);
1429 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1430 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1431 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1432 dot_stack[curr_tree_depth] = dot;
1433 node_stack[curr_tree_depth] = node;
1434 flags[curr_tree_depth] = 0;
1435 skip_U = 0;
1436 skip_T = 0;
1437 continue;
1438 }
1439 }
1440 }
1441
1442 if (!skip_T) {
1443
1444 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1445
1446 // angle - inc_angle < M_PI_2
1447 if ((dot > - angle.sin) || (angle.cos <= 0.0)) {
1448
1449 if (node->flags & T_IS_LEAF) {
1450
1451 angle = check_leaf_NNN(
1452 n, point_coordinates_xyz, (struct point_id_xyz *)(node->T),
1453 node->T_size, results, results_array_size, num_results, angle);
1454
1455 } else {
1456
1457 // traverse down one level
1458 ++curr_tree_depth;
1459 node = (struct point_sphere_part_node *)(node->T);
1460 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1461 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1462 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1463 dot_stack[curr_tree_depth] = dot;
1464 node_stack[curr_tree_depth] = node;
1465 flags[curr_tree_depth] = 0;
1466 skip_U = 0;
1467 skip_T = 0;
1468 continue;
1469 }
1470 }
1471 }
1472
1473 if (curr_tree_depth == 0) break;
1474
1475 // go up one level in the tree
1476
1477 curr_tree_depth--;
1478 dot = dot_stack[curr_tree_depth];
1479 node = node_stack[curr_tree_depth];
1480 skip_U = flags[curr_tree_depth] & U_FLAG;
1481 skip_T = flags[curr_tree_depth] & T_FLAG;
1482
1483 } while (1);
1484 }
1485
yac_point_sphere_part_search_NNN(struct point_sphere_part_search * search,size_t num_points,double (* coordinates_xyz)[3],size_t n,double ** cos_angles,size_t * cos_angles_array_size,double (** result_coordinates_xyz)[3],size_t * result_coordinates_xyz_array_size,size_t ** local_point_ids,size_t * local_point_ids_array_size,size_t * num_local_point_ids)1486 void yac_point_sphere_part_search_NNN(struct point_sphere_part_search * search,
1487 size_t num_points,
1488 double (*coordinates_xyz)[3], size_t n,
1489 double ** cos_angles,
1490 size_t * cos_angles_array_size,
1491 double (**result_coordinates_xyz)[3],
1492 size_t * result_coordinates_xyz_array_size,
1493 size_t ** local_point_ids,
1494 size_t * local_point_ids_array_size,
1495 size_t * num_local_point_ids) {
1496
1497 if (cos_angles != NULL)
1498 ENSURE_ARRAY_SIZE(*cos_angles, *cos_angles_array_size, num_points * n);
1499
1500 if (n == 1) {
1501 yac_point_sphere_part_search_NN(
1502 search, num_points, coordinates_xyz, (cos_angles!=NULL)?*cos_angles:NULL,
1503 result_coordinates_xyz, result_coordinates_xyz_array_size,
1504 local_point_ids, local_point_ids_array_size, num_local_point_ids);
1505
1506 size_t total_num_local_points = 0;
1507 for (size_t i = 0; i < num_points; ++i)
1508 total_num_local_points += num_local_point_ids[i];
1509
1510 if ((cos_angles != NULL) && (total_num_local_points > num_points)) {
1511
1512 ENSURE_ARRAY_SIZE(*cos_angles, *cos_angles_array_size,
1513 total_num_local_points);
1514
1515 for (size_t i = num_points - 1, offset = total_num_local_points - 1;
1516 i < num_points; i--) {
1517
1518 for (size_t j = 0; j < num_local_point_ids[i]; ++j, --offset)
1519 (*cos_angles)[offset] = (*cos_angles)[i];
1520 }
1521 }
1522 return;
1523 }
1524
1525
1526 if (search == NULL) {
1527 memset(num_local_point_ids, 0, num_points * sizeof(*num_local_point_ids));
1528 return;
1529 }
1530
1531 struct point_sphere_part_node * base_node = &(search->base_node);
1532
1533 size_t total_num_local_point_ids = 0;
1534
1535 double * dot_stack = xmalloc(search->max_tree_depth * sizeof(*dot_stack));
1536 struct point_sphere_part_node ** node_stack =
1537 xmalloc(search->max_tree_depth * sizeof(*node_stack));
1538 int * flags = xmalloc(search->max_tree_depth * sizeof(*flags));
1539
1540 struct point_id_xyz_angle * results = NULL;
1541 size_t results_array_size = 0;
1542
1543 for (size_t i = 0; i < num_points; ++i) {
1544
1545 struct point_sphere_part_node * curr_node = base_node;
1546
1547 double * curr_coordinates_xyz = coordinates_xyz[i];
1548
1549 size_t curr_tree_depth = 0;
1550 struct point_id_xyz * points = search->points;
1551 size_t curr_num_points = 0;
1552
1553 // get the matching leaf for the current point
1554 do {
1555
1556 double dot = curr_node->gc_norm_vector[0]*curr_coordinates_xyz[0] +
1557 curr_node->gc_norm_vector[1]*curr_coordinates_xyz[1] +
1558 curr_node->gc_norm_vector[2]*curr_coordinates_xyz[2];
1559
1560 dot_stack[curr_tree_depth] = dot;
1561 node_stack[curr_tree_depth] = curr_node;
1562 flags[curr_tree_depth] = 0;
1563
1564 // angle >= M_PI_2
1565 if (dot <= 0.0) {
1566
1567 if (curr_node->U_size < n) {
1568
1569 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1570 curr_num_points = curr_node->U_size + curr_node->T_size;
1571 break;
1572 } else if (curr_node->flags & U_IS_LEAF) {
1573
1574 flags[curr_tree_depth] = U_FLAG;
1575 curr_num_points = curr_node->U_size;
1576 break;
1577 } else {
1578
1579 flags[curr_tree_depth] = U_FLAG;
1580 curr_node = curr_node->U;
1581 }
1582
1583 } else {
1584
1585 if (curr_node->T_size < n) {
1586
1587 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1588 curr_num_points = curr_node->U_size + curr_node->T_size;
1589 break;
1590 } else if (curr_node->flags & T_IS_LEAF) {
1591
1592 points += curr_node->U_size;
1593 flags[curr_tree_depth] = T_FLAG;
1594 curr_num_points = curr_node->T_size;
1595 break;
1596 } else {
1597
1598 points += curr_node->U_size;
1599 flags[curr_tree_depth] = T_FLAG;
1600 curr_node = curr_node->T;
1601 }
1602 }
1603
1604 curr_tree_depth++;
1605 } while (1);
1606
1607 assert(curr_num_points > 0);
1608
1609 size_t num_results =
1610 initial_point_bnd_search_NNN(
1611 n, points, curr_num_points, curr_coordinates_xyz,
1612 &results, &results_array_size);
1613
1614 // do a detailed search
1615 point_search_NNN(
1616 n, curr_coordinates_xyz, &results, &results_array_size, &num_results,
1617 dot_stack, node_stack, flags, curr_tree_depth);
1618
1619 // extract the results
1620 ENSURE_ARRAY_SIZE(*local_point_ids, *local_point_ids_array_size,
1621 total_num_local_point_ids + num_results);
1622 size_t * local_point_ids_ =
1623 (*local_point_ids) + total_num_local_point_ids;
1624 double * cos_angles_;
1625 if (cos_angles != NULL) {
1626 ENSURE_ARRAY_SIZE(*cos_angles, *cos_angles_array_size,
1627 total_num_local_point_ids + num_results);
1628 cos_angles_ = (*cos_angles) + total_num_local_point_ids;
1629 } else {
1630 cos_angles_ = NULL;
1631 }
1632 double (*result_coordinates_xyz_)[3];
1633 if (result_coordinates_xyz != NULL) {
1634 ENSURE_ARRAY_SIZE(*result_coordinates_xyz,
1635 *result_coordinates_xyz_array_size,
1636 total_num_local_point_ids + num_results);
1637 result_coordinates_xyz_ =
1638 (*result_coordinates_xyz) + total_num_local_point_ids;
1639 } else {
1640 result_coordinates_xyz_ = NULL;
1641 }
1642
1643 for (size_t j = 0; j < num_results; ++j) {
1644
1645 local_point_ids_[j] = results[j].idx;
1646 if (cos_angles_ != NULL) cos_angles_[j] = results[j].cos_angle;
1647 if (result_coordinates_xyz_ != NULL) {
1648 result_coordinates_xyz_[j][0] = results[j].coordinates_xyz[0];
1649 result_coordinates_xyz_[j][1] = results[j].coordinates_xyz[1];
1650 result_coordinates_xyz_[j][2] = results[j].coordinates_xyz[2];
1651 }
1652 }
1653
1654 num_local_point_ids[i] = num_results;
1655 total_num_local_point_ids += num_results;
1656 }
1657
1658 free(results);
1659 free(flags);
1660 free(node_stack);
1661 free(dot_stack);
1662 }
1663
yac_point_sphere_part_search_bnd_circle_contains_points(struct point_sphere_part_search * search,struct bounding_circle circle)1664 int yac_point_sphere_part_search_bnd_circle_contains_points(
1665 struct point_sphere_part_search * search, struct bounding_circle circle) {
1666
1667 if (search == NULL) return 0;
1668
1669 return point_check_bnd_circle(&(search->base_node), circle);
1670 }
1671
search_point(struct sphere_part_node * node,double point[],size_t ** overlap_cells,size_t * overlap_cells_array_size,size_t * num_overlap_cells,struct overlaps * search_interval_tree_buffer,double prev_gc_norm_vector[])1672 static void search_point(struct sphere_part_node * node,
1673 double point[],
1674 size_t ** overlap_cells,
1675 size_t * overlap_cells_array_size,
1676 size_t * num_overlap_cells,
1677 struct overlaps * search_interval_tree_buffer,
1678 double prev_gc_norm_vector[]) {
1679
1680 double dot = point[0] * node->gc_norm_vector[0] +
1681 point[1] * node->gc_norm_vector[1] +
1682 point[2] * node->gc_norm_vector[2];
1683
1684 // angle < M_PI_2
1685 if (dot > -yac_angle_tol) {
1686
1687 if (node->flags & T_IS_LEAF) {
1688
1689 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1690 *num_overlap_cells + node->T_size);
1691 memcpy(*overlap_cells + *num_overlap_cells, node->T,
1692 node->T_size * sizeof(**overlap_cells));
1693 *num_overlap_cells += node->T_size;
1694
1695 } else {
1696 search_point(node->T, point, overlap_cells,
1697 overlap_cells_array_size, num_overlap_cells,
1698 search_interval_tree_buffer, node->gc_norm_vector);
1699 }
1700 }
1701
1702 // angle > M_PI_2
1703 if (dot < yac_angle_tol) {
1704
1705 if (node->flags & U_IS_LEAF) {
1706
1707 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1708 *num_overlap_cells + node->U_size);
1709 memcpy(*overlap_cells + *num_overlap_cells, node->U,
1710 node->U_size * sizeof(**overlap_cells));
1711 *num_overlap_cells += node->U_size;
1712
1713 } else {
1714 search_point(node->U, point, overlap_cells,
1715 overlap_cells_array_size, num_overlap_cells,
1716 search_interval_tree_buffer, node->gc_norm_vector);
1717 }
1718 }
1719
1720 // fabs(angle - M_PI_2) <= (node->I_angle)
1721 // fabs(cos(angle)) <= sin(node->I_angle)
1722 if (fabs(dot) <= node->I_angle.sin) {
1723
1724 if (node->flags & I_IS_INTERVAL_TREE) {
1725
1726 double GCp[3], bVp[3];
1727 crossproduct_ld(node->gc_norm_vector, point, GCp);
1728 crossproduct_ld(GCp, node->gc_norm_vector, bVp);
1729 normalise_vector(bVp);
1730 double base_angle = get_vector_angle(bVp, prev_gc_norm_vector);
1731
1732 struct interval search_interval =
1733 {.left=base_angle, .right=base_angle};
1734
1735 search_interval_tree_buffer->num_overlaps = 0;
1736
1737 yac_search_interval_tree(node->I.ivt.head_node, node->I.ivt.num_nodes,
1738 search_interval, search_interval_tree_buffer);
1739
1740 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1741 *num_overlap_cells +
1742 search_interval_tree_buffer->num_overlaps);
1743
1744 for (size_t i = 0; i < search_interval_tree_buffer->num_overlaps;
1745 ++i) {
1746 (*overlap_cells)[(*num_overlap_cells)+i] =
1747 node->I.ivt.head_node[
1748 search_interval_tree_buffer->overlap_iv[i]].value;
1749 }
1750
1751 *num_overlap_cells += search_interval_tree_buffer->num_overlaps;
1752
1753 } else {
1754
1755 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1756 *num_overlap_cells + node->I_size);
1757 memcpy(*overlap_cells + *num_overlap_cells, node->I.list,
1758 node->I_size * sizeof(**overlap_cells));
1759 *num_overlap_cells += node->I_size;
1760 }
1761 }
1762 }
1763
yac_bnd_sphere_part_search_do_point_search(struct bnd_sphere_part_search * search,coordinate_pointer coordinates_xyz,size_t count,size_t ** cells,size_t * num_cells_per_coordinate)1764 void yac_bnd_sphere_part_search_do_point_search(
1765 struct bnd_sphere_part_search * search, coordinate_pointer coordinates_xyz,
1766 size_t count, size_t ** cells, size_t * num_cells_per_coordinate) {
1767
1768 struct sphere_part_node * base_node = &(search->base_node);
1769
1770 size_t * temp_search_results = NULL;
1771 size_t temp_search_results_array_size = 0;
1772 size_t num_temp_search_results = 0;
1773
1774 struct overlaps search_interval_tree_buffer = {0, 0, NULL};
1775
1776 memset(
1777 num_cells_per_coordinate, 0, count * sizeof(*num_cells_per_coordinate));
1778 size_t * cells_ = NULL;
1779 size_t cells_array_size = 0;
1780 size_t num_cells = 0;
1781 ENSURE_ARRAY_SIZE(cells_, cells_array_size, count);
1782
1783 for (size_t i = 0; i < count; ++i) {
1784
1785 double * curr_coordinates_xyz = &(coordinates_xyz[i][0]);
1786
1787 num_temp_search_results = 0;
1788
1789 double gc_norm_vector[3] = {0.0,0.0,1.0};
1790
1791 search_point(base_node, curr_coordinates_xyz, &temp_search_results,
1792 &temp_search_results_array_size, &num_temp_search_results,
1793 &search_interval_tree_buffer, gc_norm_vector);
1794
1795 ENSURE_ARRAY_SIZE(
1796 cells_, cells_array_size, num_cells + num_temp_search_results);
1797
1798 memcpy(cells_ + num_cells, temp_search_results,
1799 num_temp_search_results * sizeof(*temp_search_results));
1800 num_cells_per_coordinate[i] = num_temp_search_results;
1801 num_cells += num_temp_search_results;
1802 }
1803
1804 free(temp_search_results);
1805 free(search_interval_tree_buffer.overlap_iv);
1806
1807 *cells = xrealloc(cells_, num_cells * sizeof(*cells_));
1808 }
1809
yac_bnd_sphere_part_search_do_bnd_circle_search(struct bnd_sphere_part_search * search,struct bounding_circle * bnd_circles,size_t count,size_t ** cells,size_t * num_cells_per_bnd_circle)1810 void yac_bnd_sphere_part_search_do_bnd_circle_search(
1811 struct bnd_sphere_part_search * search, struct bounding_circle * bnd_circles,
1812 size_t count, size_t ** cells, size_t * num_cells_per_bnd_circle) {
1813
1814 struct sphere_part_node * base_node = &(search->base_node);
1815
1816 size_t * temp_search_results = NULL;
1817 size_t temp_search_results_array_size = 0;
1818 size_t num_temp_search_results = 0;
1819
1820 struct overlaps search_interval_tree_buffer = {0, 0, NULL};
1821
1822 memset(
1823 num_cells_per_bnd_circle, 0, count * sizeof(*num_cells_per_bnd_circle));
1824 size_t * cells_ = NULL;
1825 size_t cells_array_size = 0;
1826 size_t num_cells = 0;
1827 ENSURE_ARRAY_SIZE(cells_, cells_array_size, count);
1828
1829 for (size_t i = 0; i < count; ++i) {
1830
1831 num_temp_search_results = 0;
1832
1833 double gc_norm_vector[3] = {0.0,0.0,1.0};
1834
1835 search_bnd_circle(base_node, bnd_circles[i], &temp_search_results,
1836 &temp_search_results_array_size, &num_temp_search_results,
1837 &search_interval_tree_buffer, gc_norm_vector);
1838
1839 ENSURE_ARRAY_SIZE(
1840 cells_, cells_array_size, num_cells + num_temp_search_results);
1841
1842 memcpy(cells_ + num_cells, temp_search_results,
1843 num_temp_search_results * sizeof(*temp_search_results));
1844 num_cells_per_bnd_circle[i] = num_temp_search_results;
1845 num_cells += num_temp_search_results;
1846 }
1847
1848 free(temp_search_results);
1849 free(search_interval_tree_buffer.overlap_iv);
1850
1851 *cells = xrealloc(cells_, num_cells * sizeof(*cells_));
1852 }
1853
free_sphere_part_tree(struct sphere_part_node tree)1854 static void free_sphere_part_tree (struct sphere_part_node tree) {
1855
1856 // free I_list
1857 if (tree.flags & I_IS_INTERVAL_TREE)
1858 free(tree.I.ivt.head_node);
1859
1860 if ((tree.flags & U_IS_LEAF) == 0) {
1861 free_sphere_part_tree(*(struct sphere_part_node*)(tree.U));
1862 free(tree.U);
1863 }
1864
1865 if ((tree.flags & T_IS_LEAF) == 0) {
1866 free_sphere_part_tree(*(struct sphere_part_node*)(tree.T));
1867 free(tree.T);
1868 }
1869 }
1870
free_point_sphere_part_tree(struct point_sphere_part_node * tree)1871 static void free_point_sphere_part_tree (struct point_sphere_part_node * tree) {
1872
1873 if ((tree->flags & U_IS_LEAF) == 0) {
1874 free_point_sphere_part_tree(tree->U);
1875 free(tree->U);
1876 }
1877
1878 if ((tree->flags & T_IS_LEAF) == 0) {
1879 free_point_sphere_part_tree(tree->T);
1880 free(tree->T);
1881 }
1882 }
1883
yac_delete_point_sphere_part_search(struct point_sphere_part_search * search)1884 void yac_delete_point_sphere_part_search(
1885 struct point_sphere_part_search * search) {
1886
1887 if (search == NULL) return;
1888
1889 free_point_sphere_part_tree(&(search->base_node));
1890 free(search->points);
1891 free(search);
1892 }
1893
yac_bnd_sphere_part_search_delete(struct bnd_sphere_part_search * search)1894 void yac_bnd_sphere_part_search_delete(struct bnd_sphere_part_search * search) {
1895
1896 if (search == NULL) return;
1897
1898 free_sphere_part_tree(search->base_node);
1899 free(search->ids);
1900 free(search);
1901 }
1902