YetAnotherCoupler 3.2.0_a
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 on 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
289 // set node type for current cell
290 part_data[i].node_type = I_NODE_FULL;
291 I_FULL_size++;
292
293 max_inc_angle = SIN_COS_M_PI_2;
294
295 } else {
296
297 // set node type for current cell
298 part_data[i].node_type = I_NODE;
299 I_size++;
300
301 struct sin_cos_angle inc_angle =
302 sum_angles_no_check(diff_angle_gc, curr_bnd_circle.inc_angle);
303
304 if (compare_angles(max_inc_angle, inc_angle) < 0)
305 max_inc_angle = inc_angle;
306 }
307
308 // angle > M_PI_2
309 } else if (angle.cos < 0.0) {
310
311 // set node type for current cell
312 part_data[i].node_type = U_NODE;
313 U_size++;
314
315 } else {
316
317 // set node type for current cell
318 part_data[i].node_type = T_NODE;
319 T_size++;
320 }
321 }
322
323 sort_partition_data(part_data, I_FULL_size, I_size, U_size, T_size);
324
325 I_size += I_FULL_size;
326 parent_node->I_size = I_size;
327 parent_node->U_size = U_size;
328 parent_node->T_size = T_size;
329
330 // if max_inc_angle > PI/2
331 if (compare_angles(max_inc_angle, SIN_COS_M_PI_2) >= 0) {
332 parent_node->I_angle = SIN_COS_M_PI_2;
333 } else {
334 parent_node->I_angle = max_inc_angle;
335 }
336
337 if (I_size > 0) {
338
339 if (I_size > I_list_tree_min_size) {
340
341 assert(sizeof(struct interval_node) > sizeof(size_t));
342 struct interval_node * head_node = xmalloc(I_size * sizeof(*head_node));
343 parent_node->I.ivt.head_node = head_node;
344 parent_node->I.ivt.num_nodes = I_size;
345
346 // for all bounding circles that include gc_norm_vector or
347 // -gc_norm_vector
348 for (size_t i = 0; i < I_FULL_size; ++i) {
349
350 head_node[i].range.left = -M_PI;
351 head_node[i].range.right = M_PI;
352 head_node[i].value = part_data[i].local_id;
353 }
354
355 for (size_t i = I_FULL_size; i < I_size; ++i) {
356
357 double GCp[3], bVp[3];
358 struct bounding_circle curr_bnd_circle = part_data[i].bnd_circle;
359
360 // project the base vector of the current bounding circle onto the
361 // current partitioning great circle
363 curr_bnd_circle.base_vector, GCp);
364 crossproduct_kahan(GCp, parent_node->gc_norm_vector, bVp);
366 (fabs(bVp[0]) > 1e-9) || (fabs(bVp[1]) > 1e-9) ||
367 (fabs(bVp[2]) > 1e-9),
368 "ERROR(partition_data): "
369 "projected vector is nearly identical to gc_norm_vector")
370 normalise_vector(bVp);
371
372 // the inc_angle of the bounding circle also needs to be projected
373 // onto the great circle
374 // (the formula for this is:
375 // new_inc_angle=acos(sin(inc_angle)/cos(base_angle))
376 // To find this formula, you have to determine the longitude of
377 // of longitude circle that has exactly one intersection with the
378 // bounding circle.
379 // (see https://www.dropbox.com/s/82bxzno1mjogbtf/function_2nd_try.pdf)
380 double bnd_circle_lat_cos =
381 get_vector_angle_2(bVp, curr_bnd_circle.base_vector).cos;
382 double inc_angle =
383 M_PI_2 - acos(curr_bnd_circle.inc_angle.sin/bnd_circle_lat_cos);
384
385 // By definition the previous norm vector is on the current great
386 // great circle. We use this as a reference point for I
387
388 // compute "distance" of the projected base vector to the reference
389 // point
390 double base_angle = get_vector_angle(bVp, prev_gc_norm_vector);
391
392 head_node[i].range.left = base_angle - inc_angle;
393 head_node[i].range.right = base_angle + inc_angle;
394 head_node[i].value = part_data[i].local_id;
395 }
396
397 yac_generate_interval_tree(head_node, I_size);
398 parent_node->flags |= I_IS_INTERVAL_TREE;
399 } else {
400 for (size_t i = 0; i < I_size; ++i)
401 local_cell_ids[i] = part_data[i].local_id;
402 parent_node->I.list = (void*)local_cell_ids;
403 }
404 } else
405 parent_node->I.list = NULL;
406
407 part_data += I_size;
408 local_cell_ids += I_size;
409
410 // check whether the lists are small enough (if not -> partition again)
411 if (U_size <= threshold) {
412
413 for (size_t i = 0; i < U_size; ++i)
414 local_cell_ids[i] = part_data[i].local_id;
415 parent_node->U = (void*)local_cell_ids;
416 parent_node->flags |= U_IS_LEAF;
417
418 } else {
419
420 parent_node->U = get_sphere_part_node();
421 partition_data(local_cell_ids, part_data, U_size, threshold,
422 parent_node->U, parent_node->gc_norm_vector);
423 }
424 local_cell_ids += U_size;
425 part_data += U_size;
426
427 if (T_size <= threshold) {
428
429 for (size_t i = 0; i < T_size; ++i)
430 local_cell_ids[i] = part_data[i].local_id;
431 parent_node->T = (void*)local_cell_ids;
432 parent_node->flags |= T_IS_LEAF;
433 local_cell_ids += T_size;
434
435 } else {
436
437 parent_node->T = get_sphere_part_node();
438 partition_data(local_cell_ids, part_data, T_size, threshold,
439 parent_node->T, parent_node->gc_norm_vector);
440 }
441}
442
443static int compare_point_idx_xyz(void const * a, void const * b) {
444 return (((struct point_id_xyz *)a)->idx > ((struct point_id_xyz *)b)->idx) -
445 (((struct point_id_xyz *)a)->idx < ((struct point_id_xyz *)b)->idx);
446}
447
449 struct point_id_xyz * points, size_t num_points, size_t threshold,
450 double prev_gc_norm_vector[], size_t curr_tree_depth,
451 size_t * max_tree_depth) {
452
453 if (curr_tree_depth > *max_tree_depth) *max_tree_depth = curr_tree_depth;
454
455 struct point_sphere_part_node * node = xmalloc(1 * sizeof(*node));
456 double * gc_norm_vector = &(node->gc_norm_vector[0]);
457
459 points, sizeof(*points), num_points, prev_gc_norm_vector, gc_norm_vector);
460
461 // angle between a point and the great circle plane
462 // acos(dot(gc_norm_vector, point_xyz)) = angle(gc_norm_vector, point_xyz)
463 // acos(dot(gc_norm_vector, point_xyz)) - PI/2 = angle(gc_plane, point_xyz)
464 // dot <= 0.0 -> U list
465 // dot > 0.0 -> T list
466
467 struct point_id_xyz * left = points, * right = points + num_points - 1;
468
469 // sort such that all points for the U list come first, followed by the
470 // elements of the T list
471 while (1) {
472 // find element that does not belong into U-list
473 while (left <= right) {
474 double * curr_coordinates_xyz = &(left->coordinates_xyz[0]);
475 double dot = curr_coordinates_xyz[0] * gc_norm_vector[0] +
476 curr_coordinates_xyz[1] * gc_norm_vector[1] +
477 curr_coordinates_xyz[2] * gc_norm_vector[2];
478
479 // if (angle < M_PI_2)
480 if (dot > 0.0) break;
481 ++left;
482 };
483
484 // find element that does not belong into T-list
485 while (left < right) {
486 double * curr_coordinates_xyz = &(right->coordinates_xyz[0]);
487 double dot = curr_coordinates_xyz[0] * gc_norm_vector[0] +
488 curr_coordinates_xyz[1] * gc_norm_vector[1] +
489 curr_coordinates_xyz[2] * gc_norm_vector[2];
490
491 // if (angle >= M_PI_2)
492 if (dot <= 0.0) break;
493 --right;
494 }
495
496 if (left < right) {
497 struct point_id_xyz tmp_point = *left;
498 *left = *right;
499 *right = tmp_point;
500 ++left;
501 --right;
502 } else {
503 break;
504 }
505 }
506
507 size_t U_size = left - points;
508 size_t T_size = num_points - U_size;
509
510 node->U_size = U_size;
511 node->T_size = T_size;
512 node->flags = 0;
513
514 // check whether the lists are small enough (if not -> partition again)
515 if ((U_size <= threshold) || (U_size == num_points)) {
516
517 node->U = points;
518 node->flags |= U_IS_LEAF;
519 qsort(points, U_size, sizeof(*points), compare_point_idx_xyz);
520
521 } else {
522
523 node->U = partition_point_data(points, U_size, threshold, gc_norm_vector,
524 curr_tree_depth + 1, max_tree_depth);
525 }
526
527 if ((T_size <= threshold) || (T_size == num_points)) {
528
529 node->T = points + U_size;
530 node->flags |= T_IS_LEAF;
531 qsort(points + U_size, T_size, sizeof(*points), compare_point_idx_xyz);
532
533 } else {
534
535 node->T =
536 partition_point_data(points + U_size, T_size, threshold, gc_norm_vector,
537 curr_tree_depth + 1, max_tree_depth);
538 }
539
540 return node;
541}
542
544 struct bounding_circle * circles, size_t num_circles) {
545
546 struct bnd_sphere_part_search * search = xmalloc(1 * sizeof(*search));
547
548 double gc_norm_vector[3] = {0.0,0.0,1.0};
549
551
552 size_t * ids = xmalloc(num_circles * sizeof(*ids));
553 search->ids = ids;
554
555 struct temp_partition_data * part_data =
556 xmalloc(num_circles * sizeof(*part_data));
557 for (size_t i = 0; i < num_circles; ++i) {
558 part_data[i].bnd_circle = circles[i];
559 part_data[i].local_id = i;
560 }
561
562 partition_data(ids, part_data, num_circles, I_list_tree_min_size,
563 &(search->base_node), gc_norm_vector);
564
565 free(part_data);
566
567 return search;
568}
569
571 const void * a,const void * b) {
572
573 struct point_id_xyz_int32 * point_a = (struct point_id_xyz_int32 *)a;
574 struct point_id_xyz_int32 * point_b = (struct point_id_xyz_int32 *)b;
575
576 int ret;
577
578 for (int i = 0; i < 3; ++i)
579 if ((ret = (point_a->coordinate_xyz[i] > point_b->coordinate_xyz[i]) -
580 (point_a->coordinate_xyz[i] < point_b->coordinate_xyz[i])))
581 return ret;
582 return 0;
583}
584
585static struct point_id_xyz *
588 yac_int const * ids, int const * mask) {
589
590 struct point_id_xyz_int32 * points_int32 =
591 xmalloc(*num_points * sizeof(*points_int32));
592
593 double const scale = (double)(2 << 21);
594
595 size_t num_unmasked_points;
596
597 if (mask == NULL) {
598 num_unmasked_points = *num_points;
599 for (size_t i = 0; i < num_unmasked_points; ++i) {
600
601 points_int32[i].idx = i;
602 for (size_t j = 0; j < 3; ++j)
603 points_int32[i].coordinate_xyz[j] =
604 (int32_t)round(coordinates_xyz[i][j] * scale);
605 }
606 } else {
607 num_unmasked_points = 0;
608 for (size_t i = 0; i < *num_points; ++i) {
609
610 if (!mask[i]) continue;
611 points_int32[num_unmasked_points].idx = i;
612 for (size_t j = 0; j < 3; ++j)
613 points_int32[num_unmasked_points].coordinate_xyz[j] =
614 (int32_t)round(coordinates_xyz[i][j] * scale);
615 num_unmasked_points++;
616 }
617 }
618
619 // sort points
620 qsort(points_int32, num_unmasked_points,
621 sizeof(*points_int32), compare_points_int32_coord);
622
623 struct point_id_xyz_int32 dummy;
624 dummy.idx = SIZE_MAX;
625 dummy.coordinate_xyz[0] = INT32_MAX;
626 dummy.coordinate_xyz[1] = INT32_MAX;
627 dummy.coordinate_xyz[2] = INT32_MAX;
628 struct point_id_xyz_int32 * prev = &dummy, * curr = points_int32;
629 yac_int prev_id = XT_INT_MAX;
630 size_t new_num_points = 0;
631 for (size_t i = 0; i < num_unmasked_points; ++i, ++curr) {
632
633 size_t curr_idx = curr->idx;
634 if (compare_points_int32_coord(prev, curr)) {
635 prev = points_int32 + new_num_points++;
636 if (prev != curr) *prev = *curr;
637 prev_id = ids[curr_idx];
638 } else {
639 yac_int curr_id = ids[curr_idx];
640 if (curr_id > prev_id) {
641 prev_id = curr_id;
642 prev->idx = curr_idx;
643 }
644 }
645 }
646
647 struct point_id_xyz * points = xmalloc(new_num_points * sizeof(*points));
648 for (size_t i = 0; i < new_num_points; ++i) {
649 size_t curr_idx = points_int32[i].idx;
650 points[i].idx = curr_idx;
651 memcpy(
652 points[i].coordinates_xyz, coordinates_xyz[curr_idx], 3 * sizeof(double));
653 }
654 *num_points = new_num_points;
655 free(points_int32);
656 return points;
657}
658
660 size_t num_points, yac_const_coordinate_pointer coordinates_xyz,
661 yac_int const * ids) {
662
663 if (num_points == 0) return NULL;
664
665 struct point_sphere_part_search * search = xmalloc(1 * sizeof(*search));
666 struct point_id_xyz * points =
668 search->points = points;
669
670 size_t max_tree_depth = 0;
671
672 // emperical measurements have given a threshold for the leaf size of 2
673 struct point_sphere_part_node * tmp_node =
675 points, num_points, I_list_tree_min_size, (double[3]){0.0,0.0,1.0},
676 1, &max_tree_depth);
677
678 search->base_node = *tmp_node;
679 search->max_tree_depth = max_tree_depth;
680 free(tmp_node);
681
682 return search;
683}
684
686 size_t num_points, yac_const_coordinate_pointer coordinates_xyz,
687 yac_int const * ids, int const * mask) {
688
689 if (num_points == 0) return NULL;
690
691 struct point_id_xyz * points =
693
694 struct point_sphere_part_search * search = xmalloc(1 * sizeof(*search));
695 search->points = xrealloc(points, num_points * sizeof(*points));
696
697 size_t max_tree_depth = 0;
698
699 // emperical measurements have given a threshold for the leaf size of 2
700 struct point_sphere_part_node * tmp_node =
703 (double[3]){0.0,0.0,1.0}, 1, &max_tree_depth);
704
705 search->base_node = *tmp_node;
706 search->max_tree_depth = max_tree_depth;
707 free(tmp_node);
708
709 return search;
710}
711
713 struct sphere_part_node * node, struct bounding_circle bnd_circle,
714 size_t ** restrict overlap_cells, size_t * overlap_cells_array_size,
715 size_t * restrict num_overlap_cells,
716 struct overlaps * search_interval_tree_buffer, double prev_gc_norm_vector[]) {
717
718 if (node->flags & I_IS_INTERVAL_TREE) {
719
720 struct sin_cos_angle angle =
722 bnd_circle.base_vector, node->gc_norm_vector);
723 angle.cos = fabs(angle.cos);
724
725 // if gc_norm_vector or -gc_norm_vector is in the bounding circle
726 if (compare_angles(angle, bnd_circle.inc_angle) <= 0) {
727 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
728 *num_overlap_cells + node->I.ivt.num_nodes);
729 for (size_t i = 0; i < node->I.ivt.num_nodes; ++i)
730 (*overlap_cells)[(*num_overlap_cells)+i] =
731 node->I.ivt.head_node[i].value;
732 *num_overlap_cells += node->I.ivt.num_nodes;
733 return;
734 }
735
736 double GCp[3], bVp[3];
737
738 // project the base vector of the current bounding circle onto the
739 // current great circle
740 crossproduct_kahan(node->gc_norm_vector, bnd_circle.base_vector, GCp);
741 crossproduct_kahan(GCp, node->gc_norm_vector, bVp);
743 (fabs(bVp[0]) > 1e-9) || (fabs(bVp[1]) > 1e-9) || (fabs(bVp[2]) > 1e-9),
744 "ERROR(search_bnd_circle_I_node): "
745 "projected vector is nearly identical to gc_norm_vector")
746 normalise_vector(bVp);
747
748 // the inc_angle of the bounding circle also needs to be projected
749 // onto the great circle (see routine partition data for a detailed
750 // explanation)
751 double bnd_circle_lat_cos =
752 get_vector_angle_2(bVp, bnd_circle.base_vector).cos;
753 double inc_angle =
754 M_PI_2 - acos(bnd_circle.inc_angle.sin/bnd_circle_lat_cos);
755
756 // compute "distance" of the projected base vector to the reference point
757 double base_angle = get_vector_angle(bVp, prev_gc_norm_vector);
758
759 search_interval_tree_buffer->num_overlaps = 0;
760
762 node->I.ivt.head_node, node->I.ivt.num_nodes,
763 (struct interval){
764 .left = base_angle - inc_angle,
765 .right = base_angle + inc_angle},
766 search_interval_tree_buffer);
767
768 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
769 *num_overlap_cells +
770 search_interval_tree_buffer->num_overlaps);
771
772 for (size_t i = 0; i < search_interval_tree_buffer->num_overlaps; ++i)
773 (*overlap_cells)[(*num_overlap_cells)+i] =
774 node->I.ivt.head_node[
775 search_interval_tree_buffer->overlap_iv[i]].value;
776
777 *num_overlap_cells += search_interval_tree_buffer->num_overlaps;
778
779 } else {
780
781 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
782 *num_overlap_cells + node->I_size);
783 memcpy(*overlap_cells + *num_overlap_cells, node->I.list,
784 node->I_size * sizeof(**overlap_cells));
785 *num_overlap_cells += node->I_size;
786 }
787}
788
791 struct sphere_part_node * node, struct bounding_circle bnd_circle,
792 size_t ** restrict overlap_cells, size_t * overlap_cells_array_size,
793 size_t * restrict num_overlap_cells,
794 struct overlaps * search_interval_tree_buffer, double prev_gc_norm_vector[]) {
795
796 if (node->flags & T_IS_LEAF) {
797
798 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
799 *num_overlap_cells + node->T_size);
800 memcpy(*overlap_cells + *num_overlap_cells, node->T,
801 node->T_size * sizeof(**overlap_cells));
802 *num_overlap_cells += node->T_size;
803
804 } else {
806 node->T, bnd_circle, overlap_cells, overlap_cells_array_size,
807 num_overlap_cells, search_interval_tree_buffer, node->gc_norm_vector);
808 }
809
810 if (node->flags & U_IS_LEAF) {
811
812 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
813 *num_overlap_cells + node->U_size);
814 memcpy(*overlap_cells + *num_overlap_cells, node->U,
815 node->U_size * sizeof(**overlap_cells));
816 *num_overlap_cells += node->U_size;
817
818 } else {
820 node->U, bnd_circle, overlap_cells, overlap_cells_array_size,
821 num_overlap_cells, search_interval_tree_buffer, node->gc_norm_vector);
822 }
823
825 node, bnd_circle, overlap_cells, overlap_cells_array_size,
826 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
827}
828
830 struct sphere_part_node * node, struct bounding_circle bnd_circle,
831 size_t ** restrict overlap_cells, size_t * overlap_cells_array_size,
832 size_t * restrict num_overlap_cells,
833 struct overlaps * search_interval_tree_buffer, double prev_gc_norm_vector[]) {
834
835 double dot = bnd_circle.base_vector[0] * node->gc_norm_vector[0] +
836 bnd_circle.base_vector[1] * node->gc_norm_vector[1] +
837 bnd_circle.base_vector[2] * node->gc_norm_vector[2];
838
839 // angle < M_PI_2 + bnd_circle.inc_angle
840 if (dot > - bnd_circle.inc_angle.sin) {
841
842 if (node->flags & T_IS_LEAF) {
843
844 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
845 *num_overlap_cells + node->T_size);
846 memcpy(*overlap_cells + *num_overlap_cells, node->T,
847 node->T_size * sizeof(**overlap_cells));
848 *num_overlap_cells += node->T_size;
849
850 } else {
852 node->T, bnd_circle, overlap_cells, overlap_cells_array_size,
853 num_overlap_cells, search_interval_tree_buffer,
854 node->gc_norm_vector);
855 }
856 }
857
858 // angle > M_PI_2 - bnd_circle.inc_angle
859 if (dot < bnd_circle.inc_angle.sin) {
860
861 if (node->flags & U_IS_LEAF) {
862
863 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
864 *num_overlap_cells + node->U_size);
865 memcpy(*overlap_cells + *num_overlap_cells, node->U,
866 node->U_size * sizeof(**overlap_cells));
867 *num_overlap_cells += node->U_size;
868
869 } else {
871 node->U, bnd_circle, overlap_cells, overlap_cells_array_size,
872 num_overlap_cells, search_interval_tree_buffer,
873 node->gc_norm_vector);
874 }
875 }
876
877 struct sin_cos_angle angle_sum =
878 sum_angles_no_check(node->I_angle, bnd_circle.inc_angle);
879
880 // if (I_angle + inc_angle > PI/2) ||
881 // (fabs(angle - M_PI_2) <= (I_angle + inc_angle))
882 //
883 // assumtion:
884 // I_angle >= 0 && I_angle <= PI/2
885 // inc_angle >= 0 && inc_angle <= PI/2
886 // angle >= 0 && angle <= PI
887 //
888 // => I_angle + inc_angle >= 0 && I_angle + inc_angle <= PI
889 //
890 // I_angle + inc_angle >= PI/2
891 //
892 // fabs(angle - M_PI_2) <= (I_angle + inc_angle)
893 // => sin(fabs(angle - M_PI_2)) <= sin(I_angle + inc_angle)
894 // this is wrong for (I_angle + inc_angle) > PI/2, however that case is
895 // already covered by the first condition
896 // => fabs(cos(angle)) <= sin(I_angle + inc_angle)
897 if (((angle_sum.sin < 0.0) || (angle_sum.cos <= 0.0)) ||
898 (fabs(dot) <= angle_sum.sin)) {
900 node, bnd_circle, overlap_cells, overlap_cells_array_size,
901 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
902 }
903}
904
905static void search_bnd_circle(struct sphere_part_node * node,
906 struct bounding_circle bnd_circle,
907 size_t ** restrict overlap_cells,
908 size_t * overlap_cells_array_size,
909 size_t * restrict num_overlap_cells,
910 struct overlaps * search_interval_tree_buffer,
911 double prev_gc_norm_vector[]) {
912
913 // if the bounding circle has an angle in the range of [0;PI/2[
914 if (bnd_circle.inc_angle.cos > 0.0)
916 node, bnd_circle, overlap_cells, overlap_cells_array_size,
917 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
918 else
920 node, bnd_circle, overlap_cells, overlap_cells_array_size,
921 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
922}
923
924static inline void check_leaf_NN(
925 struct point_id_xyz * points, size_t num_points,
926 double * point_coordinates_xyz, struct sin_cos_angle * best_angle,
927 double (**result_coordinates_xyz)[3],
928 size_t * result_coordinates_xyz_array_size, size_t ** local_point_ids,
929 size_t * local_point_ids_array_size, size_t total_num_local_point_ids,
930 size_t * num_local_point_ids) {
931
932 size_t * local_point_ids_ = *local_point_ids;
933 size_t local_point_ids_array_size_ = *local_point_ids_array_size;
934 double (*result_coordinates_xyz_)[3];
935 size_t result_coordinates_xyz_array_size_;
936 size_t num_local_point_ids_ = *num_local_point_ids;
937
938 if (result_coordinates_xyz != NULL) {
939 result_coordinates_xyz_ = *result_coordinates_xyz;
940 result_coordinates_xyz_array_size_ = *result_coordinates_xyz_array_size;
942 result_coordinates_xyz_, result_coordinates_xyz_array_size_,
943 total_num_local_point_ids + num_local_point_ids_ + num_points);
944 *result_coordinates_xyz = result_coordinates_xyz_;
945 *result_coordinates_xyz_array_size = result_coordinates_xyz_array_size_;
946 result_coordinates_xyz_ += total_num_local_point_ids;
947 }
949 local_point_ids_, local_point_ids_array_size_,
950 total_num_local_point_ids + num_local_point_ids_ + num_points);
951 *local_point_ids = local_point_ids_;
952 *local_point_ids_array_size = local_point_ids_array_size_;
953 local_point_ids_ += total_num_local_point_ids;
954
955
956 // check leaf for results
957 for (size_t i = 0; i < num_points; ++i) {
958
959 struct sin_cos_angle curr_angle =
961 points[i].coordinates_xyz, point_coordinates_xyz);
962 int compare = compare_angles(curr_angle, *best_angle);
963
964 // if the point is worse than the currently best point
965 if (compare > 0) continue;
966
967 // if we found a better point
968 if (compare < 0) {
969
970 *best_angle = curr_angle;
971 num_local_point_ids_ = 1;
972 if (result_coordinates_xyz != NULL) {
973 result_coordinates_xyz_[0][0] = points[i].coordinates_xyz[0];
974 result_coordinates_xyz_[0][1] = points[i].coordinates_xyz[1];
975 result_coordinates_xyz_[0][2] = points[i].coordinates_xyz[2];
976 }
977 local_point_ids_[0] = points[i].idx;
978
979 } else {
980
981 if (result_coordinates_xyz != NULL) {
982 result_coordinates_xyz_[num_local_point_ids_][0] =
983 points[i].coordinates_xyz[0];
984 result_coordinates_xyz_[num_local_point_ids_][1] =
985 points[i].coordinates_xyz[1];
986 result_coordinates_xyz_[num_local_point_ids_][2] =
987 points[i].coordinates_xyz[2];
988 }
989 local_point_ids_[num_local_point_ids_] = points[i].idx;
990 num_local_point_ids_++;
991 }
992 }
993
994 *num_local_point_ids = num_local_point_ids_;
995}
996
997static void point_search_NN(
998 struct bounding_circle * bnd_circle, double (**result_coordinates_xyz)[3],
999 size_t * result_coordinates_xyz_array_size, size_t ** local_point_ids,
1000 size_t * local_point_ids_array_size, size_t total_num_local_point_ids,
1001 size_t * num_local_point_ids, double * dot_stack,
1002 struct point_sphere_part_node ** node_stack,
1003 int * flags, size_t curr_tree_depth) {
1004
1005 double * point_coordinates_xyz = bnd_circle->base_vector;
1006 struct sin_cos_angle best_angle = bnd_circle->inc_angle;
1007
1008 double dot = dot_stack[curr_tree_depth];
1009 struct point_sphere_part_node * node = node_stack[curr_tree_depth];
1010 int skip_U = flags[curr_tree_depth] & U_FLAG;
1011 int skip_T = flags[curr_tree_depth] & T_FLAG;
1012
1013 do {
1014
1015 if (!skip_U) {
1016
1017 flags[curr_tree_depth] |= U_FLAG;
1018
1019 // angle + inc_angle >= M_PI_2
1020 if ((dot < best_angle.sin) | (best_angle.cos <= 0.0)) {
1021
1022 if (node->flags & U_IS_LEAF) {
1023
1025 (struct point_id_xyz *)(node->U), node->U_size,
1026 point_coordinates_xyz, &best_angle, result_coordinates_xyz,
1027 result_coordinates_xyz_array_size, local_point_ids,
1028 local_point_ids_array_size, total_num_local_point_ids,
1029 num_local_point_ids);
1030
1031 } else {
1032
1033 // traverse down one level
1034 ++curr_tree_depth;
1035 node = (struct point_sphere_part_node *)(node->U);
1036 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1037 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1038 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1039 dot_stack[curr_tree_depth] = dot;
1040 node_stack[curr_tree_depth] = node;
1041 flags[curr_tree_depth] = 0;
1042 // skip_U = 0;
1043 skip_T = 0;
1044 continue;
1045 }
1046 }
1047 }
1048
1049 if (!skip_T) {
1050
1051 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1052
1053 // angle - inc_angle < M_PI_2
1054 if ((dot > - best_angle.sin) || (best_angle.cos <= 0.0)) {
1055
1056 if (node->flags & T_IS_LEAF) {
1057
1059 (struct point_id_xyz *)(node->T), node->T_size,
1060 point_coordinates_xyz, &best_angle, result_coordinates_xyz,
1061 result_coordinates_xyz_array_size, local_point_ids,
1062 local_point_ids_array_size, total_num_local_point_ids,
1063 num_local_point_ids);
1064
1065 } else {
1066
1067 // traverse down one level
1068 ++curr_tree_depth;
1069 node = (struct point_sphere_part_node *)(node->T);
1070 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1071 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1072 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1073 dot_stack[curr_tree_depth] = dot;
1074 node_stack[curr_tree_depth] = node;
1075 flags[curr_tree_depth] = 0;
1076 skip_U = 0;
1077 // skip_T = 0;
1078 continue;
1079 }
1080 }
1081 }
1082
1083 if (curr_tree_depth == 0) break;
1084
1085 // go up one level in the tree
1086
1087 curr_tree_depth--;
1088 dot = dot_stack[curr_tree_depth];
1089 node = node_stack[curr_tree_depth];
1090 skip_U = flags[curr_tree_depth] & U_FLAG;
1091 skip_T = flags[curr_tree_depth] & T_FLAG;
1092
1093 } while (1);
1094
1095 bnd_circle->inc_angle = best_angle;
1096}
1097
1099 struct point_sphere_part_node * node, struct bounding_circle bnd_circle) {
1100
1101 double dot = node->gc_norm_vector[0]*bnd_circle.base_vector[0] +
1102 node->gc_norm_vector[1]*bnd_circle.base_vector[1] +
1103 node->gc_norm_vector[2]*bnd_circle.base_vector[2];
1104
1105 int ret = 0;
1106
1107 // angle + inc_angle >= M_PI_2
1108 if (dot <= bnd_circle.inc_angle.sin) {
1109
1110 if (node->flags & U_IS_LEAF) {
1111
1112 struct point_id_xyz * U = (struct point_id_xyz *)(node->U);
1113 size_t U_size = node->U_size;
1114 for (size_t i = 0; i < U_size; ++i) {
1115 double cos_angle =
1116 U[i].coordinates_xyz[0] * bnd_circle.base_vector[0] +
1117 U[i].coordinates_xyz[1] * bnd_circle.base_vector[1] +
1118 U[i].coordinates_xyz[2] * bnd_circle.base_vector[2];
1119 if (cos_angle > bnd_circle.inc_angle.cos) return 1;
1120 }
1121
1122 } else {
1123 ret = point_check_bnd_circle(node->U, bnd_circle);
1124 }
1125 }
1126
1127 // angle - inc_angle < M_PI_2
1128 if ((!ret) && (dot > - bnd_circle.inc_angle.sin)) {
1129
1130 if (node->flags & T_IS_LEAF) {
1131
1132 struct point_id_xyz * T = (struct point_id_xyz *)(node->T);
1133 size_t T_size = node->T_size;
1134 for (size_t i = 0; i < T_size; ++i) {
1135 double cos_angle =
1136 T[i].coordinates_xyz[0] * bnd_circle.base_vector[0] +
1137 T[i].coordinates_xyz[1] * bnd_circle.base_vector[1] +
1138 T[i].coordinates_xyz[2] * bnd_circle.base_vector[2];
1139 if (cos_angle > bnd_circle.inc_angle.cos) return 1;
1140 }
1141
1142 } else {
1143 ret = point_check_bnd_circle(node->T, bnd_circle);
1144 }
1145 }
1146
1147 return ret;
1148}
1149
1151 struct point_id_xyz * points, size_t num_points, double coordinate_xyz[3],
1152 size_t ** local_point_ids, size_t * local_point_ids_array_size,
1153 double (**result_coordinates_xyz)[3],
1154 size_t * result_coordinates_xyz_array_size,
1155 size_t total_num_local_point_ids, size_t * num_local_point_ids) {
1156
1157 for (size_t i = 0; i < num_points; ++i) {
1158
1159 // if the points are nearly identical
1160 if (points_are_identically(points[i].coordinates_xyz, coordinate_xyz)) {
1161
1162 ENSURE_ARRAY_SIZE(*local_point_ids, *local_point_ids_array_size,
1163 total_num_local_point_ids + 1);
1164 (*local_point_ids)[total_num_local_point_ids] = points[i].idx;
1165 if (result_coordinates_xyz != NULL) {
1166 ENSURE_ARRAY_SIZE(*result_coordinates_xyz,
1167 *result_coordinates_xyz_array_size,
1168 total_num_local_point_ids + 1);
1169 memcpy((*result_coordinates_xyz) + total_num_local_point_ids,
1170 points[i].coordinates_xyz, 3 * sizeof(double));
1171 }
1172 *num_local_point_ids = 1;
1173 return 1;
1174 }
1175 }
1176
1177 return 0;
1178}
1179
1181 size_t num_points,
1182 double (*coordinates_xyz)[3],
1183 double * cos_angles,
1184 double (**result_coordinates_xyz)[3],
1185 size_t * result_coordinates_xyz_array_size,
1186 size_t ** local_point_ids,
1187 size_t * local_point_ids_array_size,
1188 size_t * num_local_point_ids) {
1189
1190 memset(num_local_point_ids, 0, num_points * sizeof(*num_local_point_ids));
1191
1192 if (search == NULL) return;
1193
1194 struct point_sphere_part_node * base_node = &(search->base_node);
1195
1196 size_t total_num_local_point_ids = 0;
1197
1198 double * dot_stack = xmalloc(search->max_tree_depth * sizeof(*dot_stack));
1199 struct point_sphere_part_node ** node_stack =
1200 xmalloc(search->max_tree_depth * sizeof(*node_stack));
1201 int * flags = xmalloc(search->max_tree_depth * sizeof(*flags));
1202
1203 for (size_t i = 0; i < num_points; ++i) {
1204
1205 struct point_sphere_part_node * curr_node = base_node;
1206
1207 double * curr_coordinates_xyz = coordinates_xyz[i];
1208
1209 size_t curr_tree_depth = 0;
1210 struct point_id_xyz * points = NULL;
1211 size_t curr_num_points = 0;
1212
1213 // get the matching leaf for the current point
1214 do {
1215
1216 double dot = curr_node->gc_norm_vector[0]*curr_coordinates_xyz[0] +
1217 curr_node->gc_norm_vector[1]*curr_coordinates_xyz[1] +
1218 curr_node->gc_norm_vector[2]*curr_coordinates_xyz[2];
1219
1220 dot_stack[curr_tree_depth] = dot;
1221 node_stack[curr_tree_depth] = curr_node;
1222 flags[curr_tree_depth] = 0;
1223
1224 // angle > M_PI_2
1225 if (dot < yac_angle_tol) {
1226
1227 flags[curr_tree_depth] = U_FLAG;
1228
1229 if (curr_node->flags & U_IS_LEAF) {
1230 if (curr_node->U_size > 0) {
1231 points = (struct point_id_xyz*)(curr_node->U);
1232 curr_num_points = curr_node->U_size;
1233 break;
1234 } else {
1235 flags[curr_tree_depth] = T_FLAG;
1236 YAC_ASSERT(
1237 curr_node->flags & T_IS_LEAF,
1238 "ERROR(yac_point_sphere_part_search_NN): "
1239 "if one branch is empty, the other has to be a leaf");
1240 points = (struct point_id_xyz*)(curr_node->T);
1241 curr_num_points = curr_node->T_size;
1242 break;
1243 }
1244 } else curr_node = curr_node->U;
1245
1246 // angle < M_PI_2
1247 } else if (dot > -yac_angle_tol) {
1248
1249 flags[curr_tree_depth] = T_FLAG;
1250
1251 if (curr_node->flags & T_IS_LEAF) {
1252 if (curr_node->T_size > 0) {
1253 points = (struct point_id_xyz*)(curr_node->T);
1254 curr_num_points = curr_node->T_size;
1255 break;
1256 } else {
1257 flags[curr_tree_depth] = U_FLAG;
1258 YAC_ASSERT(
1259 curr_node->flags & U_IS_LEAF,
1260 "ERROR(yac_point_sphere_part_search_NN): "
1261 "if one branch is empty, the other has to be a leaf");
1262 points = (struct point_id_xyz*)(curr_node->U);
1263 curr_num_points = curr_node->U_size;
1264 break;
1265 }
1266 } else curr_node = curr_node->T;
1267 }
1268
1269 curr_tree_depth++;
1270 } while (1);
1271
1272 // if we do not have to do a finer search
1274 points, curr_num_points, curr_coordinates_xyz, local_point_ids,
1275 local_point_ids_array_size, result_coordinates_xyz,
1276 result_coordinates_xyz_array_size, total_num_local_point_ids,
1277 num_local_point_ids + i)) {
1278
1279 if (cos_angles != NULL) cos_angles[i] = 1.0;
1280
1281 } else {
1282
1283 struct bounding_circle bnd_circle;
1284 bnd_circle.base_vector[0] = curr_coordinates_xyz[0];
1285 bnd_circle.base_vector[1] = curr_coordinates_xyz[1];
1286 bnd_circle.base_vector[2] = curr_coordinates_xyz[2];
1287 bnd_circle.inc_angle = SIN_COS_M_PI;
1288 bnd_circle.sq_crd = DBL_MAX;
1289
1291 points, curr_num_points, curr_coordinates_xyz, &bnd_circle.inc_angle,
1292 result_coordinates_xyz, result_coordinates_xyz_array_size,
1293 local_point_ids, local_point_ids_array_size, total_num_local_point_ids,
1294 num_local_point_ids + i);
1295
1296 // get best result points
1298 &bnd_circle, result_coordinates_xyz, result_coordinates_xyz_array_size,
1299 local_point_ids, local_point_ids_array_size, total_num_local_point_ids,
1300 num_local_point_ids + i, dot_stack, node_stack, flags, curr_tree_depth);
1301
1302 if (cos_angles != NULL) cos_angles[i] = bnd_circle.inc_angle.cos;
1303 }
1304
1305 total_num_local_point_ids += num_local_point_ids[i];
1306 }
1307
1308 free(flags);
1309 free(node_stack);
1310 free(dot_stack);
1311}
1312
1313static inline int compare_point_id_xyz_angle(const void * a, const void * b) {
1314
1315 const struct point_id_xyz_angle * p_a = (const struct point_id_xyz_angle *)a;
1316 const struct point_id_xyz_angle * p_b = (const struct point_id_xyz_angle *)b;
1317
1318 int ret = (p_a->cos_angle < p_b->cos_angle) -
1319 (p_a->cos_angle > p_b->cos_angle);
1320
1321 if (ret != 0) return ret;
1322
1323 return (p_a->point.idx > p_b->point.idx) - (p_a->point.idx < p_b->point.idx);
1324}
1325
1327 size_t n, struct point_id_xyz * points, size_t num_points,
1328 double * point_coordinates_xyz, struct point_id_xyz_angle ** results,
1329 size_t * results_array_size) {
1330
1331 assert(num_points > 0);
1332
1333 ENSURE_ARRAY_SIZE(*results, *results_array_size, num_points);
1334 struct point_id_xyz_angle * results_ = *results;
1335
1336#ifdef __NEC__
1337// vectorization of the following loop leads to failues of
1338//
1339// test_couple_config_parallel1
1340// test_interp_method_nnn_parallel
1341// test_interp_method_hcsbb_parallel
1342//
1343// with NEC compiler when CFLAGS='-O2'
1344#pragma _NEC novector
1345#endif
1346 for (size_t i = 0; i < num_points; ++i) {
1347
1348 results_[i].point = points[i];
1349 results_[i].cos_angle = clamp_abs_one(
1350 points[i].coordinates_xyz[0] * point_coordinates_xyz[0] +
1351 points[i].coordinates_xyz[1] * point_coordinates_xyz[1] +
1352 points[i].coordinates_xyz[2] * point_coordinates_xyz[2]);
1353 }
1354
1355 qsort(results_, num_points, sizeof(*results_), compare_point_id_xyz_angle);
1356
1357 if (num_points <= n) return num_points;
1358
1359 size_t num_results;
1360 double min_cos_angle = results_[n - 1].cos_angle;
1361
1362 for (num_results = n;
1363 (num_results < num_points) &&
1364 !(fabs(min_cos_angle - results_[num_results].cos_angle) > 0.0);
1365 ++num_results);
1366
1367 return num_results;
1368}
1369
1370static inline struct sin_cos_angle check_leaf_NNN(
1371 size_t n, double * point_coordinates_xyz,
1372 struct point_id_xyz * points, size_t num_points,
1373 struct point_id_xyz_angle ** results, size_t * results_array_size,
1374 size_t * num_results, struct sin_cos_angle curr_angle) {
1375
1376 size_t num_results_ = *num_results;
1377 ENSURE_ARRAY_SIZE(*results, *results_array_size, num_results_ + num_points);
1378 struct point_id_xyz_angle * results_ = *results;
1379
1380 int flag = 0;
1381
1382 double min_cos_angle = results_[num_results_-1].cos_angle;
1383
1384 // check leaf for results
1385 for (size_t i = 0; i < num_points; ++i) {
1386
1387 double curr_cos_angle =
1388 points[i].coordinates_xyz[0] * point_coordinates_xyz[0] +
1389 points[i].coordinates_xyz[1] * point_coordinates_xyz[1] +
1390 points[i].coordinates_xyz[2] * point_coordinates_xyz[2];
1391
1392 // if the point is worse than the currently best point
1393 if (curr_cos_angle < min_cos_angle) continue;
1394
1395 struct point_id_xyz_angle point =
1396 {.point = points[i], .cos_angle = curr_cos_angle};
1397
1398 // insert point
1399 size_t j;
1400 for (j = 0; j < num_results_; ++j) {
1401
1403 &point, results_ + num_results_ - j - 1) < 0) {
1404 results_[num_results_ - j] = results_[num_results_ - j - 1];
1405 } else {
1406 break;
1407 }
1408 }
1409 results_[num_results_ - j] = point;
1410
1411 ++num_results_;
1412 flag = 1;
1413 }
1414
1415 if (flag) {
1416
1417 if (num_results_ > n) {
1418
1419 size_t new_num_results;
1420 min_cos_angle = results_[n - 1].cos_angle;
1421
1422 for (new_num_results = n;
1423 (new_num_results < num_results_) &&
1424 !(fabs(min_cos_angle - results_[new_num_results].cos_angle) > 0.0);
1425 ++new_num_results);
1426 num_results_ = new_num_results;
1427 }
1428 *num_results = num_results_;
1429
1430 return
1432 results_[num_results_-1].point.coordinates_xyz, point_coordinates_xyz);
1433 } else return curr_angle;
1434}
1435
1437 size_t n, double * point_coordinates_xyz,
1438 struct point_id_xyz_angle ** results, size_t * results_array_size,
1439 size_t * num_results, double * dot_stack,
1440 struct point_sphere_part_node ** node_stack, int * flags,
1441 size_t curr_tree_depth) {
1442
1443 struct sin_cos_angle angle =
1445 (*results)[(*num_results)-1].point.coordinates_xyz,
1446 point_coordinates_xyz);
1447
1448 // if we have already found at least n exactly matching points
1449 if ((*num_results >= n) && (angle.sin <= yac_angle_tol)) return;
1450
1451 double dot = dot_stack[curr_tree_depth];
1452 struct point_sphere_part_node * node = node_stack[curr_tree_depth];
1453 int skip_U = flags[curr_tree_depth] & U_FLAG;
1454 int skip_T = flags[curr_tree_depth] & T_FLAG;
1455
1456 do {
1457
1458 if (!skip_U) {
1459
1460 flags[curr_tree_depth] |= U_FLAG;
1461
1462 // angle + inc_angle >= M_PI_2
1463 if ((dot < angle.sin) | (angle.cos <= 0.0)) {
1464
1465 if (node->flags & U_IS_LEAF) {
1466
1467 angle = check_leaf_NNN(
1468 n, point_coordinates_xyz, (struct point_id_xyz *)(node->U),
1469 node->U_size, results, results_array_size, num_results, angle);
1470
1471 } else {
1472
1473 // traverse down one level
1474 ++curr_tree_depth;
1475 node = (struct point_sphere_part_node *)(node->U);
1476 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1477 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1478 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1479 dot_stack[curr_tree_depth] = dot;
1480 node_stack[curr_tree_depth] = node;
1481 flags[curr_tree_depth] = 0;
1482 // skip_U = 0;
1483 skip_T = 0;
1484 continue;
1485 }
1486 }
1487 }
1488
1489 if (!skip_T) {
1490
1491 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1492
1493 // angle - inc_angle < M_PI_2
1494 if ((dot > - angle.sin) || (angle.cos <= 0.0)) {
1495
1496 if (node->flags & T_IS_LEAF) {
1497
1498 angle = check_leaf_NNN(
1499 n, point_coordinates_xyz, (struct point_id_xyz *)(node->T),
1500 node->T_size, results, results_array_size, num_results, angle);
1501
1502 } else {
1503
1504 // traverse down one level
1505 ++curr_tree_depth;
1506 node = (struct point_sphere_part_node *)(node->T);
1507 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1508 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1509 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1510 dot_stack[curr_tree_depth] = dot;
1511 node_stack[curr_tree_depth] = node;
1512 flags[curr_tree_depth] = 0;
1513 skip_U = 0;
1514 // skip_T = 0;
1515 continue;
1516 }
1517 }
1518 }
1519
1520 if (curr_tree_depth == 0) break;
1521
1522 // go up one level in the tree
1523
1524 curr_tree_depth--;
1525 dot = dot_stack[curr_tree_depth];
1526 node = node_stack[curr_tree_depth];
1527 skip_U = flags[curr_tree_depth] & U_FLAG;
1528 skip_T = flags[curr_tree_depth] & T_FLAG;
1529
1530 } while (1);
1531}
1532
1534 size_t num_points,
1535 double (*coordinates_xyz)[3], size_t n,
1536 double ** cos_angles,
1537 size_t * cos_angles_array_size,
1538 double (**result_coordinates_xyz)[3],
1539 size_t * result_coordinates_xyz_array_size,
1540 size_t ** local_point_ids,
1541 size_t * local_point_ids_array_size,
1542 size_t * num_local_point_ids) {
1543
1544 if (num_points == 0) return;
1545
1546 if (cos_angles != NULL)
1547 ENSURE_ARRAY_SIZE(*cos_angles, *cos_angles_array_size, num_points * n);
1548
1549 if (n == 1) {
1551 search, num_points, coordinates_xyz, (cos_angles!=NULL)?*cos_angles:NULL,
1552 result_coordinates_xyz, result_coordinates_xyz_array_size,
1553 local_point_ids, local_point_ids_array_size, num_local_point_ids);
1554
1555 size_t total_num_local_points = 0;
1556 for (size_t i = 0; i < num_points; ++i)
1557 total_num_local_points += num_local_point_ids[i];
1558
1559 if ((cos_angles != NULL) && (total_num_local_points > num_points)) {
1560
1561 ENSURE_ARRAY_SIZE(*cos_angles, *cos_angles_array_size,
1562 total_num_local_points);
1563
1564 for (size_t i = num_points - 1, offset = total_num_local_points - 1;
1565 i != (size_t)-1; i--) {
1566
1567 for (size_t j = 0; j < num_local_point_ids[i]; ++j, --offset)
1568 (*cos_angles)[offset] = (*cos_angles)[i];
1569 }
1570 }
1571 return;
1572 }
1573
1574
1575 if (search == NULL) {
1576 memset(num_local_point_ids, 0, num_points * sizeof(*num_local_point_ids));
1577 return;
1578 }
1579
1580 struct point_sphere_part_node * base_node = &(search->base_node);
1581
1582 size_t total_num_local_point_ids = 0;
1583
1584 double * dot_stack = xmalloc(search->max_tree_depth * sizeof(*dot_stack));
1585 struct point_sphere_part_node ** node_stack =
1586 xmalloc(search->max_tree_depth * sizeof(*node_stack));
1587 int * flags = xmalloc(search->max_tree_depth * sizeof(*flags));
1588
1589 struct point_id_xyz_angle * results = NULL;
1590 size_t results_array_size = 0;
1591
1592 for (size_t i = 0; i < num_points; ++i) {
1593
1594 struct point_sphere_part_node * curr_node = base_node;
1595
1596 double * curr_coordinates_xyz = coordinates_xyz[i];
1597
1598 size_t curr_tree_depth = 0;
1599 struct point_id_xyz * points = search->points;
1600 size_t curr_num_points = 0;
1601
1602 // get the matching leaf for the current point
1603 do {
1604
1605 double dot = curr_node->gc_norm_vector[0]*curr_coordinates_xyz[0] +
1606 curr_node->gc_norm_vector[1]*curr_coordinates_xyz[1] +
1607 curr_node->gc_norm_vector[2]*curr_coordinates_xyz[2];
1608
1609 dot_stack[curr_tree_depth] = dot;
1610 node_stack[curr_tree_depth] = curr_node;
1611 flags[curr_tree_depth] = 0;
1612
1613 // angle >= M_PI_2
1614 if (dot <= 0.0) {
1615
1616 if (curr_node->U_size < n) {
1617
1618 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1619 curr_num_points = curr_node->U_size + curr_node->T_size;
1620 break;
1621 } else if (curr_node->flags & U_IS_LEAF) {
1622
1623 flags[curr_tree_depth] = U_FLAG;
1624 curr_num_points = curr_node->U_size;
1625 break;
1626 } else {
1627
1628 flags[curr_tree_depth] = U_FLAG;
1629 curr_node = curr_node->U;
1630 }
1631
1632 } else {
1633
1634 if (curr_node->T_size < n) {
1635
1636 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1637 curr_num_points = curr_node->U_size + curr_node->T_size;
1638 break;
1639 } else if (curr_node->flags & T_IS_LEAF) {
1640
1641 points += curr_node->U_size;
1642 flags[curr_tree_depth] = T_FLAG;
1643 curr_num_points = curr_node->T_size;
1644 break;
1645 } else {
1646
1647 points += curr_node->U_size;
1648 flags[curr_tree_depth] = T_FLAG;
1649 curr_node = curr_node->T;
1650 }
1651 }
1652
1653 curr_tree_depth++;
1654 } while (1);
1655
1656 assert(curr_num_points > 0);
1657
1658 size_t num_results =
1660 n, points, curr_num_points, curr_coordinates_xyz,
1661 &results, &results_array_size);
1662
1663 // do a detailed search
1665 n, curr_coordinates_xyz, &results, &results_array_size, &num_results,
1666 dot_stack, node_stack, flags, curr_tree_depth);
1667
1668 // extract the results
1669 ENSURE_ARRAY_SIZE(*local_point_ids, *local_point_ids_array_size,
1670 total_num_local_point_ids + num_results);
1671 size_t * local_point_ids_ =
1672 (*local_point_ids) + total_num_local_point_ids;
1673 double * cos_angles_;
1674 if (cos_angles != NULL) {
1675 ENSURE_ARRAY_SIZE(*cos_angles, *cos_angles_array_size,
1676 total_num_local_point_ids + num_results);
1677 cos_angles_ = (*cos_angles) + total_num_local_point_ids;
1678 } else {
1679 cos_angles_ = NULL;
1680 }
1681 double (*result_coordinates_xyz_)[3];
1682 if (result_coordinates_xyz != NULL) {
1683 ENSURE_ARRAY_SIZE(*result_coordinates_xyz,
1684 *result_coordinates_xyz_array_size,
1685 total_num_local_point_ids + num_results);
1686 result_coordinates_xyz_ =
1687 (*result_coordinates_xyz) + total_num_local_point_ids;
1688 } else {
1689 result_coordinates_xyz_ = NULL;
1690 }
1691
1692 for (size_t j = 0; j < num_results; ++j) {
1693
1694 local_point_ids_[j] = results[j].point.idx;
1695 if (cos_angles_ != NULL) cos_angles_[j] = results[j].cos_angle;
1696 if (result_coordinates_xyz_ != NULL) {
1697 result_coordinates_xyz_[j][0] = results[j].point.coordinates_xyz[0];
1698 result_coordinates_xyz_[j][1] = results[j].point.coordinates_xyz[1];
1699 result_coordinates_xyz_[j][2] = results[j].point.coordinates_xyz[2];
1700 }
1701 }
1702
1703 num_local_point_ids[i] = num_results;
1704 total_num_local_point_ids += num_results;
1705 }
1706
1707 free(results);
1708 free(flags);
1709 free(node_stack);
1710 free(dot_stack);
1711}
1712
1714 struct point_sphere_part_search * search, struct bounding_circle circle) {
1715
1716 if (search == NULL) return 0;
1717
1718 return point_check_bnd_circle(&(search->base_node), circle);
1719}
1720
1721static void search_point(struct sphere_part_node * node,
1722 double point[],
1723 size_t ** overlap_cells,
1724 size_t * overlap_cells_array_size,
1725 size_t * num_overlap_cells,
1726 struct overlaps * search_interval_tree_buffer,
1727 double prev_gc_norm_vector[]) {
1728
1729 double dot = point[0] * node->gc_norm_vector[0] +
1730 point[1] * node->gc_norm_vector[1] +
1731 point[2] * node->gc_norm_vector[2];
1732
1733 // angle < M_PI_2
1734 if (dot > -yac_angle_tol) {
1735
1736 if (node->flags & T_IS_LEAF) {
1737
1738 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1739 *num_overlap_cells + node->T_size);
1740 memcpy(*overlap_cells + *num_overlap_cells, node->T,
1741 node->T_size * sizeof(**overlap_cells));
1742 *num_overlap_cells += node->T_size;
1743
1744 } else {
1745 search_point(node->T, point, overlap_cells,
1746 overlap_cells_array_size, num_overlap_cells,
1747 search_interval_tree_buffer, node->gc_norm_vector);
1748 }
1749 }
1750
1751 // angle > M_PI_2
1752 if (dot < yac_angle_tol) {
1753
1754 if (node->flags & U_IS_LEAF) {
1755
1756 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1757 *num_overlap_cells + node->U_size);
1758 memcpy(*overlap_cells + *num_overlap_cells, node->U,
1759 node->U_size * sizeof(**overlap_cells));
1760 *num_overlap_cells += node->U_size;
1761
1762 } else {
1763 search_point(node->U, point, overlap_cells,
1764 overlap_cells_array_size, num_overlap_cells,
1765 search_interval_tree_buffer, node->gc_norm_vector);
1766 }
1767 }
1768
1769 // fabs(angle - M_PI_2) <= (node->I_angle)
1770 // fabs(cos(angle)) <= sin(node->I_angle)
1771 if (fabs(dot) <= node->I_angle.sin) {
1772
1773 if (node->flags & I_IS_INTERVAL_TREE) {
1774
1775 // project the point onto the current great circle
1776 double GCp[3], bVp[3];
1777 crossproduct_kahan(node->gc_norm_vector, point, GCp);
1778 crossproduct_kahan(GCp, node->gc_norm_vector, bVp);
1779
1780 struct interval search_interval;
1781 // if the projected point does not coincide with the norm vector of
1782 // the plane through the great circle
1783 if ((fabs(bVp[0]) > 1e-9) || (fabs(bVp[1]) > 1e-9) ||
1784 (fabs(bVp[2]) > 1e-9)) {
1785 normalise_vector(bVp);
1786 double base_angle = get_vector_angle(bVp, prev_gc_norm_vector);
1787 search_interval.left=base_angle;
1788 search_interval.right=base_angle;
1789 } else {
1790 search_interval.left = -M_PI;
1791 search_interval.right = M_PI;
1792 }
1793
1794 search_interval_tree_buffer->num_overlaps = 0;
1795
1797 search_interval, search_interval_tree_buffer);
1798
1799 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1800 *num_overlap_cells +
1801 search_interval_tree_buffer->num_overlaps);
1802
1803 for (size_t i = 0; i < search_interval_tree_buffer->num_overlaps;
1804 ++i) {
1805 (*overlap_cells)[(*num_overlap_cells)+i] =
1806 node->I.ivt.head_node[
1807 search_interval_tree_buffer->overlap_iv[i]].value;
1808 }
1809
1810 *num_overlap_cells += search_interval_tree_buffer->num_overlaps;
1811
1812 } else {
1813
1814 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1815 *num_overlap_cells + node->I_size);
1816 memcpy(*overlap_cells + *num_overlap_cells, node->I.list,
1817 node->I_size * sizeof(**overlap_cells));
1818 *num_overlap_cells += node->I_size;
1819 }
1820 }
1821}
1822
1824 struct bnd_sphere_part_search * search, yac_coordinate_pointer coordinates_xyz,
1825 size_t count, size_t ** cells, size_t * num_cells_per_coordinate) {
1826
1827 struct sphere_part_node * base_node = &(search->base_node);
1828
1829 size_t * temp_search_results = NULL;
1830 size_t temp_search_results_array_size = 0;
1831 size_t num_temp_search_results = 0;
1832
1833 struct overlaps search_interval_tree_buffer = {0, 0, NULL};
1834
1835 memset(
1836 num_cells_per_coordinate, 0, count * sizeof(*num_cells_per_coordinate));
1837 size_t * cells_ = NULL;
1838 size_t cells_array_size = 0;
1839 size_t num_cells = 0;
1840 ENSURE_ARRAY_SIZE(cells_, cells_array_size, count);
1841
1842 for (size_t i = 0; i < count; ++i) {
1843
1844 double * curr_coordinates_xyz = &(coordinates_xyz[i][0]);
1845
1846 num_temp_search_results = 0;
1847
1848 double gc_norm_vector[3] = {0.0,0.0,1.0};
1849
1850 search_point(base_node, curr_coordinates_xyz, &temp_search_results,
1851 &temp_search_results_array_size, &num_temp_search_results,
1852 &search_interval_tree_buffer, gc_norm_vector);
1853
1855 cells_, cells_array_size, num_cells + num_temp_search_results);
1856
1857 memcpy(cells_ + num_cells, temp_search_results,
1858 num_temp_search_results * sizeof(*temp_search_results));
1859 num_cells_per_coordinate[i] = num_temp_search_results;
1860 num_cells += num_temp_search_results;
1861 }
1862
1863 free(temp_search_results);
1864 free(search_interval_tree_buffer.overlap_iv);
1865
1866 *cells = xrealloc(cells_, num_cells * sizeof(*cells_));
1867}
1868
1870 struct bnd_sphere_part_search * search, struct bounding_circle * bnd_circles,
1871 size_t count, size_t ** cells, size_t * num_cells_per_bnd_circle) {
1872
1873 struct sphere_part_node * base_node = &(search->base_node);
1874
1875 size_t * temp_search_results = NULL;
1876 size_t temp_search_results_array_size = 0;
1877 size_t num_temp_search_results = 0;
1878
1879 struct overlaps search_interval_tree_buffer = {0, 0, NULL};
1880
1881 memset(
1882 num_cells_per_bnd_circle, 0, count * sizeof(*num_cells_per_bnd_circle));
1883 size_t * cells_ = NULL;
1884 size_t cells_array_size = 0;
1885 size_t num_cells = 0;
1886 ENSURE_ARRAY_SIZE(cells_, cells_array_size, count);
1887
1888 for (size_t i = 0; i < count; ++i) {
1889
1890 num_temp_search_results = 0;
1891
1892 double gc_norm_vector[3] = {0.0,0.0,1.0};
1893
1894 search_bnd_circle(base_node, bnd_circles[i], &temp_search_results,
1895 &temp_search_results_array_size, &num_temp_search_results,
1896 &search_interval_tree_buffer, gc_norm_vector);
1897
1899 cells_, cells_array_size, num_cells + num_temp_search_results);
1900
1901 memcpy(cells_ + num_cells, temp_search_results,
1902 num_temp_search_results * sizeof(*temp_search_results));
1903 num_cells_per_bnd_circle[i] = num_temp_search_results;
1904 num_cells += num_temp_search_results;
1905 }
1906
1907 free(temp_search_results);
1908 free(search_interval_tree_buffer.overlap_iv);
1909
1910 *cells = xrealloc(cells_, num_cells * sizeof(*cells_));
1911}
1912
1913static void free_sphere_part_tree (struct sphere_part_node tree) {
1914
1915 // free I_list
1916 if (tree.flags & I_IS_INTERVAL_TREE)
1917 free(tree.I.ivt.head_node);
1918
1919 if ((tree.flags & U_IS_LEAF) == 0) {
1920 free_sphere_part_tree(*(struct sphere_part_node*)(tree.U));
1921 free(tree.U);
1922 }
1923
1924 if ((tree.flags & T_IS_LEAF) == 0) {
1925 free_sphere_part_tree(*(struct sphere_part_node*)(tree.T));
1926 free(tree.T);
1927 }
1928}
1929
1931
1932 if ((tree->flags & U_IS_LEAF) == 0) {
1934 free(tree->U);
1935 }
1936
1937 if ((tree->flags & T_IS_LEAF) == 0) {
1939 free(tree->T);
1940 }
1941}
1942
1944 struct point_sphere_part_search * search) {
1945
1946 if (search == NULL) return;
1947
1949 free(search->points);
1950 free(search);
1951}
1952
1954
1955 if (search == NULL) return;
1956
1958 free(search->ids);
1959 free(search);
1960}
#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)
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)
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 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)
int yac_point_sphere_part_search_bnd_circle_contains_points(struct point_sphere_part_search *search, struct bounding_circle circle)
static int point_check_bnd_circle(struct point_sphere_part_node *node, struct bounding_circle bnd_circle)
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:120
static size_t num_points
Definition yac.c:121
#define YAC_ASSERT(exp, msg)
Definition yac_assert.h:15
Xt_int yac_int
Definition yac_types.h:15
double const (*const yac_const_coordinate_pointer)[3]
Definition yac_types.h:20
double(* yac_coordinate_pointer)[3]
Definition yac_types.h:19