YetAnotherCoupler 3.5.2
Loading...
Searching...
No Matches
sphere_part.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 <assert.h>
11#include <stdlib.h>
12#include <math.h>
13#include <string.h>
14#include <stdint.h>
15#include <float.h>
16
17#include "sphere_part.h"
18#include "geometry.h"
19#include "basic_grid.h"
20#include "interval_tree.h"
21#include "utils_core.h"
22#include "ensure_array_size.h"
23
24union I_list {
25 struct {
27 size_t num_nodes;
28 } ivt;
29 size_t *list;
30};
31
32enum {
35};
36enum {
37 U_FLAG = 1,
38 T_FLAG = 2,
39};
40
46
48
49 int flags;
50
51 union I_list I;
52 void * U, * T;
53
55
57
58 double gc_norm_vector[3];
59};
60
65
68 I_NODE = 1,
69 U_NODE = 2,
70 T_NODE = 3,
71};
72
74 struct bounding_circle bnd_circle; // has to be first entry
75 size_t local_id;
77};
78
80 double coordinates_xyz[3]; // has to be the first entry
81 size_t idx; // index of the point in the coordinates array passed to
82 // the constructor
83};
84
89
91
92 int flags;
93
94 void * U, * T;
95
96 size_t U_size, T_size;
97
98 double gc_norm_vector[3];
99};
100
107
109 size_t idx;
110 int32_t coordinate_xyz[3];
111};
112
113static void init_sphere_part_node(struct sphere_part_node * node) {
114
115 node->flags = 0;
116 node->I_size = 0;
117 node->U_size = 0;
118 node->T_size = 0;
119 node->I_angle = SIN_COS_ZERO;
120 node->gc_norm_vector[0] = 0;
121 node->gc_norm_vector[1] = 0;
122 node->gc_norm_vector[2] = 1;
123}
124
126
127 struct sphere_part_node * node = xmalloc(1 * sizeof(*node));
128
130
131 return node;
132}
133
134// computes the norm vector for the plane the partitions the data in half
135// (more or less)
136static inline void compute_gc_norm_vector(
137 void * coords_data, size_t coords_size, size_t coords_count,
138 double prev_gc_norm_vector[], double gc_norm_vector[]) {
139
140
141 double balance_point[3] = {0.0,0.0,0.0};
142
143 // compute balance point
144 for (size_t i = 0; i < coords_count; ++i) {
145
146 double * coords =
147 (double*)(((unsigned char*)coords_data) + i * coords_size);
148 balance_point[0] += coords[0];
149 balance_point[1] += coords[1];
150 balance_point[2] += coords[2];
151 }
152
153 if ((fabs(balance_point[0]) > 1e-9) ||
154 (fabs(balance_point[1]) > 1e-9) ||
155 (fabs(balance_point[2]) > 1e-9)) {
156 normalise_vector(balance_point);
157 } else {
158 balance_point[0] = prev_gc_norm_vector[2];
159 balance_point[1] = prev_gc_norm_vector[0];
160 balance_point[2] = prev_gc_norm_vector[1];
161 }
162
164 balance_point, prev_gc_norm_vector, gc_norm_vector);
165
166 if ((fabs(gc_norm_vector[0]) > 1e-9) ||
167 (fabs(gc_norm_vector[1]) > 1e-9) ||
168 (fabs(gc_norm_vector[2]) > 1e-9)) {
170 } else {
171 gc_norm_vector[0] = prev_gc_norm_vector[2];
172 gc_norm_vector[1] = prev_gc_norm_vector[0];
173 gc_norm_vector[2] = prev_gc_norm_vector[1];
174 }
175}
176
178{
179 struct temp_partition_data temp = *a;
180 *a = *b;
181 *b = temp;
182}
183
184static size_t swap_node_type(struct temp_partition_data *part_data, size_t i, int node_type, size_t begin, size_t end)
185{
186 for (size_t j = begin; j < end; ++j)
187 {
188 if (part_data[j].node_type == node_type)
189 {
190 swap_partition_data(&part_data[i], &part_data[j]);
191 return j + 1;
192 }
193 }
194
195 return end + 1;
196}
197
198static void sort_partition_data(struct temp_partition_data *part_data, size_t I_FULL_size, size_t I_size, size_t U_size, size_t T_size)
199{
200 size_t I_begin = I_FULL_size;
201 size_t U_begin = I_FULL_size + I_size;
202 size_t T_begin = I_FULL_size + I_size + U_size;
203
204 size_t I_end = I_begin + I_size;
205 size_t U_end = U_begin + U_size;
206 size_t T_end = T_begin + T_size;
207
208 while (I_end > I_begin && part_data[I_end-1].node_type == I_NODE) I_end--;
209 while (U_end > U_begin && part_data[U_end-1].node_type == U_NODE) U_end--;
210 while (T_end > T_begin && part_data[T_end-1].node_type == T_NODE) T_end--;
211
212 for (size_t i = 0; i < I_FULL_size; ++i)
213 {
214 if (part_data[i].node_type != I_NODE_FULL)
215 {
216 I_begin = swap_node_type(part_data, i, I_NODE_FULL, I_begin, T_end);
217 }
218 }
219
220 I_begin = I_FULL_size;
221 for (size_t i = I_begin; i < I_end; ++i)
222 {
223 if (part_data[i].node_type != I_NODE)
224 {
225 U_begin = swap_node_type(part_data, i, I_NODE, U_begin, U_end);
226 if (U_begin > U_end)
227 {
228 T_begin = swap_node_type(part_data, i, I_NODE, T_begin, T_end);
229 }
230 }
231 }
232
233 U_begin = I_FULL_size + I_size;
234 T_begin = I_FULL_size + I_size + U_size;
235 for (size_t i = U_begin; i < U_end; ++i)
236 {
237 if (part_data[i].node_type != U_NODE)
238 {
239 T_begin = swap_node_type(part_data, i, U_NODE, T_begin, T_end);
240 }
241 }
242}
243
244static void partition_data (
245 size_t * local_cell_ids, struct temp_partition_data * part_data,
246 size_t num_cell_ids, size_t threshold, struct sphere_part_node * parent_node,
247 double prev_gc_norm_vector[]) {
248
249 if (num_cell_ids == 0) {
250 parent_node->flags = U_IS_LEAF + T_IS_LEAF;
251 return;
252 }
253
255 part_data, sizeof(*part_data), num_cell_ids,
256 prev_gc_norm_vector, parent_node->gc_norm_vector);
257
258 // partition data into cells that overlap with the great circle and cells
259 // that are one side of the circle
260
261 size_t I_FULL_size = 0;
262 size_t I_size = 0;
263 size_t U_size = 0;
264 size_t T_size = 0;
265
266 struct sin_cos_angle max_inc_angle = SIN_COS_ZERO;
267
268 for (size_t i = 0; i < num_cell_ids; ++i) {
269
270 struct bounding_circle curr_bnd_circle = part_data[i].bnd_circle;
271
272 // get angle between the norm vector of the great circle and the base
273 // point of the bounding circle
274 struct sin_cos_angle angle =
276 curr_bnd_circle.base_vector, parent_node->gc_norm_vector);
277
278 // get the angle between between the plane of the great circle and base
279 // point of the bounding circle
280 struct sin_cos_angle diff_angle_gc =
281 sin_cos_angle_new(fabs(angle.cos), angle.sin);
282
283 // if the point intersects with the great circle
284 if (compare_angles(diff_angle_gc, curr_bnd_circle.inc_angle) <= 0) {
285
286 // if gc_norm_vector or -gc_norm_vector is in the bounding circle
287 if ((angle.sin < curr_bnd_circle.inc_angle.sin) ||
288 (0.0 >= curr_bnd_circle.inc_angle.cos)) {
289
290 // set node type for current cell
291 part_data[i].node_type = I_NODE_FULL;
292 I_FULL_size++;
293
294 max_inc_angle = SIN_COS_M_PI_2;
295
296 } else {
297
298 // set node type for current cell
299 part_data[i].node_type = I_NODE;
300 I_size++;
301
302 struct sin_cos_angle inc_angle =
303 sum_angles_no_check(diff_angle_gc, curr_bnd_circle.inc_angle);
304
305 if (compare_angles(max_inc_angle, inc_angle) < 0)
306 max_inc_angle = inc_angle;
307 }
308
309 // angle > M_PI_2
310 } else if (angle.cos < 0.0) {
311
312 // set node type for current cell
313 part_data[i].node_type = U_NODE;
314 U_size++;
315
316 } else {
317
318 // set node type for current cell
319 part_data[i].node_type = T_NODE;
320 T_size++;
321 }
322 }
323
324 sort_partition_data(part_data, I_FULL_size, I_size, U_size, T_size);
325
326 I_size += I_FULL_size;
327 parent_node->I_size = I_size;
328 parent_node->U_size = U_size;
329 parent_node->T_size = T_size;
330
331 // if max_inc_angle > PI/2
332 if (compare_angles(max_inc_angle, SIN_COS_M_PI_2) >= 0) {
333 parent_node->I_angle = SIN_COS_M_PI_2;
334 } else {
335 parent_node->I_angle = max_inc_angle;
336 }
337
338 if (I_size > 0) {
339
340 if (I_size > I_list_tree_min_size) {
341
342 assert(sizeof(struct interval_node) > sizeof(size_t));
343 struct interval_node * head_node = xmalloc(I_size * sizeof(*head_node));
344 parent_node->I.ivt.head_node = head_node;
345 parent_node->I.ivt.num_nodes = I_size;
346
347 // for all bounding circles that include gc_norm_vector or
348 // -gc_norm_vector
349 for (size_t i = 0; i < I_FULL_size; ++i) {
350
351 head_node[i].range.left = -M_PI;
352 head_node[i].range.right = M_PI;
353 head_node[i].value = part_data[i].local_id;
354 }
355
356 for (size_t i = I_FULL_size; i < I_size; ++i) {
357
358 double GCp[3], bVp[3];
359 struct bounding_circle curr_bnd_circle = part_data[i].bnd_circle;
360
361 // project the base vector of the current bounding circle onto the
362 // current partitioning great circle
364 curr_bnd_circle.base_vector, GCp);
365 crossproduct_kahan(GCp, parent_node->gc_norm_vector, bVp);
367 (fabs(bVp[0]) > 1e-9) || (fabs(bVp[1]) > 1e-9) ||
368 (fabs(bVp[2]) > 1e-9),
369 "ERROR(partition_data): "
370 "projected vector is nearly identical to gc_norm_vector")
371 normalise_vector(bVp);
372
373 // the inc_angle of the bounding circle also needs to be projected
374 // onto the great circle
375 // (the formula for this is:
376 // new_inc_angle=acos(sin(inc_angle)/cos(base_angle))
377 // To find this formula, you have to determine the longitude of
378 // of longitude circle that has exactly one intersection with the
379 // bounding circle.
380 // (see https://www.dropbox.com/s/82bxzno1mjogbtf/function_2nd_try.pdf)
381 double bnd_circle_lat_cos =
382 get_vector_angle_2(bVp, curr_bnd_circle.base_vector).cos;
383 double inc_angle =
384 M_PI_2 - acos(curr_bnd_circle.inc_angle.sin/bnd_circle_lat_cos);
385
386 // By definition the previous norm vector is on the current great
387 // great circle. We use this as a reference point for I
388
389 // compute "distance" of the projected base vector to the reference
390 // point
391 double base_angle = get_vector_angle(bVp, prev_gc_norm_vector);
392
393 head_node[i].range.left = base_angle - inc_angle;
394 head_node[i].range.right = base_angle + inc_angle;
395 head_node[i].value = part_data[i].local_id;
396 }
397
398 yac_generate_interval_tree(head_node, I_size);
399 parent_node->flags |= I_IS_INTERVAL_TREE;
400 } else {
401 for (size_t i = 0; i < I_size; ++i)
402 local_cell_ids[i] = part_data[i].local_id;
403 parent_node->I.list = (void*)local_cell_ids;
404 }
405 } else
406 parent_node->I.list = NULL;
407
408 part_data += I_size;
409 local_cell_ids += I_size;
410
411 // check whether the lists are small enough (if not -> partition again)
412 if (U_size <= threshold) {
413
414 for (size_t i = 0; i < U_size; ++i)
415 local_cell_ids[i] = part_data[i].local_id;
416 parent_node->U = (void*)local_cell_ids;
417 parent_node->flags |= U_IS_LEAF;
418
419 } else {
420
421 parent_node->U = get_sphere_part_node();
422 partition_data(local_cell_ids, part_data, U_size, threshold,
423 parent_node->U, parent_node->gc_norm_vector);
424 }
425 local_cell_ids += U_size;
426 part_data += U_size;
427
428 if (T_size <= threshold) {
429
430 for (size_t i = 0; i < T_size; ++i)
431 local_cell_ids[i] = part_data[i].local_id;
432 parent_node->T = (void*)local_cell_ids;
433 parent_node->flags |= T_IS_LEAF;
434 local_cell_ids += T_size;
435
436 } else {
437
438 parent_node->T = get_sphere_part_node();
439 partition_data(local_cell_ids, part_data, T_size, threshold,
440 parent_node->T, parent_node->gc_norm_vector);
441 }
442}
443
444static int compare_point_idx_xyz(void const * a, void const * b) {
445 return (((struct point_id_xyz *)a)->idx > ((struct point_id_xyz *)b)->idx) -
446 (((struct point_id_xyz *)a)->idx < ((struct point_id_xyz *)b)->idx);
447}
448
450 struct point_id_xyz * points, size_t num_points, size_t threshold,
451 double prev_gc_norm_vector[], size_t curr_tree_depth,
452 size_t * max_tree_depth) {
453
454 if (curr_tree_depth > *max_tree_depth) *max_tree_depth = curr_tree_depth;
455
456 struct point_sphere_part_node * node = xmalloc(1 * sizeof(*node));
457 double * gc_norm_vector = &(node->gc_norm_vector[0]);
458
460 points, sizeof(*points), num_points, prev_gc_norm_vector, gc_norm_vector);
461
462 // angle between a point and the great circle plane
463 // acos(dot(gc_norm_vector, point_xyz)) = angle(gc_norm_vector, point_xyz)
464 // acos(dot(gc_norm_vector, point_xyz)) - PI/2 = angle(gc_plane, point_xyz)
465 // dot <= 0.0 -> U list
466 // dot > 0.0 -> T list
467
468 struct point_id_xyz * left = points, * right = points + num_points - 1;
469
470 // sort such that all points for the U list come first, followed by the
471 // elements of the T list
472 while (1) {
473 // find element that does not belong into U-list
474 while (left <= right) {
475 double * curr_coordinates_xyz = &(left->coordinates_xyz[0]);
476 double dot = curr_coordinates_xyz[0] * gc_norm_vector[0] +
477 curr_coordinates_xyz[1] * gc_norm_vector[1] +
478 curr_coordinates_xyz[2] * gc_norm_vector[2];
479
480 // if (angle < M_PI_2)
481 if (dot > 0.0) break;
482 ++left;
483 };
484
485 // find element that does not belong into T-list
486 while (left < right) {
487 double * curr_coordinates_xyz = &(right->coordinates_xyz[0]);
488 double dot = curr_coordinates_xyz[0] * gc_norm_vector[0] +
489 curr_coordinates_xyz[1] * gc_norm_vector[1] +
490 curr_coordinates_xyz[2] * gc_norm_vector[2];
491
492 // if (angle >= M_PI_2)
493 if (dot <= 0.0) break;
494 --right;
495 }
496
497 if (left < right) {
498 struct point_id_xyz tmp_point = *left;
499 *left = *right;
500 *right = tmp_point;
501 ++left;
502 --right;
503 } else {
504 break;
505 }
506 }
507
508 size_t U_size = left - points;
509 size_t T_size = num_points - U_size;
510
511 node->U_size = U_size;
512 node->T_size = T_size;
513 node->flags = 0;
514
515 // check whether the lists are small enough (if not -> partition again)
516 if ((U_size <= threshold) || (U_size == num_points)) {
517
518 node->U = points;
519 node->flags |= U_IS_LEAF;
520 qsort(points, U_size, sizeof(*points), compare_point_idx_xyz);
521
522 } else {
523
524 node->U = partition_point_data(points, U_size, threshold, gc_norm_vector,
525 curr_tree_depth + 1, max_tree_depth);
526 }
527
528 if ((T_size <= threshold) || (T_size == num_points)) {
529
530 node->T = points + U_size;
531 node->flags |= T_IS_LEAF;
532 qsort(points + U_size, T_size, sizeof(*points), compare_point_idx_xyz);
533
534 } else {
535
536 node->T =
537 partition_point_data(points + U_size, T_size, threshold, gc_norm_vector,
538 curr_tree_depth + 1, max_tree_depth);
539 }
540
541 return node;
542}
543
545 struct bounding_circle * circles, size_t num_circles) {
546
547 struct bnd_sphere_part_search * search = xmalloc(1 * sizeof(*search));
548
549 double gc_norm_vector[3] = {0.0,0.0,1.0};
550
552
553 size_t * ids = xmalloc(num_circles * sizeof(*ids));
554 search->ids = ids;
555
556 struct temp_partition_data * part_data =
557 xmalloc(num_circles * sizeof(*part_data));
558 for (size_t i = 0; i < num_circles; ++i) {
559 part_data[i].bnd_circle = circles[i];
560 part_data[i].local_id = i;
561 }
562
563 partition_data(ids, part_data, num_circles, I_list_tree_min_size,
564 &(search->base_node), gc_norm_vector);
565
566 free(part_data);
567
568 return search;
569}
570
572 const void * a,const void * b) {
573
574 struct point_id_xyz_int32 * point_a = (struct point_id_xyz_int32 *)a;
575 struct point_id_xyz_int32 * point_b = (struct point_id_xyz_int32 *)b;
576
577 int ret;
578
579 for (int i = 0; i < 3; ++i)
580 if ((ret = (point_a->coordinate_xyz[i] > point_b->coordinate_xyz[i]) -
581 (point_a->coordinate_xyz[i] < point_b->coordinate_xyz[i])))
582 return ret;
583 return 0;
584}
585
586static struct point_id_xyz *
589 yac_int const * ids, int const * mask) {
590
591 struct point_id_xyz_int32 * points_int32 =
592 xmalloc(*num_points * sizeof(*points_int32));
593
594 double const scale = (double)(2 << 21);
595
596 size_t num_unmasked_points;
597
598 if (mask == NULL) {
599 num_unmasked_points = *num_points;
600 for (size_t i = 0; i < num_unmasked_points; ++i) {
601
602 points_int32[i].idx = i;
603 for (size_t j = 0; j < 3; ++j)
604 points_int32[i].coordinate_xyz[j] =
605 (int32_t)round(coordinates_xyz[i][j] * scale);
606 }
607 } else {
608 num_unmasked_points = 0;
609 for (size_t i = 0; i < *num_points; ++i) {
610
611 if (!mask[i]) continue;
612 points_int32[num_unmasked_points].idx = i;
613 for (size_t j = 0; j < 3; ++j)
614 points_int32[num_unmasked_points].coordinate_xyz[j] =
615 (int32_t)round(coordinates_xyz[i][j] * scale);
616 num_unmasked_points++;
617 }
618 }
619
620 // sort points
621 qsort(points_int32, num_unmasked_points,
622 sizeof(*points_int32), compare_points_int32_coord);
623
624 struct point_id_xyz_int32 dummy;
625 dummy.idx = SIZE_MAX;
626 dummy.coordinate_xyz[0] = INT32_MAX;
627 dummy.coordinate_xyz[1] = INT32_MAX;
628 dummy.coordinate_xyz[2] = INT32_MAX;
629 struct point_id_xyz_int32 * prev = &dummy, * curr = points_int32;
630 yac_int prev_id = XT_INT_MAX;
631 size_t new_num_points = 0;
632 for (size_t i = 0; i < num_unmasked_points; ++i, ++curr) {
633
634 size_t curr_idx = curr->idx;
635 if (compare_points_int32_coord(prev, curr)) {
636 prev = points_int32 + new_num_points++;
637 if (prev != curr) *prev = *curr;
638 prev_id = ids[curr_idx];
639 } else {
640 yac_int curr_id = ids[curr_idx];
641 if (curr_id > prev_id) {
642 prev_id = curr_id;
643 prev->idx = curr_idx;
644 }
645 }
646 }
647
648 struct point_id_xyz * points = xmalloc(new_num_points * sizeof(*points));
649 for (size_t i = 0; i < new_num_points; ++i) {
650 size_t curr_idx = points_int32[i].idx;
651 points[i].idx = curr_idx;
652 memcpy(
653 points[i].coordinates_xyz, coordinates_xyz[curr_idx], 3 * sizeof(double));
654 }
655 *num_points = new_num_points;
656 free(points_int32);
657 return points;
658}
659
661 size_t num_points, yac_const_coordinate_pointer coordinates_xyz,
662 yac_int const * ids) {
663
664 if (num_points == 0) return NULL;
665
666 struct point_sphere_part_search * search = xmalloc(1 * sizeof(*search));
667 struct point_id_xyz * points =
669 search->points = points;
670
671 size_t max_tree_depth = 0;
672
673 // emperical measurements have given a threshold for the leaf size of 2
674 struct point_sphere_part_node * tmp_node =
676 points, num_points, I_list_tree_min_size, (double[3]){0.0,0.0,1.0},
677 1, &max_tree_depth);
678
679 search->base_node = *tmp_node;
680 search->max_tree_depth = max_tree_depth;
681 free(tmp_node);
682
683 return search;
684}
685
687 size_t num_points, yac_const_coordinate_pointer coordinates_xyz,
688 yac_int const * ids, int const * mask) {
689
690 if (num_points == 0) return NULL;
691
692 struct point_id_xyz * points =
694
695 struct point_sphere_part_search * search = xmalloc(1 * sizeof(*search));
696 search->points = xrealloc(points, num_points * sizeof(*points));
697
698 size_t max_tree_depth = 0;
699
700 // emperical measurements have given a threshold for the leaf size of 2
701 struct point_sphere_part_node * tmp_node =
704 (double[3]){0.0,0.0,1.0}, 1, &max_tree_depth);
705
706 search->base_node = *tmp_node;
707 search->max_tree_depth = max_tree_depth;
708 free(tmp_node);
709
710 return search;
711}
712
714 struct sphere_part_node * node, struct bounding_circle bnd_circle,
715 size_t ** restrict overlap_cells, size_t * overlap_cells_array_size,
716 size_t * restrict num_overlap_cells,
717 struct overlaps * search_interval_tree_buffer, double prev_gc_norm_vector[]) {
718
719 if (node->flags & I_IS_INTERVAL_TREE) {
720
721 struct sin_cos_angle angle =
723 bnd_circle.base_vector, node->gc_norm_vector);
724 angle.cos = fabs(angle.cos);
725
726 // if gc_norm_vector or -gc_norm_vector is in the bounding circle
727 if (compare_angles(angle, bnd_circle.inc_angle) <= 0) {
728 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
729 *num_overlap_cells + node->I.ivt.num_nodes);
730 for (size_t i = 0; i < node->I.ivt.num_nodes; ++i)
731 (*overlap_cells)[(*num_overlap_cells)+i] =
732 node->I.ivt.head_node[i].value;
733 *num_overlap_cells += node->I.ivt.num_nodes;
734 return;
735 }
736
737 double GCp[3], bVp[3];
738
739 // project the base vector of the current bounding circle onto the
740 // current great circle
741 crossproduct_kahan(node->gc_norm_vector, bnd_circle.base_vector, GCp);
742 crossproduct_kahan(GCp, node->gc_norm_vector, bVp);
744 (fabs(bVp[0]) > 1e-9) || (fabs(bVp[1]) > 1e-9) || (fabs(bVp[2]) > 1e-9),
745 "ERROR(search_bnd_circle_I_node): "
746 "projected vector is nearly identical to gc_norm_vector")
747 normalise_vector(bVp);
748
749 // the inc_angle of the bounding circle also needs to be projected
750 // onto the great circle (see routine partition data for a detailed
751 // explanation)
752 double bnd_circle_lat_cos =
753 get_vector_angle_2(bVp, bnd_circle.base_vector).cos;
754 double inc_angle =
755 M_PI_2 - acos(bnd_circle.inc_angle.sin/bnd_circle_lat_cos);
756
757 // compute "distance" of the projected base vector to the reference point
758 double base_angle = get_vector_angle(bVp, prev_gc_norm_vector);
759
760 search_interval_tree_buffer->num_overlaps = 0;
761
763 node->I.ivt.head_node, node->I.ivt.num_nodes,
764 (struct interval){
765 .left = base_angle - inc_angle,
766 .right = base_angle + inc_angle},
767 search_interval_tree_buffer);
768
769 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
770 *num_overlap_cells +
771 search_interval_tree_buffer->num_overlaps);
772
773 for (size_t i = 0; i < search_interval_tree_buffer->num_overlaps; ++i)
774 (*overlap_cells)[(*num_overlap_cells)+i] =
775 node->I.ivt.head_node[
776 search_interval_tree_buffer->overlap_iv[i]].value;
777
778 *num_overlap_cells += search_interval_tree_buffer->num_overlaps;
779
780 } else {
781
782 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
783 *num_overlap_cells + node->I_size);
784 memcpy(*overlap_cells + *num_overlap_cells, node->I.list,
785 node->I_size * sizeof(**overlap_cells));
786 *num_overlap_cells += node->I_size;
787 }
788}
789
792 struct sphere_part_node * node, struct bounding_circle bnd_circle,
793 size_t ** restrict overlap_cells, size_t * overlap_cells_array_size,
794 size_t * restrict num_overlap_cells,
795 struct overlaps * search_interval_tree_buffer, double prev_gc_norm_vector[]) {
796
797 if (node->flags & T_IS_LEAF) {
798
799 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
800 *num_overlap_cells + node->T_size);
801 memcpy(*overlap_cells + *num_overlap_cells, node->T,
802 node->T_size * sizeof(**overlap_cells));
803 *num_overlap_cells += node->T_size;
804
805 } else {
807 node->T, bnd_circle, overlap_cells, overlap_cells_array_size,
808 num_overlap_cells, search_interval_tree_buffer, node->gc_norm_vector);
809 }
810
811 if (node->flags & U_IS_LEAF) {
812
813 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
814 *num_overlap_cells + node->U_size);
815 memcpy(*overlap_cells + *num_overlap_cells, node->U,
816 node->U_size * sizeof(**overlap_cells));
817 *num_overlap_cells += node->U_size;
818
819 } else {
821 node->U, bnd_circle, overlap_cells, overlap_cells_array_size,
822 num_overlap_cells, search_interval_tree_buffer, node->gc_norm_vector);
823 }
824
826 node, bnd_circle, overlap_cells, overlap_cells_array_size,
827 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
828}
829
831 struct sphere_part_node * node, struct bounding_circle bnd_circle,
832 size_t ** restrict overlap_cells, size_t * overlap_cells_array_size,
833 size_t * restrict num_overlap_cells,
834 struct overlaps * search_interval_tree_buffer, double prev_gc_norm_vector[]) {
835
836 double dot = bnd_circle.base_vector[0] * node->gc_norm_vector[0] +
837 bnd_circle.base_vector[1] * node->gc_norm_vector[1] +
838 bnd_circle.base_vector[2] * node->gc_norm_vector[2];
839
840 // angle < M_PI_2 + bnd_circle.inc_angle
841 if (dot > - bnd_circle.inc_angle.sin) {
842
843 if (node->flags & T_IS_LEAF) {
844
845 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
846 *num_overlap_cells + node->T_size);
847 memcpy(*overlap_cells + *num_overlap_cells, node->T,
848 node->T_size * sizeof(**overlap_cells));
849 *num_overlap_cells += node->T_size;
850
851 } else {
853 node->T, bnd_circle, overlap_cells, overlap_cells_array_size,
854 num_overlap_cells, search_interval_tree_buffer,
855 node->gc_norm_vector);
856 }
857 }
858
859 // angle > M_PI_2 - bnd_circle.inc_angle
860 if (dot < bnd_circle.inc_angle.sin) {
861
862 if (node->flags & U_IS_LEAF) {
863
864 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
865 *num_overlap_cells + node->U_size);
866 memcpy(*overlap_cells + *num_overlap_cells, node->U,
867 node->U_size * sizeof(**overlap_cells));
868 *num_overlap_cells += node->U_size;
869
870 } else {
872 node->U, bnd_circle, overlap_cells, overlap_cells_array_size,
873 num_overlap_cells, search_interval_tree_buffer,
874 node->gc_norm_vector);
875 }
876 }
877
878 struct sin_cos_angle angle_sum =
879 sum_angles_no_check(node->I_angle, bnd_circle.inc_angle);
880
881 // if (I_angle + inc_angle > PI/2) ||
882 // (fabs(angle - M_PI_2) <= (I_angle + inc_angle))
883 //
884 // assumtion:
885 // I_angle >= 0 && I_angle <= PI/2
886 // inc_angle >= 0 && inc_angle <= PI/2
887 // angle >= 0 && angle <= PI
888 //
889 // => I_angle + inc_angle >= 0 && I_angle + inc_angle <= PI
890 //
891 // I_angle + inc_angle >= PI/2
892 //
893 // fabs(angle - M_PI_2) <= (I_angle + inc_angle)
894 // => sin(fabs(angle - M_PI_2)) <= sin(I_angle + inc_angle)
895 // this is wrong for (I_angle + inc_angle) > PI/2, however that case is
896 // already covered by the first condition
897 // => fabs(cos(angle)) <= sin(I_angle + inc_angle)
898 if (((angle_sum.sin < 0.0) || (angle_sum.cos <= 0.0)) ||
899 (fabs(dot) <= angle_sum.sin)) {
901 node, bnd_circle, overlap_cells, overlap_cells_array_size,
902 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
903 }
904}
905
906static void search_bnd_circle(struct sphere_part_node * node,
907 struct bounding_circle bnd_circle,
908 size_t ** restrict overlap_cells,
909 size_t * overlap_cells_array_size,
910 size_t * restrict num_overlap_cells,
911 struct overlaps * search_interval_tree_buffer,
912 double prev_gc_norm_vector[]) {
913
914 // if the bounding circle has an angle in the range of [0;PI/2[
915 if (bnd_circle.inc_angle.cos > 0.0)
917 node, bnd_circle, overlap_cells, overlap_cells_array_size,
918 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
919 else
921 node, bnd_circle, overlap_cells, overlap_cells_array_size,
922 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
923}
924
925static inline void check_leaf_NN(
926 struct point_id_xyz * points, size_t num_points,
927 double * point_coordinates_xyz, struct sin_cos_angle * best_angle,
928 double (**result_coordinates_xyz)[3],
929 size_t * result_coordinates_xyz_array_size, size_t ** local_point_ids,
930 size_t * local_point_ids_array_size, size_t total_num_local_point_ids,
931 size_t * num_local_point_ids) {
932
933 size_t * local_point_ids_ = *local_point_ids;
934 size_t local_point_ids_array_size_ = *local_point_ids_array_size;
935 double (*result_coordinates_xyz_)[3];
936 size_t result_coordinates_xyz_array_size_;
937 size_t num_local_point_ids_ = *num_local_point_ids;
938
939 if (result_coordinates_xyz != NULL) {
940 result_coordinates_xyz_ = *result_coordinates_xyz;
941 result_coordinates_xyz_array_size_ = *result_coordinates_xyz_array_size;
943 result_coordinates_xyz_, result_coordinates_xyz_array_size_,
944 total_num_local_point_ids + num_local_point_ids_ + num_points);
945 *result_coordinates_xyz = result_coordinates_xyz_;
946 *result_coordinates_xyz_array_size = result_coordinates_xyz_array_size_;
947 result_coordinates_xyz_ += total_num_local_point_ids;
948 }
950 local_point_ids_, local_point_ids_array_size_,
951 total_num_local_point_ids + num_local_point_ids_ + num_points);
952 *local_point_ids = local_point_ids_;
953 *local_point_ids_array_size = local_point_ids_array_size_;
954 local_point_ids_ += total_num_local_point_ids;
955
956
957 // check leaf for results
958 for (size_t i = 0; i < num_points; ++i) {
959
960 struct sin_cos_angle curr_angle =
962 points[i].coordinates_xyz, point_coordinates_xyz);
963 int compare = compare_angles(curr_angle, *best_angle);
964
965 // if the point is worse than the currently best point
966 if (compare > 0) continue;
967
968 // if we found a better point
969 if (compare < 0) {
970
971 *best_angle = curr_angle;
972 num_local_point_ids_ = 1;
973 if (result_coordinates_xyz != NULL) {
974 result_coordinates_xyz_[0][0] = points[i].coordinates_xyz[0];
975 result_coordinates_xyz_[0][1] = points[i].coordinates_xyz[1];
976 result_coordinates_xyz_[0][2] = points[i].coordinates_xyz[2];
977 }
978 local_point_ids_[0] = points[i].idx;
979
980 } else {
981
982 if (result_coordinates_xyz != NULL) {
983 result_coordinates_xyz_[num_local_point_ids_][0] =
984 points[i].coordinates_xyz[0];
985 result_coordinates_xyz_[num_local_point_ids_][1] =
986 points[i].coordinates_xyz[1];
987 result_coordinates_xyz_[num_local_point_ids_][2] =
988 points[i].coordinates_xyz[2];
989 }
990 local_point_ids_[num_local_point_ids_] = points[i].idx;
991 num_local_point_ids_++;
992 }
993 }
994
995 *num_local_point_ids = num_local_point_ids_;
996}
997
998static void point_search_NN(
999 struct bounding_circle * bnd_circle, double (**result_coordinates_xyz)[3],
1000 size_t * result_coordinates_xyz_array_size, size_t ** local_point_ids,
1001 size_t * local_point_ids_array_size, size_t total_num_local_point_ids,
1002 size_t * num_local_point_ids, double * dot_stack,
1003 struct point_sphere_part_node ** node_stack,
1004 int * flags, size_t curr_tree_depth) {
1005
1006 double * point_coordinates_xyz = bnd_circle->base_vector;
1007 struct sin_cos_angle best_angle = bnd_circle->inc_angle;
1008
1009 double dot = dot_stack[curr_tree_depth];
1010 struct point_sphere_part_node * node = node_stack[curr_tree_depth];
1011 int skip_U = flags[curr_tree_depth] & U_FLAG;
1012 int skip_T = flags[curr_tree_depth] & T_FLAG;
1013
1014 do {
1015
1016 if (!skip_U) {
1017
1018 flags[curr_tree_depth] |= U_FLAG;
1019
1020 // angle + inc_angle >= M_PI_2
1021 if ((dot < best_angle.sin) | (best_angle.cos <= 0.0)) {
1022
1023 if (node->flags & U_IS_LEAF) {
1024
1026 (struct point_id_xyz *)(node->U), node->U_size,
1027 point_coordinates_xyz, &best_angle, result_coordinates_xyz,
1028 result_coordinates_xyz_array_size, local_point_ids,
1029 local_point_ids_array_size, total_num_local_point_ids,
1030 num_local_point_ids);
1031
1032 } else {
1033
1034 // traverse down one level
1035 ++curr_tree_depth;
1036 node = (struct point_sphere_part_node *)(node->U);
1037 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1038 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1039 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1040 dot_stack[curr_tree_depth] = dot;
1041 node_stack[curr_tree_depth] = node;
1042 flags[curr_tree_depth] = 0;
1043 // skip_U = 0;
1044 skip_T = 0;
1045 continue;
1046 }
1047 }
1048 }
1049
1050 if (!skip_T) {
1051
1052 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1053
1054 // angle - inc_angle < M_PI_2
1055 if ((dot > - best_angle.sin) || (best_angle.cos <= 0.0)) {
1056
1057 if (node->flags & T_IS_LEAF) {
1058
1060 (struct point_id_xyz *)(node->T), node->T_size,
1061 point_coordinates_xyz, &best_angle, result_coordinates_xyz,
1062 result_coordinates_xyz_array_size, local_point_ids,
1063 local_point_ids_array_size, total_num_local_point_ids,
1064 num_local_point_ids);
1065
1066 } else {
1067
1068 // traverse down one level
1069 ++curr_tree_depth;
1070 node = (struct point_sphere_part_node *)(node->T);
1071 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1072 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1073 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1074 dot_stack[curr_tree_depth] = dot;
1075 node_stack[curr_tree_depth] = node;
1076 flags[curr_tree_depth] = 0;
1077 skip_U = 0;
1078 // skip_T = 0;
1079 continue;
1080 }
1081 }
1082 }
1083
1084 if (curr_tree_depth == 0) break;
1085
1086 // go up one level in the tree
1087
1088 curr_tree_depth--;
1089 dot = dot_stack[curr_tree_depth];
1090 node = node_stack[curr_tree_depth];
1091 skip_U = flags[curr_tree_depth] & U_FLAG;
1092 skip_T = flags[curr_tree_depth] & T_FLAG;
1093
1094 } while (1);
1095
1096 bnd_circle->inc_angle = best_angle;
1097}
1098
1099
1101 struct point_id_xyz * points, size_t num_points, double coordinate_xyz[3],
1102 size_t ** local_point_ids, size_t * local_point_ids_array_size,
1103 double (**result_coordinates_xyz)[3],
1104 size_t * result_coordinates_xyz_array_size,
1105 size_t total_num_local_point_ids, size_t * num_local_point_ids) {
1106
1107 for (size_t i = 0; i < num_points; ++i) {
1108
1109 // if the points are nearly identical
1110 if (points_are_identically(points[i].coordinates_xyz, coordinate_xyz)) {
1111
1112 ENSURE_ARRAY_SIZE(*local_point_ids, *local_point_ids_array_size,
1113 total_num_local_point_ids + 1);
1114 (*local_point_ids)[total_num_local_point_ids] = points[i].idx;
1115 if (result_coordinates_xyz != NULL) {
1116 ENSURE_ARRAY_SIZE(*result_coordinates_xyz,
1117 *result_coordinates_xyz_array_size,
1118 total_num_local_point_ids + 1);
1119 memcpy((*result_coordinates_xyz) + total_num_local_point_ids,
1120 points[i].coordinates_xyz, 3 * sizeof(double));
1121 }
1122 *num_local_point_ids = 1;
1123 return 1;
1124 }
1125 }
1126
1127 return 0;
1128}
1129
1131 size_t num_points,
1132 double (*coordinates_xyz)[3],
1133 double * cos_angles,
1134 double (**result_coordinates_xyz)[3],
1135 size_t * result_coordinates_xyz_array_size,
1136 size_t ** local_point_ids,
1137 size_t * local_point_ids_array_size,
1138 size_t * num_local_point_ids) {
1139
1140 memset(num_local_point_ids, 0, num_points * sizeof(*num_local_point_ids));
1141
1142 if (search == NULL) return;
1143
1144 struct point_sphere_part_node * base_node = &(search->base_node);
1145
1146 size_t total_num_local_point_ids = 0;
1147
1148 double * dot_stack = xmalloc(search->max_tree_depth * sizeof(*dot_stack));
1149 struct point_sphere_part_node ** node_stack =
1150 xmalloc(search->max_tree_depth * sizeof(*node_stack));
1151 int * flags = xmalloc(search->max_tree_depth * sizeof(*flags));
1152
1153 for (size_t i = 0; i < num_points; ++i) {
1154
1155 struct point_sphere_part_node * curr_node = base_node;
1156
1157 double * curr_coordinates_xyz = coordinates_xyz[i];
1158
1159 size_t curr_tree_depth = 0;
1160 struct point_id_xyz * points = NULL;
1161 size_t curr_num_points = 0;
1162
1163 // get the matching leaf for the current point
1164 do {
1165
1166 double dot = curr_node->gc_norm_vector[0]*curr_coordinates_xyz[0] +
1167 curr_node->gc_norm_vector[1]*curr_coordinates_xyz[1] +
1168 curr_node->gc_norm_vector[2]*curr_coordinates_xyz[2];
1169
1170 dot_stack[curr_tree_depth] = dot;
1171 node_stack[curr_tree_depth] = curr_node;
1172 flags[curr_tree_depth] = 0;
1173
1174 // angle > M_PI_2
1175 if (dot < yac_angle_tol) {
1176
1177 flags[curr_tree_depth] = U_FLAG;
1178
1179 if (curr_node->flags & U_IS_LEAF) {
1180 if (curr_node->U_size > 0) {
1181 points = (struct point_id_xyz*)(curr_node->U);
1182 curr_num_points = curr_node->U_size;
1183 break;
1184 } else {
1185 flags[curr_tree_depth] = T_FLAG;
1186 YAC_ASSERT(
1187 curr_node->flags & T_IS_LEAF,
1188 "ERROR(yac_point_sphere_part_search_NN): "
1189 "if one branch is empty, the other has to be a leaf");
1190 points = (struct point_id_xyz*)(curr_node->T);
1191 curr_num_points = curr_node->T_size;
1192 break;
1193 }
1194 } else curr_node = curr_node->U;
1195
1196 // angle < M_PI_2
1197 } else if (dot > -yac_angle_tol) {
1198
1199 flags[curr_tree_depth] = T_FLAG;
1200
1201 if (curr_node->flags & T_IS_LEAF) {
1202 if (curr_node->T_size > 0) {
1203 points = (struct point_id_xyz*)(curr_node->T);
1204 curr_num_points = curr_node->T_size;
1205 break;
1206 } else {
1207 flags[curr_tree_depth] = U_FLAG;
1208 YAC_ASSERT(
1209 curr_node->flags & U_IS_LEAF,
1210 "ERROR(yac_point_sphere_part_search_NN): "
1211 "if one branch is empty, the other has to be a leaf");
1212 points = (struct point_id_xyz*)(curr_node->U);
1213 curr_num_points = curr_node->U_size;
1214 break;
1215 }
1216 } else curr_node = curr_node->T;
1217 }
1218
1219 curr_tree_depth++;
1220 } while (1);
1221
1222 // if we do not have to do a finer search
1224 points, curr_num_points, curr_coordinates_xyz, local_point_ids,
1225 local_point_ids_array_size, result_coordinates_xyz,
1226 result_coordinates_xyz_array_size, total_num_local_point_ids,
1227 num_local_point_ids + i)) {
1228
1229 if (cos_angles != NULL) cos_angles[i] = 1.0;
1230
1231 } else {
1232
1233 struct bounding_circle bnd_circle;
1234 bnd_circle.base_vector[0] = curr_coordinates_xyz[0];
1235 bnd_circle.base_vector[1] = curr_coordinates_xyz[1];
1236 bnd_circle.base_vector[2] = curr_coordinates_xyz[2];
1237 bnd_circle.inc_angle = SIN_COS_M_PI;
1238 bnd_circle.sq_crd = DBL_MAX;
1239
1241 points, curr_num_points, curr_coordinates_xyz, &bnd_circle.inc_angle,
1242 result_coordinates_xyz, result_coordinates_xyz_array_size,
1243 local_point_ids, local_point_ids_array_size, total_num_local_point_ids,
1244 num_local_point_ids + i);
1245
1246 // get best result points
1248 &bnd_circle, result_coordinates_xyz, result_coordinates_xyz_array_size,
1249 local_point_ids, local_point_ids_array_size, total_num_local_point_ids,
1250 num_local_point_ids + i, dot_stack, node_stack, flags, curr_tree_depth);
1251
1252 if (cos_angles != NULL) cos_angles[i] = bnd_circle.inc_angle.cos;
1253 }
1254
1255 total_num_local_point_ids += num_local_point_ids[i];
1256 }
1257
1258 free(flags);
1259 free(node_stack);
1260 free(dot_stack);
1261}
1262
1263static inline int compare_point_id_xyz_angle(const void * a, const void * b) {
1264
1265 const struct point_id_xyz_angle * p_a = (const struct point_id_xyz_angle *)a;
1266 const struct point_id_xyz_angle * p_b = (const struct point_id_xyz_angle *)b;
1267
1268 int ret = (p_a->cos_angle < p_b->cos_angle) -
1269 (p_a->cos_angle > p_b->cos_angle);
1270
1271 if (ret != 0) return ret;
1272
1273 return (p_a->point.idx > p_b->point.idx) - (p_a->point.idx < p_b->point.idx);
1274}
1275
1277 size_t n, struct point_id_xyz * points, size_t num_points,
1278 double * point_coordinates_xyz, struct point_id_xyz_angle ** results,
1279 size_t * results_array_size) {
1280
1281 assert(num_points > 0);
1282
1283 ENSURE_ARRAY_SIZE(*results, *results_array_size, num_points);
1284 struct point_id_xyz_angle * results_ = *results;
1285
1286#ifdef __NEC__
1287// vectorization of the following loop leads to failues of
1288//
1289// test_couple_config_parallel1
1290// test_interp_method_nnn_parallel
1291// test_interp_method_hcsbb_parallel
1292//
1293// with NEC compiler when CFLAGS='-O2'
1294#pragma _NEC novector
1295#endif
1296 for (size_t i = 0; i < num_points; ++i) {
1297
1298 results_[i].point = points[i];
1299 results_[i].cos_angle = clamp_abs_one(
1300 points[i].coordinates_xyz[0] * point_coordinates_xyz[0] +
1301 points[i].coordinates_xyz[1] * point_coordinates_xyz[1] +
1302 points[i].coordinates_xyz[2] * point_coordinates_xyz[2]);
1303 }
1304
1305 qsort(results_, num_points, sizeof(*results_), compare_point_id_xyz_angle);
1306
1307 if (num_points <= n) return num_points;
1308
1309 size_t num_results;
1310 double min_cos_angle = results_[n - 1].cos_angle;
1311
1312 for (num_results = n;
1313 (num_results < num_points) &&
1314 !(fabs(min_cos_angle - results_[num_results].cos_angle) > 0.0);
1315 ++num_results);
1316
1317 return num_results;
1318}
1319
1320static inline struct sin_cos_angle check_leaf_NNN(
1321 size_t n, double * point_coordinates_xyz,
1322 struct point_id_xyz * points, size_t num_points,
1323 struct point_id_xyz_angle ** results, size_t * results_array_size,
1324 size_t * num_results, struct sin_cos_angle curr_angle) {
1325
1326 size_t num_results_ = *num_results;
1327 ENSURE_ARRAY_SIZE(*results, *results_array_size, num_results_ + num_points);
1328 struct point_id_xyz_angle * results_ = *results;
1329
1330 int flag = 0;
1331
1332 double min_cos_angle = results_[num_results_-1].cos_angle;
1333
1334 // check leaf for results
1335 for (size_t i = 0; i < num_points; ++i) {
1336
1337 double curr_cos_angle =
1338 points[i].coordinates_xyz[0] * point_coordinates_xyz[0] +
1339 points[i].coordinates_xyz[1] * point_coordinates_xyz[1] +
1340 points[i].coordinates_xyz[2] * point_coordinates_xyz[2];
1341
1342 // if the point is worse than the currently best point
1343 if (curr_cos_angle < min_cos_angle) continue;
1344
1345 struct point_id_xyz_angle point =
1346 {.point = points[i], .cos_angle = curr_cos_angle};
1347
1348 // insert point
1349 size_t j;
1350 for (j = 0; j < num_results_; ++j) {
1351
1353 &point, results_ + num_results_ - j - 1) < 0) {
1354 results_[num_results_ - j] = results_[num_results_ - j - 1];
1355 } else {
1356 break;
1357 }
1358 }
1359 results_[num_results_ - j] = point;
1360
1361 ++num_results_;
1362 flag = 1;
1363 }
1364
1365 if (flag) {
1366
1367 if (num_results_ > n) {
1368
1369 size_t new_num_results;
1370 min_cos_angle = results_[n - 1].cos_angle;
1371
1372 for (new_num_results = n;
1373 (new_num_results < num_results_) &&
1374 !(fabs(min_cos_angle - results_[new_num_results].cos_angle) > 0.0);
1375 ++new_num_results);
1376 num_results_ = new_num_results;
1377 }
1378 *num_results = num_results_;
1379
1380 return
1382 results_[num_results_-1].point.coordinates_xyz, point_coordinates_xyz);
1383 } else return curr_angle;
1384}
1385
1387 size_t n, double * point_coordinates_xyz,
1388 struct point_id_xyz_angle ** results, size_t * results_array_size,
1389 size_t * num_results, double * dot_stack,
1390 struct point_sphere_part_node ** node_stack, int * flags,
1391 size_t curr_tree_depth) {
1392
1393 struct sin_cos_angle angle =
1395 (*results)[(*num_results)-1].point.coordinates_xyz,
1396 point_coordinates_xyz);
1397
1398 // if we have already found at least n exactly matching points
1399 if ((*num_results >= n) && (angle.sin <= yac_angle_tol)) return;
1400
1401 double dot = dot_stack[curr_tree_depth];
1402 struct point_sphere_part_node * node = node_stack[curr_tree_depth];
1403 int skip_U = flags[curr_tree_depth] & U_FLAG;
1404 int skip_T = flags[curr_tree_depth] & T_FLAG;
1405
1406 do {
1407
1408 if (!skip_U) {
1409
1410 flags[curr_tree_depth] |= U_FLAG;
1411
1412 // angle + inc_angle >= M_PI_2
1413 if ((dot < angle.sin) | (angle.cos <= 0.0)) {
1414
1415 if (node->flags & U_IS_LEAF) {
1416
1417 angle = check_leaf_NNN(
1418 n, point_coordinates_xyz, (struct point_id_xyz *)(node->U),
1419 node->U_size, results, results_array_size, num_results, angle);
1420
1421 } else {
1422
1423 // traverse down one level
1424 ++curr_tree_depth;
1425 node = (struct point_sphere_part_node *)(node->U);
1426 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1427 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1428 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1429 dot_stack[curr_tree_depth] = dot;
1430 node_stack[curr_tree_depth] = node;
1431 flags[curr_tree_depth] = 0;
1432 // skip_U = 0;
1433 skip_T = 0;
1434 continue;
1435 }
1436 }
1437 }
1438
1439 if (!skip_T) {
1440
1441 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1442
1443 // angle - inc_angle < M_PI_2
1444 if ((dot > - angle.sin) || (angle.cos <= 0.0)) {
1445
1446 if (node->flags & T_IS_LEAF) {
1447
1448 angle = check_leaf_NNN(
1449 n, point_coordinates_xyz, (struct point_id_xyz *)(node->T),
1450 node->T_size, results, results_array_size, num_results, angle);
1451
1452 } else {
1453
1454 // traverse down one level
1455 ++curr_tree_depth;
1456 node = (struct point_sphere_part_node *)(node->T);
1457 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1458 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1459 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1460 dot_stack[curr_tree_depth] = dot;
1461 node_stack[curr_tree_depth] = node;
1462 flags[curr_tree_depth] = 0;
1463 skip_U = 0;
1464 // skip_T = 0;
1465 continue;
1466 }
1467 }
1468 }
1469
1470 if (curr_tree_depth == 0) break;
1471
1472 // go up one level in the tree
1473
1474 curr_tree_depth--;
1475 dot = dot_stack[curr_tree_depth];
1476 node = node_stack[curr_tree_depth];
1477 skip_U = flags[curr_tree_depth] & U_FLAG;
1478 skip_T = flags[curr_tree_depth] & T_FLAG;
1479
1480 } while (1);
1481}
1482
1484 size_t num_points,
1485 double (*coordinates_xyz)[3], size_t n,
1486 double ** cos_angles,
1487 size_t * cos_angles_array_size,
1488 double (**result_coordinates_xyz)[3],
1489 size_t * result_coordinates_xyz_array_size,
1490 size_t ** local_point_ids,
1491 size_t * local_point_ids_array_size,
1492 size_t * num_local_point_ids) {
1493
1494 if (num_points == 0) return;
1495
1496 if (cos_angles != NULL)
1497 ENSURE_ARRAY_SIZE(*cos_angles, *cos_angles_array_size, num_points * n);
1498
1499 if (n == 1) {
1501 search, num_points, coordinates_xyz, (cos_angles!=NULL)?*cos_angles:NULL,
1502 result_coordinates_xyz, result_coordinates_xyz_array_size,
1503 local_point_ids, local_point_ids_array_size, num_local_point_ids);
1504
1505 size_t total_num_local_points = 0;
1506 for (size_t i = 0; i < num_points; ++i)
1507 total_num_local_points += num_local_point_ids[i];
1508
1509 if ((cos_angles != NULL) && (total_num_local_points > num_points)) {
1510
1511 ENSURE_ARRAY_SIZE(*cos_angles, *cos_angles_array_size,
1512 total_num_local_points);
1513
1514 for (size_t i = num_points - 1, offset = total_num_local_points - 1;
1515 i != (size_t)-1; i--) {
1516
1517 for (size_t j = 0; j < num_local_point_ids[i]; ++j, --offset)
1518 (*cos_angles)[offset] = (*cos_angles)[i];
1519 }
1520 }
1521 return;
1522 }
1523
1524
1525 if (search == NULL) {
1526 memset(num_local_point_ids, 0, num_points * sizeof(*num_local_point_ids));
1527 return;
1528 }
1529
1530 struct point_sphere_part_node * base_node = &(search->base_node);
1531
1532 size_t total_num_local_point_ids = 0;
1533
1534 double * dot_stack = xmalloc(search->max_tree_depth * sizeof(*dot_stack));
1535 struct point_sphere_part_node ** node_stack =
1536 xmalloc(search->max_tree_depth * sizeof(*node_stack));
1537 int * flags = xmalloc(search->max_tree_depth * sizeof(*flags));
1538
1539 struct point_id_xyz_angle * results = NULL;
1540 size_t results_array_size = 0;
1541
1542 for (size_t i = 0; i < num_points; ++i) {
1543
1544 struct point_sphere_part_node * curr_node = base_node;
1545
1546 double * curr_coordinates_xyz = coordinates_xyz[i];
1547
1548 size_t curr_tree_depth = 0;
1549 struct point_id_xyz * points = search->points;
1550 size_t curr_num_points = 0;
1551
1552 // get the matching leaf for the current point
1553 do {
1554
1555 double dot = curr_node->gc_norm_vector[0]*curr_coordinates_xyz[0] +
1556 curr_node->gc_norm_vector[1]*curr_coordinates_xyz[1] +
1557 curr_node->gc_norm_vector[2]*curr_coordinates_xyz[2];
1558
1559 dot_stack[curr_tree_depth] = dot;
1560 node_stack[curr_tree_depth] = curr_node;
1561 flags[curr_tree_depth] = 0;
1562
1563 // angle >= M_PI_2
1564 if (dot <= 0.0) {
1565
1566 if (curr_node->U_size < n) {
1567
1568 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1569 curr_num_points = curr_node->U_size + curr_node->T_size;
1570 break;
1571 } else if (curr_node->flags & U_IS_LEAF) {
1572
1573 flags[curr_tree_depth] = U_FLAG;
1574 curr_num_points = curr_node->U_size;
1575 break;
1576 } else {
1577
1578 flags[curr_tree_depth] = U_FLAG;
1579 curr_node = curr_node->U;
1580 }
1581
1582 } else {
1583
1584 if (curr_node->T_size < n) {
1585
1586 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1587 curr_num_points = curr_node->U_size + curr_node->T_size;
1588 break;
1589 } else if (curr_node->flags & T_IS_LEAF) {
1590
1591 points += curr_node->U_size;
1592 flags[curr_tree_depth] = T_FLAG;
1593 curr_num_points = curr_node->T_size;
1594 break;
1595 } else {
1596
1597 points += curr_node->U_size;
1598 flags[curr_tree_depth] = T_FLAG;
1599 curr_node = curr_node->T;
1600 }
1601 }
1602
1603 curr_tree_depth++;
1604 } while (1);
1605
1606 assert(curr_num_points > 0);
1607
1608 size_t num_results =
1610 n, points, curr_num_points, curr_coordinates_xyz,
1611 &results, &results_array_size);
1612
1613 // do a detailed search
1615 n, curr_coordinates_xyz, &results, &results_array_size, &num_results,
1616 dot_stack, node_stack, flags, curr_tree_depth);
1617
1618 // extract the results
1619 ENSURE_ARRAY_SIZE(*local_point_ids, *local_point_ids_array_size,
1620 total_num_local_point_ids + num_results);
1621 size_t * local_point_ids_ =
1622 (*local_point_ids) + total_num_local_point_ids;
1623 double * cos_angles_;
1624 if (cos_angles != NULL) {
1625 ENSURE_ARRAY_SIZE(*cos_angles, *cos_angles_array_size,
1626 total_num_local_point_ids + num_results);
1627 cos_angles_ = (*cos_angles) + total_num_local_point_ids;
1628 } else {
1629 cos_angles_ = NULL;
1630 }
1631 double (*result_coordinates_xyz_)[3];
1632 if (result_coordinates_xyz != NULL) {
1633 ENSURE_ARRAY_SIZE(*result_coordinates_xyz,
1634 *result_coordinates_xyz_array_size,
1635 total_num_local_point_ids + num_results);
1636 result_coordinates_xyz_ =
1637 (*result_coordinates_xyz) + total_num_local_point_ids;
1638 } else {
1639 result_coordinates_xyz_ = NULL;
1640 }
1641
1642 for (size_t j = 0; j < num_results; ++j) {
1643
1644 local_point_ids_[j] = results[j].point.idx;
1645 if (cos_angles_ != NULL) cos_angles_[j] = results[j].cos_angle;
1646 if (result_coordinates_xyz_ != NULL) {
1647 result_coordinates_xyz_[j][0] = results[j].point.coordinates_xyz[0];
1648 result_coordinates_xyz_[j][1] = results[j].point.coordinates_xyz[1];
1649 result_coordinates_xyz_[j][2] = results[j].point.coordinates_xyz[2];
1650 }
1651 }
1652
1653 num_local_point_ids[i] = num_results;
1654 total_num_local_point_ids += num_results;
1655 }
1656
1657 free(results);
1658 free(flags);
1659 free(node_stack);
1660 free(dot_stack);
1661}
1662
1664 struct point_sphere_part_search * search,
1665 size_t num_bnd_circles, struct bounding_circle * bnd_circles,
1666 size_t n, size_t ** local_point_ids, size_t * local_point_ids_array_size,
1667 size_t * num_local_point_ids) {
1668
1669 if (num_bnd_circles == 0) return;
1670
1671 if (search == NULL) {
1672 memset(
1673 num_local_point_ids, 0, num_bnd_circles * sizeof(*num_local_point_ids));
1674 return;
1675 }
1676
1677 struct point_sphere_part_node * base_node = &(search->base_node);
1678
1679 size_t total_num_local_point_ids = 0;
1680
1681 double * dot_stack = xmalloc(search->max_tree_depth * sizeof(*dot_stack));
1682 struct point_sphere_part_node ** node_stack =
1683 xmalloc(search->max_tree_depth * sizeof(*node_stack));
1684 int * flags = xmalloc(search->max_tree_depth * sizeof(*flags));
1685
1686 struct point_id_xyz_angle * results = NULL;
1687 size_t results_array_size = 0;
1688
1689 for (size_t i = 0; i < num_bnd_circles; ++i) {
1690
1691 struct point_sphere_part_node * curr_node = base_node;
1692
1693 double * curr_coordinates_xyz = bnd_circles[i].base_vector;
1694
1695 size_t curr_tree_depth = 0;
1696 struct point_id_xyz * points = search->points;
1697 size_t curr_num_points = 0;
1698
1699 // get the matching leaf for the current point
1700 do {
1701
1702 double dot = curr_node->gc_norm_vector[0]*curr_coordinates_xyz[0] +
1703 curr_node->gc_norm_vector[1]*curr_coordinates_xyz[1] +
1704 curr_node->gc_norm_vector[2]*curr_coordinates_xyz[2];
1705
1706 dot_stack[curr_tree_depth] = dot;
1707 node_stack[curr_tree_depth] = curr_node;
1708 flags[curr_tree_depth] = 0;
1709
1710 // angle >= M_PI_2
1711 if (dot <= 0.0) {
1712
1713 if (curr_node->U_size < n) {
1714
1715 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1716 curr_num_points = curr_node->U_size + curr_node->T_size;
1717 break;
1718 } else if (curr_node->flags & U_IS_LEAF) {
1719
1720 flags[curr_tree_depth] = U_FLAG;
1721 curr_num_points = curr_node->U_size;
1722 break;
1723 } else {
1724
1725 flags[curr_tree_depth] = U_FLAG;
1726 curr_node = curr_node->U;
1727 }
1728
1729 } else {
1730
1731 if (curr_node->T_size < n) {
1732
1733 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1734 curr_num_points = curr_node->U_size + curr_node->T_size;
1735 break;
1736 } else if (curr_node->flags & T_IS_LEAF) {
1737
1738 points += curr_node->U_size;
1739 flags[curr_tree_depth] = T_FLAG;
1740 curr_num_points = curr_node->T_size;
1741 break;
1742 } else {
1743
1744 points += curr_node->U_size;
1745 flags[curr_tree_depth] = T_FLAG;
1746 curr_node = curr_node->T;
1747 }
1748 }
1749
1750 curr_tree_depth++;
1751 } while (1);
1752
1753 YAC_ASSERT(
1754 curr_num_points > 0,
1755 "ERROR(yac_point_sphere_part_search_NNN_bnd_circle): "
1756 "insufficient number of points");
1757
1758 size_t num_results =
1760 n, points, curr_num_points, curr_coordinates_xyz,
1761 &results, &results_array_size);
1762
1763 // do a detailed search
1765 n, curr_coordinates_xyz, &results, &results_array_size, &num_results,
1766 dot_stack, node_stack, flags, curr_tree_depth);
1767
1768 for (; num_results > 0; --num_results)
1769 if (results[num_results-1].cos_angle >= bnd_circles[i].inc_angle.cos)
1770 break;
1771
1772 // extract the results
1773 ENSURE_ARRAY_SIZE(*local_point_ids, *local_point_ids_array_size,
1774 total_num_local_point_ids + num_results);
1775 size_t * local_point_ids_ =
1776 (*local_point_ids) + total_num_local_point_ids;
1777
1778 for (size_t j = 0; j < num_results; ++j)
1779 local_point_ids_[j] = results[j].point.idx;
1780
1781 num_local_point_ids[i] = num_results;
1782 total_num_local_point_ids += num_results;
1783 }
1784
1785 free(results);
1786 free(flags);
1787 free(node_stack);
1788 free(dot_stack);
1789}
1790
1791static int compare_angles_(void const * a, void const * b) {
1792 struct sin_cos_angle * a_ = (struct sin_cos_angle *)a;
1793 struct sin_cos_angle * b_ = (struct sin_cos_angle *)b;
1794 return compare_angles(*a_, *b_);
1795}
1796
1798 struct point_sphere_part_search * search,
1799 size_t num_points, yac_coordinate_pointer coordinates_xyz,
1800 size_t n, struct sin_cos_angle * angles) {
1801
1802 YAC_ASSERT(
1803 search != NULL,
1804 "ERRROR(yac_point_sphere_part_search_NNN_ubound): "
1805 "invalid point sphere part search (has to be != NULL)");
1806 YAC_ASSERT(
1807 n > 0, "ERROR(yac_point_sphere_part_search_NNN_ubound): "
1808 "invalid n (has to be > 0)")
1809
1810 struct sin_cos_angle * temp_angles = NULL;
1811 size_t temp_angles_array_size = 0;
1812
1813 struct point_sphere_part_node * base_node = &(search->base_node);
1814
1815 for (size_t i = 0; i < num_points; ++i) {
1816
1817 struct point_sphere_part_node * curr_node = base_node;
1818
1819 double * curr_coordinates_xyz = coordinates_xyz[i];
1820
1821 struct point_id_xyz * points = search->points;
1822 size_t curr_num_points = 0;
1823
1824 // get the matching leaf for the current point
1825 do {
1826
1827 double dot = curr_node->gc_norm_vector[0]*curr_coordinates_xyz[0] +
1828 curr_node->gc_norm_vector[1]*curr_coordinates_xyz[1] +
1829 curr_node->gc_norm_vector[2]*curr_coordinates_xyz[2];
1830
1831 // angle >= M_PI_2
1832 if (dot <= 0.0) {
1833
1834 if (curr_node->U_size < n) {
1835
1836 curr_num_points = curr_node->U_size + curr_node->T_size;
1837 break;
1838 } else if (curr_node->flags & U_IS_LEAF) {
1839
1840 curr_num_points = curr_node->U_size;
1841 break;
1842 } else {
1843
1844 curr_node = curr_node->U;
1845 }
1846
1847 } else {
1848
1849 if (curr_node->T_size < n) {
1850
1851 curr_num_points = curr_node->U_size + curr_node->T_size;
1852 break;
1853 } else if (curr_node->flags & T_IS_LEAF) {
1854
1855 points += curr_node->U_size;
1856 curr_num_points = curr_node->T_size;
1857 break;
1858 } else {
1859
1860 points += curr_node->U_size;
1861 curr_node = curr_node->T;
1862 }
1863 }
1864 } while (1);
1865
1866 YAC_ASSERT(
1867 curr_num_points >= n,
1868 "ERROR(yac_point_sphere_part_search_NNN_ubound): "
1869 "failed to find a sufficient number of points");
1870
1871 // search of the closest "n" points in the current
1872 // list of points
1873
1874 if (n == 1) {
1875
1876 struct sin_cos_angle best_angle =
1878 curr_coordinates_xyz, points[0].coordinates_xyz);
1879 for (size_t j = 1; j < curr_num_points; ++j) {
1880 struct sin_cos_angle curr_angle =
1882 curr_coordinates_xyz, points[j].coordinates_xyz);
1883 if (compare_angles(best_angle, curr_angle) > 0)
1884 best_angle = curr_angle;
1885 }
1886 angles[i] = best_angle;
1887
1888 } else {
1889
1890 // compute the angles for all current points
1892 temp_angles, temp_angles_array_size, curr_num_points);
1893 for (size_t j = 0; j < curr_num_points; ++j)
1894 temp_angles[j] =
1896 curr_coordinates_xyz, points[j].coordinates_xyz);
1897
1898 qsort(
1899 temp_angles, curr_num_points, sizeof(*temp_angles),
1901
1902 angles[i] = temp_angles[n-1];
1903 }
1904 }
1905
1906 free(temp_angles);
1907}
1908
1909static void search_point(struct sphere_part_node * node,
1910 double point[],
1911 size_t ** overlap_cells,
1912 size_t * overlap_cells_array_size,
1913 size_t * num_overlap_cells,
1914 struct overlaps * search_interval_tree_buffer,
1915 double prev_gc_norm_vector[]) {
1916
1917 double dot = point[0] * node->gc_norm_vector[0] +
1918 point[1] * node->gc_norm_vector[1] +
1919 point[2] * node->gc_norm_vector[2];
1920
1921 // angle < M_PI_2
1922 if (dot > -yac_angle_tol) {
1923
1924 if (node->flags & T_IS_LEAF) {
1925
1926 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1927 *num_overlap_cells + node->T_size);
1928 memcpy(*overlap_cells + *num_overlap_cells, node->T,
1929 node->T_size * sizeof(**overlap_cells));
1930 *num_overlap_cells += node->T_size;
1931
1932 } else {
1933 search_point(node->T, point, overlap_cells,
1934 overlap_cells_array_size, num_overlap_cells,
1935 search_interval_tree_buffer, node->gc_norm_vector);
1936 }
1937 }
1938
1939 // angle > M_PI_2
1940 if (dot < yac_angle_tol) {
1941
1942 if (node->flags & U_IS_LEAF) {
1943
1944 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1945 *num_overlap_cells + node->U_size);
1946 memcpy(*overlap_cells + *num_overlap_cells, node->U,
1947 node->U_size * sizeof(**overlap_cells));
1948 *num_overlap_cells += node->U_size;
1949
1950 } else {
1951 search_point(node->U, point, overlap_cells,
1952 overlap_cells_array_size, num_overlap_cells,
1953 search_interval_tree_buffer, node->gc_norm_vector);
1954 }
1955 }
1956
1957 // fabs(angle - M_PI_2) <= (node->I_angle)
1958 // fabs(cos(angle)) <= sin(node->I_angle)
1959 if (fabs(dot) <= node->I_angle.sin) {
1960
1961 if (node->flags & I_IS_INTERVAL_TREE) {
1962
1963 // project the point onto the current great circle
1964 double GCp[3], bVp[3];
1965 crossproduct_kahan(node->gc_norm_vector, point, GCp);
1966 crossproduct_kahan(GCp, node->gc_norm_vector, bVp);
1967
1968 struct interval search_interval;
1969 // if the projected point does not coincide with the norm vector of
1970 // the plane through the great circle
1971 if ((fabs(bVp[0]) > 1e-9) || (fabs(bVp[1]) > 1e-9) ||
1972 (fabs(bVp[2]) > 1e-9)) {
1973 normalise_vector(bVp);
1974 double base_angle = get_vector_angle(bVp, prev_gc_norm_vector);
1975 search_interval.left=base_angle;
1976 search_interval.right=base_angle;
1977 } else {
1978 search_interval.left = -M_PI;
1979 search_interval.right = M_PI;
1980 }
1981
1982 search_interval_tree_buffer->num_overlaps = 0;
1983
1985 search_interval, search_interval_tree_buffer);
1986
1987 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1988 *num_overlap_cells +
1989 search_interval_tree_buffer->num_overlaps);
1990
1991 for (size_t i = 0; i < search_interval_tree_buffer->num_overlaps;
1992 ++i) {
1993 (*overlap_cells)[(*num_overlap_cells)+i] =
1994 node->I.ivt.head_node[
1995 search_interval_tree_buffer->overlap_iv[i]].value;
1996 }
1997
1998 *num_overlap_cells += search_interval_tree_buffer->num_overlaps;
1999
2000 } else {
2001
2002 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
2003 *num_overlap_cells + node->I_size);
2004 memcpy(*overlap_cells + *num_overlap_cells, node->I.list,
2005 node->I_size * sizeof(**overlap_cells));
2006 *num_overlap_cells += node->I_size;
2007 }
2008 }
2009}
2010
2012 struct bnd_sphere_part_search * search, yac_coordinate_pointer coordinates_xyz,
2013 size_t count, size_t ** cells, size_t * num_cells_per_coordinate) {
2014
2015 struct sphere_part_node * base_node = &(search->base_node);
2016
2017 size_t * temp_search_results = NULL;
2018 size_t temp_search_results_array_size = 0;
2019 size_t num_temp_search_results = 0;
2020
2021 struct overlaps search_interval_tree_buffer = {0, 0, NULL};
2022
2023 memset(
2024 num_cells_per_coordinate, 0, count * sizeof(*num_cells_per_coordinate));
2025 size_t * cells_ = NULL;
2026 size_t cells_array_size = 0;
2027 size_t num_cells = 0;
2028 ENSURE_ARRAY_SIZE(cells_, cells_array_size, count);
2029
2030 for (size_t i = 0; i < count; ++i) {
2031
2032 double * curr_coordinates_xyz = &(coordinates_xyz[i][0]);
2033
2034 num_temp_search_results = 0;
2035
2036 double gc_norm_vector[3] = {0.0,0.0,1.0};
2037
2038 search_point(base_node, curr_coordinates_xyz, &temp_search_results,
2039 &temp_search_results_array_size, &num_temp_search_results,
2040 &search_interval_tree_buffer, gc_norm_vector);
2041
2043 cells_, cells_array_size, num_cells + num_temp_search_results);
2044
2045 memcpy(cells_ + num_cells, temp_search_results,
2046 num_temp_search_results * sizeof(*temp_search_results));
2047 num_cells_per_coordinate[i] = num_temp_search_results;
2048 num_cells += num_temp_search_results;
2049 }
2050
2051 free(temp_search_results);
2052 free(search_interval_tree_buffer.overlap_iv);
2053
2054 *cells = xrealloc(cells_, num_cells * sizeof(*cells_));
2055}
2056
2058 struct bnd_sphere_part_search * search, struct bounding_circle * bnd_circles,
2059 size_t count, size_t ** cells, size_t * num_cells_per_bnd_circle) {
2060
2061 struct sphere_part_node * base_node = &(search->base_node);
2062
2063 size_t * temp_search_results = NULL;
2064 size_t temp_search_results_array_size = 0;
2065 size_t num_temp_search_results = 0;
2066
2067 struct overlaps search_interval_tree_buffer = {0, 0, NULL};
2068
2069 memset(
2070 num_cells_per_bnd_circle, 0, count * sizeof(*num_cells_per_bnd_circle));
2071 size_t * cells_ = NULL;
2072 size_t cells_array_size = 0;
2073 size_t num_cells = 0;
2074 ENSURE_ARRAY_SIZE(cells_, cells_array_size, count);
2075
2076 for (size_t i = 0; i < count; ++i) {
2077
2078 num_temp_search_results = 0;
2079
2080 double gc_norm_vector[3] = {0.0,0.0,1.0};
2081
2082 search_bnd_circle(base_node, bnd_circles[i], &temp_search_results,
2083 &temp_search_results_array_size, &num_temp_search_results,
2084 &search_interval_tree_buffer, gc_norm_vector);
2085
2087 cells_, cells_array_size, num_cells + num_temp_search_results);
2088
2089 memcpy(cells_ + num_cells, temp_search_results,
2090 num_temp_search_results * sizeof(*temp_search_results));
2091 num_cells_per_bnd_circle[i] = num_temp_search_results;
2092 num_cells += num_temp_search_results;
2093 }
2094
2095 free(temp_search_results);
2096 free(search_interval_tree_buffer.overlap_iv);
2097
2098 *cells = xrealloc(cells_, num_cells * sizeof(*cells_));
2099}
2100
2101static void free_sphere_part_tree (struct sphere_part_node tree) {
2102
2103 // free I_list
2104 if (tree.flags & I_IS_INTERVAL_TREE)
2105 free(tree.I.ivt.head_node);
2106
2107 if ((tree.flags & U_IS_LEAF) == 0) {
2108 free_sphere_part_tree(*(struct sphere_part_node*)(tree.U));
2109 free(tree.U);
2110 }
2111
2112 if ((tree.flags & T_IS_LEAF) == 0) {
2113 free_sphere_part_tree(*(struct sphere_part_node*)(tree.T));
2114 free(tree.T);
2115 }
2116}
2117
2119
2120 if ((tree->flags & U_IS_LEAF) == 0) {
2122 free(tree->U);
2123 }
2124
2125 if ((tree->flags & T_IS_LEAF) == 0) {
2127 free(tree->T);
2128 }
2129}
2130
2132 struct point_sphere_part_search * search) {
2133
2134 if (search == NULL) return;
2135
2137 free(search->points);
2138 free(search);
2139}
2140
2142
2143 if (search == NULL) return;
2144
2146 free(search->ids);
2147 free(search);
2148}
#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 double clamp_abs_one(double val)
Definition geometry.h:401
static const struct sin_cos_angle SIN_COS_ZERO
Definition geometry.h:44
static int points_are_identically(double const *a, double const *b)
Definition geometry.h:648
static const struct sin_cos_angle SIN_COS_M_PI
Definition geometry.h:49
static struct sin_cos_angle sum_angles_no_check(struct sin_cos_angle a, struct sin_cos_angle b)
Definition geometry.h:524
static void crossproduct_kahan(double const a[], double const b[], double cross[])
Definition geometry.h:332
static const struct sin_cos_angle SIN_COS_M_PI_2
Definition geometry.h:48
static int compare_angles(struct sin_cos_angle a, struct sin_cos_angle b)
Definition geometry.h:428
#define yac_angle_tol
Definition geometry.h:34
static void normalise_vector(double v[])
Definition geometry.h:689
static double get_vector_angle(double const a[3], double const b[3])
Definition geometry.h:364
static struct sin_cos_angle sin_cos_angle_new(double sin, double cos)
Definition geometry.h:405
void yac_search_interval_tree(struct interval_node tree[], size_t num_nodes, struct interval query, struct overlaps *overlaps)
void yac_generate_interval_tree(struct interval_node intervals[], size_t num_nodes)
#define xrealloc(ptr, size)
Definition ppm_xfuncs.h:67
#define xmalloc(size)
Definition ppm_xfuncs.h:66
static int leaf_contains_matching_point(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)
static size_t 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)
static void 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[])
static int compare_point_idx_xyz(void const *a, void const *b)
void yac_point_sphere_part_search_NNN_ubound(struct point_sphere_part_search *search, size_t num_points, yac_coordinate_pointer coordinates_xyz, size_t n, struct sin_cos_angle *angles)
static size_t swap_node_type(struct temp_partition_data *part_data, size_t i, int node_type, size_t begin, size_t end)
static void 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)
static struct point_id_xyz * get_unique_points(size_t *num_points, yac_const_coordinate_pointer coordinates_xyz, yac_int const *ids, int const *mask)
void 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)
static void compute_gc_norm_vector(void *coords_data, size_t coords_size, size_t coords_count, double prev_gc_norm_vector[], double gc_norm_vector[])
static void 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)
void yac_point_sphere_part_search_NNN_bnd_circle(struct point_sphere_part_search *search, size_t num_bnd_circles, struct bounding_circle *bnd_circles, size_t n, size_t **local_point_ids, size_t *local_point_ids_array_size, size_t *num_local_point_ids)
struct bnd_sphere_part_search * yac_bnd_sphere_part_search_new(struct bounding_circle *circles, size_t num_circles)
static void 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[])
node_type
Definition sphere_part.c:66
@ I_NODE
Definition sphere_part.c:68
@ T_NODE
Definition sphere_part.c:70
@ U_NODE
Definition sphere_part.c:69
@ I_NODE_FULL
Definition sphere_part.c:67
static void 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[])
TODO change to iterative implementation and allocate overlap_cells first.
static void sort_partition_data(struct temp_partition_data *part_data, size_t I_FULL_size, size_t I_size, size_t U_size, size_t T_size)
static void 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[])
void yac_delete_point_sphere_part_search(struct point_sphere_part_search *search)
struct point_sphere_part_search * yac_point_sphere_part_search_mask_new(size_t num_points, yac_const_coordinate_pointer coordinates_xyz, yac_int const *ids, int const *mask)
void yac_bnd_sphere_part_search_delete(struct bnd_sphere_part_search *search)
static struct point_sphere_part_node * 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)
struct point_sphere_part_search * yac_point_sphere_part_search_new(size_t num_points, yac_const_coordinate_pointer coordinates_xyz, yac_int const *ids)
static struct sin_cos_angle 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)
static int compare_angles_(void const *a, void const *b)
static struct sphere_part_node * get_sphere_part_node()
static void free_sphere_part_tree(struct sphere_part_node tree)
static int compare_point_id_xyz_angle(const void *a, const void *b)
void yac_bnd_sphere_part_search_do_point_search(struct bnd_sphere_part_search *search, yac_coordinate_pointer coordinates_xyz, size_t count, size_t **cells, size_t *num_cells_per_coordinate)
static void 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[])
static void swap_partition_data(struct temp_partition_data *a, struct temp_partition_data *b)
static void init_sphere_part_node(struct sphere_part_node *node)
yac_node_flags
Definition sphere_part.c:41
@ I_IS_INTERVAL_TREE
Definition sphere_part.c:44
@ T_IS_LEAF
Definition sphere_part.c:43
@ U_IS_LEAF
Definition sphere_part.c:42
static void 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[])
void 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)
@ U_FLAG
Definition sphere_part.c:37
@ T_FLAG
Definition sphere_part.c:38
@ I_list_tree_min_size
Definition sphere_part.c:33
void 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)
static void free_point_sphere_part_tree(struct point_sphere_part_node *tree)
static int compare_points_int32_coord(const void *a, const void *b)
static void 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)
algorithm for searching cells and points on a grid
struct sphere_part_node base_node
Definition sphere_part.c:62
struct sin_cos_angle inc_angle
angle between the middle point and the boundary of the spherical cap
Definition geometry.h:61
double base_vector[3]
Definition geometry.h:59
double sq_crd
Definition geometry.h:64
struct interval range
double right
double left
size_t * overlap_iv
size_t num_overlaps
struct point_id_xyz point
Definition sphere_part.c:86
int32_t coordinate_xyz[3]
double coordinates_xyz[3]
Definition sphere_part.c:80
struct point_sphere_part_node base_node
struct point_id_xyz * points
double sin
Definition geometry.h:41
double cos
Definition geometry.h:41
double gc_norm_vector[3]
Definition sphere_part.c:58
struct sin_cos_angle I_angle
Definition sphere_part.c:56
union I_list I
Definition sphere_part.c:51
struct bounding_circle bnd_circle
Definition sphere_part.c:74
struct interval_node * head_node
Definition sphere_part.c:26
size_t * list
Definition sphere_part.c:29
struct I_list::@49 ivt
size_t num_nodes
Definition sphere_part.c:27
static struct user_input_data_points ** points
Definition yac.c:136
static size_t num_points
Definition yac.c:137
#define YAC_ASSERT(exp, msg)
Definition yac_assert.h:16
Xt_int yac_int
Definition yac_types.h:15
double const (* yac_const_coordinate_pointer)[3]
Definition yac_types.h:20
double(* yac_coordinate_pointer)[3]
Definition yac_types.h:19