YAC 3.20.0
Yet Another Coupler
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
238#ifdef HAVE_CONFIG_H
239// Get the definition of the 'restrict' keyword.
240#include "config.h"
241#endif
242
243#include <assert.h>
244#include <stdlib.h>
245#include <math.h>
246#include <string.h>
247#include <stdint.h>
248#include <float.h>
249#include <limits.h>
250
251#include "sphere_part.h"
252#include "interval_tree.h"
253#include "utils_core.h"
254#include "ensure_array_size.h"
255
256union I_list {
257 struct {
259 size_t num_nodes;
261 size_t *list;
262};
263
264enum {
267};
268enum {
271};
272
278
280
281 int flags;
282
283 union I_list I;
284 void * U, * T;
285
287
289
290 double gc_norm_vector[3];
291};
292
297
304
306 struct bounding_circle bnd_circle; // has to be first entry
307 size_t local_id;
309};
310
312 double coordinates_xyz[3]; // has to be the first entry
313 size_t idx; // index of the point in the coordinates array passed to
314 // the constructor
315};
316
321
323
324 int flags;
325
326 void * U, * T;
327
328 size_t U_size, T_size;
329
330 double gc_norm_vector[3];
331};
332
339
341 size_t idx;
342 int32_t coordinate_xyz[3];
343};
344
345static void init_sphere_part_node(struct sphere_part_node * node) {
346
347 node->flags = 0;
348 node->I_size = 0;
349 node->U_size = 0;
350 node->T_size = 0;
351 node->I_angle = SIN_COS_ZERO;
352 node->gc_norm_vector[0] = 0;
353 node->gc_norm_vector[1] = 0;
354 node->gc_norm_vector[2] = 1;
355}
356
358
359 struct sphere_part_node * node = xmalloc(1 * sizeof(*node));
360
362
363 return node;
364}
365
366// computes the norm vector for the plane the partitions the data in half
367// (more or less)
368static inline void compute_gc_norm_vector(
369 void * coords_data, size_t coords_size, size_t coords_count,
370 double prev_gc_norm_vector[], double gc_norm_vector[]) {
371
372
373 double balance_point[3] = {0.0,0.0,0.0};
374
375 // compute balance point
376 for (size_t i = 0; i < coords_count; ++i) {
377
378 double * coords =
379 (double*)(((unsigned char*)coords_data) + i * coords_size);
380 balance_point[0] += coords[0];
381 balance_point[1] += coords[1];
382 balance_point[2] += coords[2];
383 }
384
385 if ((fabs(balance_point[0]) > 1e-9) ||
386 (fabs(balance_point[1]) > 1e-9) ||
387 (fabs(balance_point[2]) > 1e-9)) {
388 normalise_vector(balance_point);
389 } else {
390 balance_point[0] = prev_gc_norm_vector[2];
391 balance_point[1] = prev_gc_norm_vector[0];
392 balance_point[2] = prev_gc_norm_vector[1];
393 }
394
396 balance_point, prev_gc_norm_vector, gc_norm_vector);
397
398 if ((fabs(gc_norm_vector[0]) > 1e-9) ||
399 (fabs(gc_norm_vector[1]) > 1e-9) ||
400 (fabs(gc_norm_vector[2]) > 1e-9)) {
402 } else {
403 gc_norm_vector[0] = prev_gc_norm_vector[2];
404 gc_norm_vector[1] = prev_gc_norm_vector[0];
405 gc_norm_vector[2] = prev_gc_norm_vector[1];
406 }
407}
408
410{
411 struct temp_partition_data temp = *a;
412 *a = *b;
413 *b = temp;
414}
415
416static size_t swap_node_type(struct temp_partition_data *part_data, size_t i, int node_type, size_t begin, size_t end)
417{
418 for (size_t j = begin; j < end; ++j)
419 {
420 if (part_data[j].node_type == node_type)
421 {
422 swap_partition_data(&part_data[i], &part_data[j]);
423 return j + 1;
424 }
425 }
426
427 return end + 1;
428}
429
430static 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)
431{
432 size_t I_begin = I_FULL_size;
433 size_t U_begin = I_FULL_size + I_size;
434 size_t T_begin = I_FULL_size + I_size + U_size;
435
436 size_t I_end = I_begin + I_size;
437 size_t U_end = U_begin + U_size;
438 size_t T_end = T_begin + T_size;
439
440 while (I_end > I_begin && part_data[I_end-1].node_type == I_NODE) I_end--;
441 while (U_end > U_begin && part_data[U_end-1].node_type == U_NODE) U_end--;
442 while (T_end > T_begin && part_data[T_end-1].node_type == T_NODE) T_end--;
443
444 for (size_t i = 0; i < I_FULL_size; ++i)
445 {
446 if (part_data[i].node_type != I_NODE_FULL)
447 {
448 I_begin = swap_node_type(part_data, i, I_NODE_FULL, I_begin, T_end);
449 }
450 }
451
452 I_begin = I_FULL_size;
453 for (size_t i = I_begin; i < I_end; ++i)
454 {
455 if (part_data[i].node_type != I_NODE)
456 {
457 U_begin = swap_node_type(part_data, i, I_NODE, U_begin, U_end);
458 if (U_begin > U_end)
459 {
460 T_begin = swap_node_type(part_data, i, I_NODE, T_begin, T_end);
461 }
462 }
463 }
464
465 U_begin = I_FULL_size + I_size;
466 T_begin = I_FULL_size + I_size + U_size;
467 for (size_t i = U_begin; i < U_end; ++i)
468 {
469 if (part_data[i].node_type != U_NODE)
470 {
471 T_begin = swap_node_type(part_data, i, U_NODE, T_begin, T_end);
472 }
473 }
474}
475
476static void partition_data (
477 size_t * local_cell_ids, struct temp_partition_data * part_data,
478 size_t num_cell_ids, size_t threshold, struct sphere_part_node * parent_node,
479 double prev_gc_norm_vector[]) {
480
481 if (num_cell_ids == 0) {
482 parent_node->flags = U_IS_LEAF + T_IS_LEAF;
483 return;
484 }
485
487 part_data, sizeof(*part_data), num_cell_ids,
488 prev_gc_norm_vector, parent_node->gc_norm_vector);
489
490 // partition data into cells that overlap with the great circle and cells
491 // that are one side of the circle
492
493 size_t I_FULL_size = 0;
494 size_t I_size = 0;
495 size_t U_size = 0;
496 size_t T_size = 0;
497
498 struct sin_cos_angle max_inc_angle = SIN_COS_ZERO;
499
500 for (size_t i = 0; i < num_cell_ids; ++i) {
501
502 struct bounding_circle curr_bnd_circle = part_data[i].bnd_circle;
503
504 // get angle between the norm vector of the great circle and the base
505 // point of the bounding circle
506 struct sin_cos_angle angle =
508 curr_bnd_circle.base_vector, parent_node->gc_norm_vector);
509
510 // get the angle between between the plane of the great circle and base
511 // point of the bounding circle
512 struct sin_cos_angle diff_angle_gc =
513 sin_cos_angle_new(fabs(angle.cos), angle.sin);
514
515 // if the point intersects with the great circle
516 if (compare_angles(diff_angle_gc, curr_bnd_circle.inc_angle) <= 0) {
517
518 // if gc_norm_vector or -gc_norm_vector is in the bounding circle
519 if ((angle.sin < curr_bnd_circle.inc_angle.sin) ||
520 (0.0 >= curr_bnd_circle.inc_angle.cos)) {
521
522 // set node type for current cell
523 part_data[i].node_type = I_NODE_FULL;
524 I_FULL_size++;
525
526 max_inc_angle = SIN_COS_M_PI_2;
527
528 } else {
529
530 // set node type for current cell
531 part_data[i].node_type = I_NODE;
532 I_size++;
533
534 struct sin_cos_angle inc_angle =
535 sum_angles_no_check(diff_angle_gc, curr_bnd_circle.inc_angle);
536
537 if (compare_angles(max_inc_angle, inc_angle) < 0)
538 max_inc_angle = inc_angle;
539 }
540
541 // angle > M_PI_2
542 } else if (angle.cos < 0.0) {
543
544 // set node type for current cell
545 part_data[i].node_type = U_NODE;
546 U_size++;
547
548 } else {
549
550 // set node type for current cell
551 part_data[i].node_type = T_NODE;
552 T_size++;
553 }
554 }
555
556 sort_partition_data(part_data, I_FULL_size, I_size, U_size, T_size);
557
558 I_size += I_FULL_size;
559 parent_node->I_size = I_size;
560 parent_node->U_size = U_size;
561 parent_node->T_size = T_size;
562
563 // if max_inc_angle > PI/2
564 if (compare_angles(max_inc_angle, SIN_COS_M_PI_2) >= 0) {
565 parent_node->I_angle = SIN_COS_M_PI_2;
566 } else {
567 parent_node->I_angle = max_inc_angle;
568 }
569
570 if (I_size > 0) {
571
572 if (I_size > I_list_tree_min_size) {
573
574 assert(sizeof(struct interval_node) > sizeof(size_t));
575 struct interval_node * head_node = xmalloc(I_size * sizeof(*head_node));
576 parent_node->I.ivt.head_node = head_node;
577 parent_node->I.ivt.num_nodes = I_size;
578
579 // for all bounding circles that include gc_norm_vector or
580 // -gc_norm_vector
581 for (size_t i = 0; i < I_FULL_size; ++i) {
582
583 head_node[i].range.left = -M_PI;
584 head_node[i].range.right = M_PI;
585 head_node[i].value = part_data[i].local_id;
586 }
587
588 for (size_t i = I_FULL_size; i < I_size; ++i) {
589
590 double GCp[3], bVp[3];
591 struct bounding_circle curr_bnd_circle = part_data[i].bnd_circle;
592
593 // project the base vector of the current bounding circle onto the
594 // current partitioning great circle
596 curr_bnd_circle.base_vector, GCp);
597 crossproduct_kahan(GCp, parent_node->gc_norm_vector, bVp);
599 (fabs(bVp[0]) > 1e-9) || (fabs(bVp[1]) > 1e-9) ||
600 (fabs(bVp[2]) > 1e-9),
601 "projected vector is nearly identical to gc_norm_vector")
602 normalise_vector(bVp);
603
604 // the inc_angle of the bounding circle also needs to be projected
605 // onto the great circle
606 // (the formula for this is:
607 // new_inc_angle=acos(sin(inc_angle)/cos(base_angle))
608 // To find this formula, you have to determine the longitude of
609 // of longitude circle that has exactly one intersection with the
610 // bounding circle.
611 // (see https://www.dropbox.com/s/82bxzno1mjogbtf/function_2nd_try.pdf)
612 double bnd_circle_lat_cos =
613 get_vector_angle_2(bVp, curr_bnd_circle.base_vector).cos;
614 double inc_angle =
615 M_PI_2 - acos(curr_bnd_circle.inc_angle.sin/bnd_circle_lat_cos);
616
617 // By definition the previous norm vector is on the current great
618 // great circle. We use this as a reference point for I
619
620 // compute "distance" of the projected base vector to the reference
621 // point
622 double base_angle = get_vector_angle(bVp, prev_gc_norm_vector);
623
624 head_node[i].range.left = base_angle - inc_angle;
625 head_node[i].range.right = base_angle + inc_angle;
626 head_node[i].value = part_data[i].local_id;
627 }
628
629 yac_generate_interval_tree(head_node, I_size);
630 parent_node->flags |= I_IS_INTERVAL_TREE;
631 } else {
632 for (size_t i = 0; i < I_size; ++i)
633 local_cell_ids[i] = part_data[i].local_id;
634 parent_node->I.list = (void*)local_cell_ids;
635 }
636 } else
637 parent_node->I.list = NULL;
638
639 part_data += I_size;
640 local_cell_ids += I_size;
641
642 // check whether the lists are small enough (if not -> partition again)
643 if (U_size <= threshold) {
644
645 for (size_t i = 0; i < U_size; ++i)
646 local_cell_ids[i] = part_data[i].local_id;
647 parent_node->U = (void*)local_cell_ids;
648 parent_node->flags |= U_IS_LEAF;
649
650 } else {
651
652 parent_node->U = get_sphere_part_node();
653 partition_data(local_cell_ids, part_data, U_size, threshold,
654 parent_node->U, parent_node->gc_norm_vector);
655 }
656 local_cell_ids += U_size;
657 part_data += U_size;
658
659 if (T_size <= threshold) {
660
661 for (size_t i = 0; i < T_size; ++i)
662 local_cell_ids[i] = part_data[i].local_id;
663 parent_node->T = (void*)local_cell_ids;
664 parent_node->flags |= T_IS_LEAF;
665 local_cell_ids += T_size;
666
667 } else {
668
669 parent_node->T = get_sphere_part_node();
670 partition_data(local_cell_ids, part_data, T_size, threshold,
671 parent_node->T, parent_node->gc_norm_vector);
672 }
673}
674
675static int compare_point_idx_xyz(void const * a, void const * b) {
676 return (((struct point_id_xyz *)a)->idx > ((struct point_id_xyz *)b)->idx) -
677 (((struct point_id_xyz *)a)->idx < ((struct point_id_xyz *)b)->idx);
678}
679
681 struct point_id_xyz * points, size_t num_points, size_t threshold,
682 double prev_gc_norm_vector[], size_t curr_tree_depth,
683 size_t * max_tree_depth, int * list_flag) {
684
685 if (curr_tree_depth > *max_tree_depth) *max_tree_depth = curr_tree_depth;
686
687 struct point_sphere_part_node * node = xmalloc(1 * sizeof(*node));
688 double * gc_norm_vector = &(node->gc_norm_vector[0]);
689
691 points, sizeof(*points), num_points, prev_gc_norm_vector, gc_norm_vector);
692
693 // angle between a point and the great circle plane
694 // acos(dot(gc_norm_vector, point_xyz)) = angle(gc_norm_vector, point_xyz)
695 // acos(dot(gc_norm_vector, point_xyz)) - PI/2 = angle(gc_plane, point_xyz)
696 // dot <= 0.0 -> U list
697 // dot > 0.0 -> T list
698
700 {
702 for (size_t i = 0; i < num_points; ++i) {
703 double * curr_coordinates_xyz = &(points[i].coordinates_xyz[0]);
704 double dot = curr_coordinates_xyz[0] * gc_norm_vector[0] +
705 curr_coordinates_xyz[1] * gc_norm_vector[1] +
706 curr_coordinates_xyz[2] * gc_norm_vector[2];
707
708 // if (angle >= M_PI_2)
709 list_flag[i] = (dot <= 0.0);
710 }
711 }
712 size_t U_size = 0, T_size = 0;
713 for (size_t i = 0; i < num_points; ++i) {
714 if (list_flag[i]) ++U_size;
715 else ++T_size;
716 }
717
718 // The number of T-points among the first U-size number of points in the
719 // array is equal to the number of U-points in the remaining array. These
720 // have to be exchanged in order to get a sorted vertex array
721
722 // search for all T-points in the U-part of the array and swap them with a
723 // U-point in the T-part
724 for (size_t i = 0, j = U_size; i < U_size; ++i) {
725 // if the current point belongs to the T-list
726 if (!list_flag[i]) {
727 // search for a matching U-point
728 for (;!list_flag[j];++j);
729 struct point_id_xyz temp_point = points[i];
730 points[i] = points[j];
731 points[j] = temp_point;
732 ++j;
733 }
734 }
735
736 node->U_size = U_size;
737 node->T_size = T_size;
738 node->flags = 0;
739
740 // check whether the lists are small enough (if not -> partition again)
741 if ((U_size <= threshold) || (U_size == num_points)) {
742
743 node->U = points;
744 node->flags |= U_IS_LEAF;
745 qsort(points, U_size, sizeof(*points), compare_point_idx_xyz);
746
747 } else {
748
749 node->U =
751 points, U_size, threshold, gc_norm_vector,
752 curr_tree_depth + 1, max_tree_depth, list_flag);
753 }
754
755 if ((T_size <= threshold) || (T_size == num_points)) {
756
757 node->T = points + U_size;
758 node->flags |= T_IS_LEAF;
759 qsort(points + U_size, T_size, sizeof(*points), compare_point_idx_xyz);
760
761 } else {
762
763 node->T =
765 points + U_size, T_size, threshold, gc_norm_vector,
766 curr_tree_depth + 1, max_tree_depth, list_flag);
767 }
768
769 return node;
770}
771
773 struct bounding_circle * circles, size_t num_circles) {
774
775 struct bnd_sphere_part_search * search = xmalloc(1 * sizeof(*search));
776
777 double gc_norm_vector[3] = {0.0,0.0,1.0};
778
780
781 size_t * ids = xmalloc(num_circles * sizeof(*ids));
782 search->ids = ids;
783
784 struct temp_partition_data * part_data =
785 xmalloc(num_circles * sizeof(*part_data));
786 for (size_t i = 0; i < num_circles; ++i) {
787 part_data[i].bnd_circle = circles[i];
788 part_data[i].local_id = i;
789 }
790
791 partition_data(ids, part_data, num_circles, I_list_tree_min_size,
792 &(search->base_node), gc_norm_vector);
793
794 free(part_data);
795
796 return search;
797}
798
800 const void * a,const void * b) {
801
802 struct point_id_xyz_int32 * point_a = (struct point_id_xyz_int32 *)a;
803 struct point_id_xyz_int32 * point_b = (struct point_id_xyz_int32 *)b;
804
805 int ret;
806
807 for (int i = 0; i < 3; ++i)
808 if ((ret = (point_a->coordinate_xyz[i] > point_b->coordinate_xyz[i]) -
809 (point_a->coordinate_xyz[i] < point_b->coordinate_xyz[i])))
810 return ret;
811 return 0;
812}
813
814static struct point_id_xyz *
817 yac_int const * ids, int const * mask) {
818
819 struct point_id_xyz_int32 * points_int32 =
820 xmalloc(*num_points * sizeof(*points_int32));
821
822 double const scale = (double)(2 << 21);
823
824 size_t num_unmasked_points;
825
826 if (mask == NULL) {
827 num_unmasked_points = *num_points;
828 for (size_t i = 0; i < num_unmasked_points; ++i) {
829
830 points_int32[i].idx = i;
831 for (size_t j = 0; j < 3; ++j)
832 points_int32[i].coordinate_xyz[j] =
833 (int32_t)round(coordinates_xyz[i][j] * scale);
834 }
835 } else {
836 num_unmasked_points = 0;
837 for (size_t i = 0; i < *num_points; ++i) {
838
839 if (!mask[i]) continue;
840 points_int32[num_unmasked_points].idx = i;
841 for (size_t j = 0; j < 3; ++j)
842 points_int32[num_unmasked_points].coordinate_xyz[j] =
843 (int32_t)round(coordinates_xyz[i][j] * scale);
844 num_unmasked_points++;
845 }
846 }
847
848 // sort points
849 qsort(points_int32, num_unmasked_points,
850 sizeof(*points_int32), compare_points_int32_coord);
851
852 struct point_id_xyz_int32 dummy;
853 dummy.idx = SIZE_MAX;
854 dummy.coordinate_xyz[0] = INT32_MAX;
855 dummy.coordinate_xyz[1] = INT32_MAX;
856 dummy.coordinate_xyz[2] = INT32_MAX;
857 struct point_id_xyz_int32 * prev = &dummy, * curr = points_int32;
858 yac_int prev_id = YAC_INT_MAX;
859 size_t new_num_points = 0;
860 for (size_t i = 0; i < num_unmasked_points; ++i, ++curr) {
861
862 size_t curr_idx = curr->idx;
863 if (compare_points_int32_coord(prev, curr)) {
864 prev = points_int32 + new_num_points++;
865 if (prev != curr) *prev = *curr;
866 prev_id = ids[curr_idx];
867 } else {
868 yac_int curr_id = ids[curr_idx];
869 if (curr_id > prev_id) {
870 prev_id = curr_id;
871 prev->idx = curr_idx;
872 }
873 }
874 }
875
876 struct point_id_xyz * points = xmalloc(new_num_points * sizeof(*points));
877 for (size_t i = 0; i < new_num_points; ++i) {
878 size_t curr_idx = points_int32[i].idx;
879 points[i].idx = curr_idx;
880 memcpy(
881 points[i].coordinates_xyz, coordinates_xyz[curr_idx], 3 * sizeof(double));
882 }
883 *num_points = new_num_points;
884 free(points_int32);
885 return points;
886}
887
889 size_t num_points, yac_const_coordinate_pointer coordinates_xyz,
890 yac_int const * ids) {
891
892 if (num_points == 0) return NULL;
893
894 struct point_sphere_part_search * search = xmalloc(1 * sizeof(*search));
895 struct point_id_xyz * points =
896 get_unique_points(&num_points, coordinates_xyz, ids, NULL);
897 search->points = points;
898
899 size_t max_tree_depth = 0;
900
901 int * list_flag = xmalloc(num_points * sizeof(*list_flag));
902
903 // emperical measurements have given a threshold for the leaf size of 2
904 struct point_sphere_part_node * tmp_node =
906 points, num_points, I_list_tree_min_size, (double[3]){0.0,0.0,1.0},
907 1, &max_tree_depth, list_flag);
908
909 free(list_flag);
910
911 search->base_node = *tmp_node;
912 search->max_tree_depth = max_tree_depth;
913 free(tmp_node);
914
915 return search;
916}
917
919 size_t num_points, yac_const_coordinate_pointer coordinates_xyz,
920 yac_int const * ids, int const * mask) {
921
922 if (num_points == 0) return NULL;
923
924 struct point_id_xyz * points =
925 get_unique_points(&num_points, coordinates_xyz, ids, mask);
926
927 struct point_sphere_part_search * search = xmalloc(1 * sizeof(*search));
928 search->points = xrealloc(points, num_points * sizeof(*points));
929
930 size_t max_tree_depth = 0;
931
932 int * list_flag = xmalloc(num_points * sizeof(*list_flag));
933
934 // emperical measurements have given a threshold for the leaf size of 2
935 struct point_sphere_part_node * tmp_node =
937 search->points, num_points, I_list_tree_min_size,
938 (double[3]){0.0,0.0,1.0}, 1, &max_tree_depth, list_flag);
939
940 free(list_flag);
941
942 search->base_node = *tmp_node;
943 search->max_tree_depth = max_tree_depth;
944 free(tmp_node);
945
946 return search;
947}
948
950 struct sphere_part_node * node, struct bounding_circle bnd_circle,
951 size_t ** restrict overlap_cells, size_t * overlap_cells_array_size,
952 size_t * restrict num_overlap_cells,
953 struct overlaps * search_interval_tree_buffer, double prev_gc_norm_vector[]) {
954
955 if (node->flags & I_IS_INTERVAL_TREE) {
956
957 struct sin_cos_angle angle =
959 bnd_circle.base_vector, node->gc_norm_vector);
960 angle.cos = fabs(angle.cos);
961
962 // if gc_norm_vector or -gc_norm_vector is in the bounding circle
963 if (compare_angles(angle, bnd_circle.inc_angle) <= 0) {
964 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
965 *num_overlap_cells + node->I.ivt.num_nodes);
966 for (size_t i = 0; i < node->I.ivt.num_nodes; ++i)
967 (*overlap_cells)[(*num_overlap_cells)+i] =
968 node->I.ivt.head_node[i].value;
969 *num_overlap_cells += node->I.ivt.num_nodes;
970 return;
971 }
972
973 double GCp[3], bVp[3];
974
975 // project the base vector of the current bounding circle onto the
976 // current great circle
977 crossproduct_kahan(node->gc_norm_vector, bnd_circle.base_vector, GCp);
978 crossproduct_kahan(GCp, node->gc_norm_vector, bVp);
980 (fabs(bVp[0]) > 1e-9) || (fabs(bVp[1]) > 1e-9) || (fabs(bVp[2]) > 1e-9),
981 "projected vector is nearly identical to gc_norm_vector")
982 normalise_vector(bVp);
983
984 // the inc_angle of the bounding circle also needs to be projected
985 // onto the great circle (see routine partition data for a detailed
986 // explanation)
987 double bnd_circle_lat_cos =
988 get_vector_angle_2(bVp, bnd_circle.base_vector).cos;
989 double inc_angle =
990 M_PI_2 - acos(bnd_circle.inc_angle.sin/bnd_circle_lat_cos);
991
992 // compute "distance" of the projected base vector to the reference point
993 double base_angle = get_vector_angle(bVp, prev_gc_norm_vector);
994
995 search_interval_tree_buffer->num_overlaps = 0;
996
998 node->I.ivt.head_node, node->I.ivt.num_nodes,
999 (struct interval){
1000 .left = base_angle - inc_angle,
1001 .right = base_angle + inc_angle},
1002 search_interval_tree_buffer);
1003
1004 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1005 *num_overlap_cells +
1006 search_interval_tree_buffer->num_overlaps);
1007
1008 for (size_t i = 0; i < search_interval_tree_buffer->num_overlaps; ++i)
1009 (*overlap_cells)[(*num_overlap_cells)+i] =
1010 node->I.ivt.head_node[
1011 search_interval_tree_buffer->overlap_iv[i]].value;
1012
1013 *num_overlap_cells += search_interval_tree_buffer->num_overlaps;
1014
1015 } else {
1016
1017 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1018 *num_overlap_cells + node->I_size);
1019 memcpy(*overlap_cells + *num_overlap_cells, node->I.list,
1020 node->I_size * sizeof(**overlap_cells));
1021 *num_overlap_cells += node->I_size;
1022 }
1023}
1024
1027 struct sphere_part_node * node, struct bounding_circle bnd_circle,
1028 size_t ** restrict overlap_cells, size_t * overlap_cells_array_size,
1029 size_t * restrict num_overlap_cells,
1030 struct overlaps * search_interval_tree_buffer, double prev_gc_norm_vector[]) {
1031
1032 if (node->flags & T_IS_LEAF) {
1033
1034 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1035 *num_overlap_cells + node->T_size);
1036 memcpy(*overlap_cells + *num_overlap_cells, node->T,
1037 node->T_size * sizeof(**overlap_cells));
1038 *num_overlap_cells += node->T_size;
1039
1040 } else {
1042 node->T, bnd_circle, overlap_cells, overlap_cells_array_size,
1043 num_overlap_cells, search_interval_tree_buffer, node->gc_norm_vector);
1044 }
1045
1046 if (node->flags & U_IS_LEAF) {
1047
1048 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1049 *num_overlap_cells + node->U_size);
1050 memcpy(*overlap_cells + *num_overlap_cells, node->U,
1051 node->U_size * sizeof(**overlap_cells));
1052 *num_overlap_cells += node->U_size;
1053
1054 } else {
1056 node->U, bnd_circle, overlap_cells, overlap_cells_array_size,
1057 num_overlap_cells, search_interval_tree_buffer, node->gc_norm_vector);
1058 }
1059
1061 node, bnd_circle, overlap_cells, overlap_cells_array_size,
1062 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
1063}
1064
1066 struct sphere_part_node * node, struct bounding_circle bnd_circle,
1067 size_t ** restrict overlap_cells, size_t * overlap_cells_array_size,
1068 size_t * restrict num_overlap_cells,
1069 struct overlaps * search_interval_tree_buffer, double prev_gc_norm_vector[]) {
1070
1071 double dot = bnd_circle.base_vector[0] * node->gc_norm_vector[0] +
1072 bnd_circle.base_vector[1] * node->gc_norm_vector[1] +
1073 bnd_circle.base_vector[2] * node->gc_norm_vector[2];
1074
1075 // angle < M_PI_2 + bnd_circle.inc_angle
1076 if (dot > - bnd_circle.inc_angle.sin) {
1077
1078 if (node->flags & T_IS_LEAF) {
1079
1080 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1081 *num_overlap_cells + node->T_size);
1082 memcpy(*overlap_cells + *num_overlap_cells, node->T,
1083 node->T_size * sizeof(**overlap_cells));
1084 *num_overlap_cells += node->T_size;
1085
1086 } else {
1088 node->T, bnd_circle, overlap_cells, overlap_cells_array_size,
1089 num_overlap_cells, search_interval_tree_buffer,
1090 node->gc_norm_vector);
1091 }
1092 }
1093
1094 // angle > M_PI_2 - bnd_circle.inc_angle
1095 if (dot < bnd_circle.inc_angle.sin) {
1096
1097 if (node->flags & U_IS_LEAF) {
1098
1099 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
1100 *num_overlap_cells + node->U_size);
1101 memcpy(*overlap_cells + *num_overlap_cells, node->U,
1102 node->U_size * sizeof(**overlap_cells));
1103 *num_overlap_cells += node->U_size;
1104
1105 } else {
1107 node->U, bnd_circle, overlap_cells, overlap_cells_array_size,
1108 num_overlap_cells, search_interval_tree_buffer,
1109 node->gc_norm_vector);
1110 }
1111 }
1112
1113 struct sin_cos_angle angle_sum =
1114 sum_angles_no_check(node->I_angle, bnd_circle.inc_angle);
1115
1116 // if (I_angle + inc_angle > PI/2) ||
1117 // (fabs(angle - M_PI_2) <= (I_angle + inc_angle))
1118 //
1119 // assumtion:
1120 // I_angle >= 0 && I_angle <= PI/2
1121 // inc_angle >= 0 && inc_angle <= PI/2
1122 // angle >= 0 && angle <= PI
1123 //
1124 // => I_angle + inc_angle >= 0 && I_angle + inc_angle <= PI
1125 //
1126 // I_angle + inc_angle >= PI/2
1127 //
1128 // fabs(angle - M_PI_2) <= (I_angle + inc_angle)
1129 // => sin(fabs(angle - M_PI_2)) <= sin(I_angle + inc_angle)
1130 // this is wrong for (I_angle + inc_angle) > PI/2, however that case is
1131 // already covered by the first condition
1132 // => fabs(cos(angle)) <= sin(I_angle + inc_angle)
1133 if (((angle_sum.sin < 0.0) || (angle_sum.cos <= 0.0)) ||
1134 (fabs(dot) <= angle_sum.sin)) {
1136 node, bnd_circle, overlap_cells, overlap_cells_array_size,
1137 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
1138 }
1139}
1140
1141static void search_bnd_circle(struct sphere_part_node * node,
1142 struct bounding_circle bnd_circle,
1143 size_t ** restrict overlap_cells,
1144 size_t * overlap_cells_array_size,
1145 size_t * restrict num_overlap_cells,
1146 struct overlaps * search_interval_tree_buffer,
1147 double prev_gc_norm_vector[]) {
1148
1149 // if the bounding circle has an angle in the range of [0;PI/2[
1150 if (bnd_circle.inc_angle.cos > 0.0)
1152 node, bnd_circle, overlap_cells, overlap_cells_array_size,
1153 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
1154 else
1156 node, bnd_circle, overlap_cells, overlap_cells_array_size,
1157 num_overlap_cells, search_interval_tree_buffer, prev_gc_norm_vector);
1158}
1159
1160static inline void check_leaf_NN(
1161 struct point_id_xyz * points, size_t num_points,
1162 double * point_coordinates_xyz, struct sin_cos_angle * best_angle,
1163 double (**result_coordinates_xyz)[3],
1164 size_t * result_coordinates_xyz_array_size, size_t ** local_point_ids,
1165 size_t * local_point_ids_array_size, size_t total_num_local_point_ids,
1166 size_t * num_local_point_ids) {
1167
1168 size_t * local_point_ids_ = *local_point_ids;
1169 size_t local_point_ids_array_size_ = *local_point_ids_array_size;
1170 double (*result_coordinates_xyz_)[3];
1171 size_t result_coordinates_xyz_array_size_;
1172 size_t num_local_point_ids_ = *num_local_point_ids;
1173
1174 if (result_coordinates_xyz != NULL) {
1175 result_coordinates_xyz_ = *result_coordinates_xyz;
1176 result_coordinates_xyz_array_size_ = *result_coordinates_xyz_array_size;
1178 result_coordinates_xyz_, result_coordinates_xyz_array_size_,
1179 total_num_local_point_ids + num_local_point_ids_ + num_points);
1180 *result_coordinates_xyz = result_coordinates_xyz_;
1181 *result_coordinates_xyz_array_size = result_coordinates_xyz_array_size_;
1182 result_coordinates_xyz_ += total_num_local_point_ids;
1183 }
1185 local_point_ids_, local_point_ids_array_size_,
1186 total_num_local_point_ids + num_local_point_ids_ + num_points);
1187 *local_point_ids = local_point_ids_;
1188 *local_point_ids_array_size = local_point_ids_array_size_;
1189 local_point_ids_ += total_num_local_point_ids;
1190
1191
1192 // check leaf for results
1193 for (size_t i = 0; i < num_points; ++i) {
1194
1195 struct sin_cos_angle curr_angle =
1197 points[i].coordinates_xyz, point_coordinates_xyz);
1198 int compare = compare_angles(curr_angle, *best_angle);
1199
1200 // if the point is worse than the currently best point
1201 if (compare > 0) continue;
1202
1203 // if we found a better point
1204 if (compare < 0) {
1205
1206 *best_angle = curr_angle;
1207 num_local_point_ids_ = 1;
1208 if (result_coordinates_xyz != NULL) {
1209 result_coordinates_xyz_[0][0] = points[i].coordinates_xyz[0];
1210 result_coordinates_xyz_[0][1] = points[i].coordinates_xyz[1];
1211 result_coordinates_xyz_[0][2] = points[i].coordinates_xyz[2];
1212 }
1213 local_point_ids_[0] = points[i].idx;
1214
1215 // if the point has the same distance
1216 } else {
1217
1218 if (result_coordinates_xyz != NULL) {
1219 result_coordinates_xyz_[num_local_point_ids_][0] =
1220 points[i].coordinates_xyz[0];
1221 result_coordinates_xyz_[num_local_point_ids_][1] =
1222 points[i].coordinates_xyz[1];
1223 result_coordinates_xyz_[num_local_point_ids_][2] =
1224 points[i].coordinates_xyz[2];
1225 }
1226 local_point_ids_[num_local_point_ids_] = points[i].idx;
1227 num_local_point_ids_++;
1228 }
1229 }
1230
1231 *num_local_point_ids = num_local_point_ids_;
1232}
1233
1235 struct bounding_circle * bnd_circle, double (**result_coordinates_xyz)[3],
1236 size_t * result_coordinates_xyz_array_size, size_t ** local_point_ids,
1237 size_t * local_point_ids_array_size, size_t total_num_local_point_ids,
1238 size_t * num_local_point_ids, double * dot_stack,
1239 struct point_sphere_part_node ** node_stack,
1240 int * flags, size_t curr_tree_depth) {
1241
1242 double * point_coordinates_xyz = bnd_circle->base_vector;
1243 struct sin_cos_angle best_angle = bnd_circle->inc_angle;
1244
1245 double dot = dot_stack[curr_tree_depth];
1246 struct point_sphere_part_node * node = node_stack[curr_tree_depth];
1247 int skip_U = flags[curr_tree_depth] & U_FLAG;
1248 int skip_T = flags[curr_tree_depth] & T_FLAG;
1249
1250 do {
1251
1252 if (!skip_U) {
1253
1254 flags[curr_tree_depth] |= U_FLAG;
1255
1256 // angle + inc_angle >= M_PI_2
1257 if ((dot < best_angle.sin) | (best_angle.cos <= 0.0)) {
1258
1259 if (node->flags & U_IS_LEAF) {
1260
1262 (struct point_id_xyz *)(node->U), node->U_size,
1263 point_coordinates_xyz, &best_angle, result_coordinates_xyz,
1264 result_coordinates_xyz_array_size, local_point_ids,
1265 local_point_ids_array_size, total_num_local_point_ids,
1266 num_local_point_ids);
1267
1268 } else {
1269
1270 // traverse down one level
1271 ++curr_tree_depth;
1272 node = (struct point_sphere_part_node *)(node->U);
1273 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1274 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1275 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1276 dot_stack[curr_tree_depth] = dot;
1277 node_stack[curr_tree_depth] = node;
1278 flags[curr_tree_depth] = 0;
1279 // skip_U = 0;
1280 skip_T = 0;
1281 continue;
1282 }
1283 }
1284 }
1285
1286 if (!skip_T) {
1287
1288 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1289
1290 // angle - inc_angle < M_PI_2
1291 if ((dot > - best_angle.sin) || (best_angle.cos <= 0.0)) {
1292
1293 if (node->flags & T_IS_LEAF) {
1294
1296 (struct point_id_xyz *)(node->T), node->T_size,
1297 point_coordinates_xyz, &best_angle, result_coordinates_xyz,
1298 result_coordinates_xyz_array_size, local_point_ids,
1299 local_point_ids_array_size, total_num_local_point_ids,
1300 num_local_point_ids);
1301
1302 } else {
1303
1304 // traverse down one level
1305 ++curr_tree_depth;
1306 node = (struct point_sphere_part_node *)(node->T);
1307 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1308 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1309 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1310 dot_stack[curr_tree_depth] = dot;
1311 node_stack[curr_tree_depth] = node;
1312 flags[curr_tree_depth] = 0;
1313 skip_U = 0;
1314 // skip_T = 0;
1315 continue;
1316 }
1317 }
1318 }
1319
1320 if (curr_tree_depth == 0) break;
1321
1322 // go up one level in the tree
1323
1324 curr_tree_depth--;
1325 dot = dot_stack[curr_tree_depth];
1326 node = node_stack[curr_tree_depth];
1327 skip_U = flags[curr_tree_depth] & U_FLAG;
1328 skip_T = flags[curr_tree_depth] & T_FLAG;
1329
1330 } while (1);
1331
1332 bnd_circle->inc_angle = best_angle;
1333}
1334
1335
1337 struct point_id_xyz * points, size_t num_points, double coordinate_xyz[3],
1338 size_t ** local_point_ids, size_t * local_point_ids_array_size,
1339 double (**result_coordinates_xyz)[3],
1340 size_t * result_coordinates_xyz_array_size,
1341 size_t total_num_local_point_ids, size_t * num_local_point_ids) {
1342
1343 for (size_t i = 0; i < num_points; ++i) {
1344
1345 // if the points are nearly identical
1346 if (points_are_identically(points[i].coordinates_xyz, coordinate_xyz)) {
1347
1348 ENSURE_ARRAY_SIZE(*local_point_ids, *local_point_ids_array_size,
1349 total_num_local_point_ids + 1);
1350 (*local_point_ids)[total_num_local_point_ids] = points[i].idx;
1351 if (result_coordinates_xyz != NULL) {
1352 ENSURE_ARRAY_SIZE(*result_coordinates_xyz,
1353 *result_coordinates_xyz_array_size,
1354 total_num_local_point_ids + 1);
1355 memcpy((*result_coordinates_xyz) + total_num_local_point_ids,
1356 points[i].coordinates_xyz, 3 * sizeof(double));
1357 }
1358 *num_local_point_ids = 1;
1359 return 1;
1360 }
1361 }
1362
1363 return 0;
1364}
1365
1367 size_t num_points,
1368 double (*coordinates_xyz)[3],
1369 double * cos_angles,
1370 double (**result_coordinates_xyz)[3],
1371 size_t * result_coordinates_xyz_array_size,
1372 size_t ** local_point_ids,
1373 size_t * local_point_ids_array_size,
1374 size_t * num_local_point_ids) {
1375
1376 memset(num_local_point_ids, 0, num_points * sizeof(*num_local_point_ids));
1377
1378 if (search == NULL) return;
1379
1380 struct point_sphere_part_node * base_node = &(search->base_node);
1381
1382 size_t total_num_local_point_ids = 0;
1383
1384 double * dot_stack = xmalloc(search->max_tree_depth * sizeof(*dot_stack));
1385 struct point_sphere_part_node ** node_stack =
1386 xmalloc(search->max_tree_depth * sizeof(*node_stack));
1387 int * flags = xmalloc(search->max_tree_depth * sizeof(*flags));
1388
1389 for (size_t i = 0; i < num_points; ++i) {
1390
1391 struct point_sphere_part_node * curr_node = base_node;
1392
1393 double * curr_coordinates_xyz = coordinates_xyz[i];
1394
1395 size_t curr_tree_depth = 0;
1396 struct point_id_xyz * points = NULL;
1397 size_t curr_num_points = 0;
1398
1399 // get the matching leaf for the current point
1400 do {
1401
1402 double dot = curr_node->gc_norm_vector[0]*curr_coordinates_xyz[0] +
1403 curr_node->gc_norm_vector[1]*curr_coordinates_xyz[1] +
1404 curr_node->gc_norm_vector[2]*curr_coordinates_xyz[2];
1405
1406 dot_stack[curr_tree_depth] = dot;
1407 node_stack[curr_tree_depth] = curr_node;
1408 flags[curr_tree_depth] = 0;
1409
1410 // angle > M_PI_2
1411 if (dot < yac_angle_tol) {
1412
1413 flags[curr_tree_depth] = U_FLAG;
1414
1415 if (curr_node->flags & U_IS_LEAF) {
1416 if (curr_node->U_size > 0) {
1417 points = (struct point_id_xyz*)(curr_node->U);
1418 curr_num_points = curr_node->U_size;
1419 break;
1420 } else {
1421 flags[curr_tree_depth] = T_FLAG;
1422 YAC_ASSERT(
1423 curr_node->flags & T_IS_LEAF,
1424 "if one branch is empty, the other has to be a leaf");
1425 points = (struct point_id_xyz*)(curr_node->T);
1426 curr_num_points = curr_node->T_size;
1427 break;
1428 }
1429 } else curr_node = curr_node->U;
1430
1431 // angle < M_PI_2
1432 } else if (dot > -yac_angle_tol) {
1433
1434 flags[curr_tree_depth] = T_FLAG;
1435
1436 if (curr_node->flags & T_IS_LEAF) {
1437 if (curr_node->T_size > 0) {
1438 points = (struct point_id_xyz*)(curr_node->T);
1439 curr_num_points = curr_node->T_size;
1440 break;
1441 } else {
1442 flags[curr_tree_depth] = U_FLAG;
1443 YAC_ASSERT(
1444 curr_node->flags & U_IS_LEAF,
1445 "if one branch is empty, the other has to be a leaf");
1446 points = (struct point_id_xyz*)(curr_node->U);
1447 curr_num_points = curr_node->U_size;
1448 break;
1449 }
1450 } else curr_node = curr_node->T;
1451 }
1452
1453 curr_tree_depth++;
1454 } while (1);
1455
1456 // if we do not have to do a finer search
1458 points, curr_num_points, curr_coordinates_xyz, local_point_ids,
1459 local_point_ids_array_size, result_coordinates_xyz,
1460 result_coordinates_xyz_array_size, total_num_local_point_ids,
1461 num_local_point_ids + i)) {
1462
1463 if (cos_angles != NULL) cos_angles[i] = 1.0;
1464
1465 } else {
1466
1467 struct bounding_circle bnd_circle;
1468 bnd_circle.base_vector[0] = curr_coordinates_xyz[0];
1469 bnd_circle.base_vector[1] = curr_coordinates_xyz[1];
1470 bnd_circle.base_vector[2] = curr_coordinates_xyz[2];
1471 bnd_circle.inc_angle = SIN_COS_M_PI;
1472 bnd_circle.sq_crd = DBL_MAX;
1473
1475 points, curr_num_points, curr_coordinates_xyz, &bnd_circle.inc_angle,
1476 result_coordinates_xyz, result_coordinates_xyz_array_size,
1477 local_point_ids, local_point_ids_array_size, total_num_local_point_ids,
1478 num_local_point_ids + i);
1479
1480 // get best result points
1482 &bnd_circle, result_coordinates_xyz, result_coordinates_xyz_array_size,
1483 local_point_ids, local_point_ids_array_size, total_num_local_point_ids,
1484 num_local_point_ids + i, dot_stack, node_stack, flags, curr_tree_depth);
1485
1486 if (cos_angles != NULL) cos_angles[i] = bnd_circle.inc_angle.cos;
1487 }
1488
1489 total_num_local_point_ids += num_local_point_ids[i];
1490 }
1491
1492 free(flags);
1493 free(node_stack);
1494 free(dot_stack);
1495}
1496
1497static inline int compare_point_id_xyz_angle(const void * a, const void * b) {
1498
1499 const struct point_id_xyz_angle * p_a = (const struct point_id_xyz_angle *)a;
1500 const struct point_id_xyz_angle * p_b = (const struct point_id_xyz_angle *)b;
1501
1502 int ret = (p_a->cos_angle < p_b->cos_angle) -
1503 (p_a->cos_angle > p_b->cos_angle);
1504
1505 if (ret != 0) return ret;
1506
1507 return (p_a->point.idx > p_b->point.idx) - (p_a->point.idx < p_b->point.idx);
1508}
1509
1511 size_t n, struct point_id_xyz * points, size_t num_points,
1512 double * point_coordinates_xyz, struct point_id_xyz_angle ** results,
1513 size_t * results_array_size) {
1514
1515 assert(num_points > 0);
1516
1517 ENSURE_ARRAY_SIZE(*results, *results_array_size, num_points);
1518 struct point_id_xyz_angle * results_ = *results;
1519
1520#ifdef __NEC__
1521// vectorization of the following loop leads to failues of
1522//
1523// test_couple_config_parallel1
1524// test_interp_method_nnn_parallel
1525// test_interp_method_hcsbb_parallel
1526//
1527// with NEC compiler when CFLAGS='-O2'
1528#pragma _NEC novector
1529#endif
1530 for (size_t i = 0; i < num_points; ++i) {
1531
1532 results_[i].point = points[i];
1533 results_[i].cos_angle = clamp_abs_one(
1534 points[i].coordinates_xyz[0] * point_coordinates_xyz[0] +
1535 points[i].coordinates_xyz[1] * point_coordinates_xyz[1] +
1536 points[i].coordinates_xyz[2] * point_coordinates_xyz[2]);
1537 }
1538
1539 qsort(results_, num_points, sizeof(*results_), compare_point_id_xyz_angle);
1540
1541 if (num_points <= n) return num_points;
1542
1543 size_t num_results;
1544 double min_cos_angle = results_[n - 1].cos_angle;
1545
1546 for (num_results = n;
1547 (num_results < num_points) &&
1548 !(fabs(min_cos_angle - results_[num_results].cos_angle) > 0.0);
1549 ++num_results);
1550
1551 return num_results;
1552}
1553
1554static inline struct sin_cos_angle check_leaf_NNN(
1555 size_t n, double * point_coordinates_xyz,
1556 struct point_id_xyz * points, size_t num_points,
1557 struct point_id_xyz_angle ** results, size_t * results_array_size,
1558 size_t * num_results, struct sin_cos_angle curr_angle) {
1559
1560 size_t num_results_ = *num_results;
1561 ENSURE_ARRAY_SIZE(*results, *results_array_size, num_results_ + num_points);
1562 struct point_id_xyz_angle * results_ = *results;
1563
1564 int flag = 0;
1565
1566 double min_cos_angle = results_[num_results_-1].cos_angle;
1567
1568 // check leaf for results
1569 for (size_t i = 0; i < num_points; ++i) {
1570
1571 double curr_cos_angle =
1572 points[i].coordinates_xyz[0] * point_coordinates_xyz[0] +
1573 points[i].coordinates_xyz[1] * point_coordinates_xyz[1] +
1574 points[i].coordinates_xyz[2] * point_coordinates_xyz[2];
1575
1576 // if the point is worse than the currently best point
1577 if (curr_cos_angle < min_cos_angle) continue;
1578
1579 struct point_id_xyz_angle point =
1580 {.point = points[i], .cos_angle = curr_cos_angle};
1581
1582 // insert point
1583 size_t j;
1584 for (j = 0; j < num_results_; ++j) {
1585
1587 &point, results_ + num_results_ - j - 1) < 0) {
1588 results_[num_results_ - j] = results_[num_results_ - j - 1];
1589 } else {
1590 break;
1591 }
1592 }
1593 results_[num_results_ - j] = point;
1594
1595 ++num_results_;
1596 flag = 1;
1597 }
1598
1599 if (flag) {
1600
1601 if (num_results_ > n) {
1602
1603 size_t new_num_results;
1604 min_cos_angle = results_[n - 1].cos_angle;
1605
1606 for (new_num_results = n;
1607 (new_num_results < num_results_) &&
1608 !(fabs(min_cos_angle - results_[new_num_results].cos_angle) > 0.0);
1609 ++new_num_results);
1610 num_results_ = new_num_results;
1611 }
1612 *num_results = num_results_;
1613
1614 return
1616 results_[num_results_-1].point.coordinates_xyz, point_coordinates_xyz);
1617 } else return curr_angle;
1618}
1619
1621 size_t n, double * point_coordinates_xyz,
1622 struct point_id_xyz_angle ** results, size_t * results_array_size,
1623 size_t * num_results, double * dot_stack,
1624 struct point_sphere_part_node ** node_stack, int * flags,
1625 size_t curr_tree_depth) {
1626
1627 struct sin_cos_angle angle =
1629 (*results)[(*num_results)-1].point.coordinates_xyz,
1630 point_coordinates_xyz);
1631
1632 // if we have already found at least n exactly matching points
1633 if ((*num_results >= n) && (angle.sin <= yac_angle_tol)) return;
1634
1635 double dot = dot_stack[curr_tree_depth];
1636 struct point_sphere_part_node * node = node_stack[curr_tree_depth];
1637 int skip_U = flags[curr_tree_depth] & U_FLAG;
1638 int skip_T = flags[curr_tree_depth] & T_FLAG;
1639
1640 do {
1641
1642 if (!skip_U) {
1643
1644 flags[curr_tree_depth] |= U_FLAG;
1645
1646 // angle + inc_angle >= M_PI_2
1647 if ((dot < angle.sin) | (angle.cos <= 0.0)) {
1648
1649 if (node->flags & U_IS_LEAF) {
1650
1651 angle = check_leaf_NNN(
1652 n, point_coordinates_xyz, (struct point_id_xyz *)(node->U),
1653 node->U_size, results, results_array_size, num_results, angle);
1654
1655 } else {
1656
1657 // traverse down one level
1658 ++curr_tree_depth;
1659 node = (struct point_sphere_part_node *)(node->U);
1660 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1661 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1662 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1663 dot_stack[curr_tree_depth] = dot;
1664 node_stack[curr_tree_depth] = node;
1665 flags[curr_tree_depth] = 0;
1666 // skip_U = 0;
1667 skip_T = 0;
1668 continue;
1669 }
1670 }
1671 }
1672
1673 if (!skip_T) {
1674
1675 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1676
1677 // angle - inc_angle < M_PI_2
1678 if ((dot > - angle.sin) || (angle.cos <= 0.0)) {
1679
1680 if (node->flags & T_IS_LEAF) {
1681
1682 angle = check_leaf_NNN(
1683 n, point_coordinates_xyz, (struct point_id_xyz *)(node->T),
1684 node->T_size, results, results_array_size, num_results, angle);
1685
1686 } else {
1687
1688 // traverse down one level
1689 ++curr_tree_depth;
1690 node = (struct point_sphere_part_node *)(node->T);
1691 dot = node->gc_norm_vector[0] * point_coordinates_xyz[0] +
1692 node->gc_norm_vector[1] * point_coordinates_xyz[1] +
1693 node->gc_norm_vector[2] * point_coordinates_xyz[2];
1694 dot_stack[curr_tree_depth] = dot;
1695 node_stack[curr_tree_depth] = node;
1696 flags[curr_tree_depth] = 0;
1697 skip_U = 0;
1698 // skip_T = 0;
1699 continue;
1700 }
1701 }
1702 }
1703
1704 if (curr_tree_depth == 0) break;
1705
1706 // go up one level in the tree
1707
1708 curr_tree_depth--;
1709 dot = dot_stack[curr_tree_depth];
1710 node = node_stack[curr_tree_depth];
1711 skip_U = flags[curr_tree_depth] & U_FLAG;
1712 skip_T = flags[curr_tree_depth] & T_FLAG;
1713
1714 } while (1);
1715}
1716
1718 size_t num_points,
1719 double (*coordinates_xyz)[3], size_t n,
1720 double ** cos_angles,
1721 size_t * cos_angles_array_size,
1722 double (**result_coordinates_xyz)[3],
1723 size_t * result_coordinates_xyz_array_size,
1724 size_t ** local_point_ids,
1725 size_t * local_point_ids_array_size,
1726 size_t * num_local_point_ids) {
1727
1728 if (num_points == 0) return;
1729
1730 if (cos_angles != NULL)
1731 ENSURE_ARRAY_SIZE(*cos_angles, *cos_angles_array_size, num_points * n);
1732
1733 if (n == 1) {
1735 search, num_points, coordinates_xyz, (cos_angles!=NULL)?*cos_angles:NULL,
1736 result_coordinates_xyz, result_coordinates_xyz_array_size,
1737 local_point_ids, local_point_ids_array_size, num_local_point_ids);
1738
1739 size_t total_num_local_points = 0;
1740 for (size_t i = 0; i < num_points; ++i)
1741 total_num_local_points += num_local_point_ids[i];
1742
1743 if ((cos_angles != NULL) && (total_num_local_points > num_points)) {
1744
1745 ENSURE_ARRAY_SIZE(*cos_angles, *cos_angles_array_size,
1746 total_num_local_points);
1747
1748 for (size_t i = num_points - 1, offset = total_num_local_points - 1;
1749 i != (size_t)-1; i--) {
1750
1751 for (size_t j = 0; j < num_local_point_ids[i]; ++j, --offset)
1752 (*cos_angles)[offset] = (*cos_angles)[i];
1753 }
1754 }
1755 return;
1756 }
1757
1758
1759 if (search == NULL) {
1760 memset(num_local_point_ids, 0, num_points * sizeof(*num_local_point_ids));
1761 return;
1762 }
1763
1764 struct point_sphere_part_node * base_node = &(search->base_node);
1765
1766 size_t total_num_local_point_ids = 0;
1767
1768 double * dot_stack = xmalloc(search->max_tree_depth * sizeof(*dot_stack));
1769 struct point_sphere_part_node ** node_stack =
1770 xmalloc(search->max_tree_depth * sizeof(*node_stack));
1771 int * flags = xmalloc(search->max_tree_depth * sizeof(*flags));
1772
1773 struct point_id_xyz_angle * results = NULL;
1774 size_t results_array_size = 0;
1775
1776 for (size_t i = 0; i < num_points; ++i) {
1777
1778 struct point_sphere_part_node * curr_node = base_node;
1779
1780 double * curr_coordinates_xyz = coordinates_xyz[i];
1781
1782 size_t curr_tree_depth = 0;
1783 struct point_id_xyz * points = search->points;
1784 size_t curr_num_points = 0;
1785
1786 // get the matching leaf for the current point
1787 do {
1788
1789 double dot = curr_node->gc_norm_vector[0]*curr_coordinates_xyz[0] +
1790 curr_node->gc_norm_vector[1]*curr_coordinates_xyz[1] +
1791 curr_node->gc_norm_vector[2]*curr_coordinates_xyz[2];
1792
1793 dot_stack[curr_tree_depth] = dot;
1794 node_stack[curr_tree_depth] = curr_node;
1795 flags[curr_tree_depth] = 0;
1796
1797 // angle >= M_PI_2
1798 if (dot <= 0.0) {
1799
1800 if (curr_node->U_size < n) {
1801
1802 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1803 curr_num_points = curr_node->U_size + curr_node->T_size;
1804 break;
1805 } else if (curr_node->flags & U_IS_LEAF) {
1806
1807 flags[curr_tree_depth] = U_FLAG;
1808 curr_num_points = curr_node->U_size;
1809 break;
1810 } else {
1811
1812 flags[curr_tree_depth] = U_FLAG;
1813 curr_node = curr_node->U;
1814 }
1815
1816 } else {
1817
1818 if (curr_node->T_size < n) {
1819
1820 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1821 curr_num_points = curr_node->U_size + curr_node->T_size;
1822 break;
1823 } else if (curr_node->flags & T_IS_LEAF) {
1824
1825 points += curr_node->U_size;
1826 flags[curr_tree_depth] = T_FLAG;
1827 curr_num_points = curr_node->T_size;
1828 break;
1829 } else {
1830
1831 points += curr_node->U_size;
1832 flags[curr_tree_depth] = T_FLAG;
1833 curr_node = curr_node->T;
1834 }
1835 }
1836
1837 curr_tree_depth++;
1838 } while (1);
1839
1840 assert(curr_num_points > 0);
1841
1842 size_t num_results =
1844 n, points, curr_num_points, curr_coordinates_xyz,
1845 &results, &results_array_size);
1846
1847 // do a detailed search
1849 n, curr_coordinates_xyz, &results, &results_array_size, &num_results,
1850 dot_stack, node_stack, flags, curr_tree_depth);
1851
1852 // extract the results
1853 ENSURE_ARRAY_SIZE(*local_point_ids, *local_point_ids_array_size,
1854 total_num_local_point_ids + num_results);
1855 size_t * local_point_ids_ =
1856 (*local_point_ids) + total_num_local_point_ids;
1857 double * cos_angles_;
1858 if (cos_angles != NULL) {
1859 ENSURE_ARRAY_SIZE(*cos_angles, *cos_angles_array_size,
1860 total_num_local_point_ids + num_results);
1861 cos_angles_ = (*cos_angles) + total_num_local_point_ids;
1862 } else {
1863 cos_angles_ = NULL;
1864 }
1865 double (*result_coordinates_xyz_)[3];
1866 if (result_coordinates_xyz != NULL) {
1867 ENSURE_ARRAY_SIZE(*result_coordinates_xyz,
1868 *result_coordinates_xyz_array_size,
1869 total_num_local_point_ids + num_results);
1870 result_coordinates_xyz_ =
1871 (*result_coordinates_xyz) + total_num_local_point_ids;
1872 } else {
1873 result_coordinates_xyz_ = NULL;
1874 }
1875
1876 for (size_t j = 0; j < num_results; ++j) {
1877
1878 local_point_ids_[j] = results[j].point.idx;
1879 if (cos_angles_ != NULL) cos_angles_[j] = results[j].cos_angle;
1880 if (result_coordinates_xyz_ != NULL) {
1881 result_coordinates_xyz_[j][0] = results[j].point.coordinates_xyz[0];
1882 result_coordinates_xyz_[j][1] = results[j].point.coordinates_xyz[1];
1883 result_coordinates_xyz_[j][2] = results[j].point.coordinates_xyz[2];
1884 }
1885 }
1886
1887 num_local_point_ids[i] = num_results;
1888 total_num_local_point_ids += num_results;
1889 }
1890
1891 free(results);
1892 free(flags);
1893 free(node_stack);
1894 free(dot_stack);
1895}
1896
1898 struct point_sphere_part_search * search,
1899 size_t num_bnd_circles, struct bounding_circle * bnd_circles,
1900 size_t n, size_t ** local_point_ids, size_t * local_point_ids_array_size,
1901 size_t * num_local_point_ids) {
1902
1903 if (num_bnd_circles == 0) return;
1904
1905 if (search == NULL) {
1906 memset(
1907 num_local_point_ids, 0, num_bnd_circles * sizeof(*num_local_point_ids));
1908 return;
1909 }
1910
1911 struct point_sphere_part_node * base_node = &(search->base_node);
1912
1913 size_t total_num_local_point_ids = 0;
1914
1915 double * dot_stack = xmalloc(search->max_tree_depth * sizeof(*dot_stack));
1916 struct point_sphere_part_node ** node_stack =
1917 xmalloc(search->max_tree_depth * sizeof(*node_stack));
1918 int * flags = xmalloc(search->max_tree_depth * sizeof(*flags));
1919
1920 struct point_id_xyz_angle * results = NULL;
1921 size_t results_array_size = 0;
1922
1923 for (size_t i = 0; i < num_bnd_circles; ++i) {
1924
1925 struct point_sphere_part_node * curr_node = base_node;
1926
1927 double * curr_coordinates_xyz = bnd_circles[i].base_vector;
1928
1929 size_t curr_tree_depth = 0;
1930 struct point_id_xyz * points = search->points;
1931 size_t curr_num_points = 0;
1932
1933 // get the matching leaf for the current point
1934 do {
1935
1936 double dot = curr_node->gc_norm_vector[0]*curr_coordinates_xyz[0] +
1937 curr_node->gc_norm_vector[1]*curr_coordinates_xyz[1] +
1938 curr_node->gc_norm_vector[2]*curr_coordinates_xyz[2];
1939
1940 dot_stack[curr_tree_depth] = dot;
1941 node_stack[curr_tree_depth] = curr_node;
1942 flags[curr_tree_depth] = 0;
1943
1944 // angle >= M_PI_2
1945 if (dot <= 0.0) {
1946
1947 if (curr_node->U_size < n) {
1948
1949 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1950 curr_num_points = curr_node->U_size + curr_node->T_size;
1951 break;
1952 } else if (curr_node->flags & U_IS_LEAF) {
1953
1954 flags[curr_tree_depth] = U_FLAG;
1955 curr_num_points = curr_node->U_size;
1956 break;
1957 } else {
1958
1959 flags[curr_tree_depth] = U_FLAG;
1960 curr_node = curr_node->U;
1961 }
1962
1963 } else {
1964
1965 if (curr_node->T_size < n) {
1966
1967 flags[curr_tree_depth] = U_FLAG + T_FLAG;
1968 curr_num_points = curr_node->U_size + curr_node->T_size;
1969 break;
1970 } else if (curr_node->flags & T_IS_LEAF) {
1971
1972 points += curr_node->U_size;
1973 flags[curr_tree_depth] = T_FLAG;
1974 curr_num_points = curr_node->T_size;
1975 break;
1976 } else {
1977
1978 points += curr_node->U_size;
1979 flags[curr_tree_depth] = T_FLAG;
1980 curr_node = curr_node->T;
1981 }
1982 }
1983
1984 curr_tree_depth++;
1985 } while (1);
1986
1987 YAC_ASSERT(curr_num_points > 0, "insufficient number of points");
1988
1989 size_t num_results =
1991 n, points, curr_num_points, curr_coordinates_xyz,
1992 &results, &results_array_size);
1993
1994 // do a detailed search
1996 n, curr_coordinates_xyz, &results, &results_array_size, &num_results,
1997 dot_stack, node_stack, flags, curr_tree_depth);
1998
1999 for (; num_results > 0; --num_results)
2000 if (results[num_results-1].cos_angle >= bnd_circles[i].inc_angle.cos)
2001 break;
2002
2003 // extract the results
2004 ENSURE_ARRAY_SIZE(*local_point_ids, *local_point_ids_array_size,
2005 total_num_local_point_ids + num_results);
2006 size_t * local_point_ids_ =
2007 (*local_point_ids) + total_num_local_point_ids;
2008
2009 for (size_t j = 0; j < num_results; ++j)
2010 local_point_ids_[j] = results[j].point.idx;
2011
2012 num_local_point_ids[i] = num_results;
2013 total_num_local_point_ids += num_results;
2014 }
2015
2016 free(results);
2017 free(flags);
2018 free(node_stack);
2019 free(dot_stack);
2020}
2021
2022static int compare_angles_(void const * a, void const * b) {
2023 struct sin_cos_angle * a_ = (struct sin_cos_angle *)a;
2024 struct sin_cos_angle * b_ = (struct sin_cos_angle *)b;
2025 return compare_angles(*a_, *b_);
2026}
2027
2029 struct point_sphere_part_search * search,
2030 size_t num_points, yac_coordinate_pointer coordinates_xyz,
2031 size_t n, struct sin_cos_angle * angles) {
2032
2033 YAC_ASSERT(
2034 search != NULL,
2035 "ERRROR(yac_point_sphere_part_search_NNN_ubound): "
2036 "invalid point sphere part search (has to be != NULL)");
2037 YAC_ASSERT(n > 0, "invalid n (has to be > 0)")
2038
2039 struct sin_cos_angle * temp_angles = NULL;
2040 size_t temp_angles_array_size = 0;
2041
2042 struct point_sphere_part_node * base_node = &(search->base_node);
2043
2044 for (size_t i = 0; i < num_points; ++i) {
2045
2046 struct point_sphere_part_node * curr_node = base_node;
2047
2048 double * curr_coordinates_xyz = coordinates_xyz[i];
2049
2050 struct point_id_xyz * points = search->points;
2051 size_t curr_num_points = 0;
2052
2053 // get the matching leaf for the current point
2054 do {
2055
2056 double dot = curr_node->gc_norm_vector[0]*curr_coordinates_xyz[0] +
2057 curr_node->gc_norm_vector[1]*curr_coordinates_xyz[1] +
2058 curr_node->gc_norm_vector[2]*curr_coordinates_xyz[2];
2059
2060 // angle >= M_PI_2
2061 if (dot <= 0.0) {
2062
2063 if (curr_node->U_size < n) {
2064
2065 curr_num_points = curr_node->U_size + curr_node->T_size;
2066 break;
2067 } else if (curr_node->flags & U_IS_LEAF) {
2068
2069 curr_num_points = curr_node->U_size;
2070 break;
2071 } else {
2072
2073 curr_node = curr_node->U;
2074 }
2075
2076 } else {
2077
2078 if (curr_node->T_size < n) {
2079
2080 curr_num_points = curr_node->U_size + curr_node->T_size;
2081 break;
2082 } else if (curr_node->flags & T_IS_LEAF) {
2083
2084 points += curr_node->U_size;
2085 curr_num_points = curr_node->T_size;
2086 break;
2087 } else {
2088
2089 points += curr_node->U_size;
2090 curr_node = curr_node->T;
2091 }
2092 }
2093 } while (1);
2094
2095 YAC_ASSERT(
2096 curr_num_points >= n, "failed to find a sufficient number of points");
2097
2098 // search of the closest "n" points in the current
2099 // list of points
2100
2101 if (n == 1) {
2102
2103 struct sin_cos_angle best_angle =
2105 curr_coordinates_xyz, points[0].coordinates_xyz);
2106 for (size_t j = 1; j < curr_num_points; ++j) {
2107 struct sin_cos_angle curr_angle =
2109 curr_coordinates_xyz, points[j].coordinates_xyz);
2110 if (compare_angles(best_angle, curr_angle) > 0)
2111 best_angle = curr_angle;
2112 }
2113 angles[i] = best_angle;
2114
2115 } else {
2116
2117 // compute the angles for all current points
2119 temp_angles, temp_angles_array_size, curr_num_points);
2120 for (size_t j = 0; j < curr_num_points; ++j)
2121 temp_angles[j] =
2123 curr_coordinates_xyz, points[j].coordinates_xyz);
2124
2125 qsort(
2126 temp_angles, curr_num_points, sizeof(*temp_angles),
2128
2129 angles[i] = temp_angles[n-1];
2130 }
2131 }
2132
2133 free(temp_angles);
2134}
2135
2136// recursive helper function to search for all points within a bounding circle
2138 struct point_sphere_part_node const * node,
2139 struct point_id_xyz const * points,
2140 struct bounding_circle const * bnd_circle,
2141 size_t ** local_point_ids, size_t * local_point_ids_array_size,
2142 size_t * num_local_point_ids) {
2143
2144 double const * search_coord = bnd_circle->base_vector;
2145 struct sin_cos_angle const inc_angle = bnd_circle->inc_angle;
2146
2147 // Compute cosine of the angle between base vector of bounding circle and
2148 // norm vector of current sphere part split plane.
2149 // Since the split plane is at an angle of 90 degree to the norm vector, the
2150 // result is also the sine of the angle between the base vector and the split
2151 // plane.
2152 double dot = node->gc_norm_vector[0] * search_coord[0] +
2153 node->gc_norm_vector[1] * search_coord[1] +
2154 node->gc_norm_vector[2] * search_coord[2];
2155
2156 // The bounding circle may overlap with the U branch if:
2157 // * base vector is on the U half of the sphere
2158 // -> dot < 0
2159 // * base vector is on the T half of the sphere but the bounding circle
2160 // overlaps with the U half
2161 // -> dot < sin(inc_angle)
2162 if (dot < inc_angle.sin + yac_angle_tol) {
2163
2164 if (node->flags & U_IS_LEAF) {
2165
2166 ENSURE_ARRAY_SIZE(*local_point_ids, *local_point_ids_array_size,
2167 *num_local_point_ids + node->U_size);
2168
2169 // check all points in the U leaf
2170 struct point_id_xyz * leaf_points = (struct point_id_xyz *)(node->U);
2171 for (size_t i = 0; i < node->U_size; ++i) {
2172 struct sin_cos_angle angle =
2173 get_vector_angle_2(search_coord, leaf_points[i].coordinates_xyz);
2174 if (compare_angles(angle, inc_angle) < 1) {
2175 (*local_point_ids)[*num_local_point_ids] = leaf_points[i].idx;
2176 (*num_local_point_ids)++;
2177 }
2178 }
2179 } else {
2180 // recurse into U branch
2182 node->U, points, bnd_circle,
2183 local_point_ids, local_point_ids_array_size, num_local_point_ids);
2184 }
2185 }
2186
2187 // The bounding circle may overlap with the T branch if:
2188 // * base vector is on the T half of the sphere
2189 // -> dot > 0
2190 // * base vector is on the U half of the sphere but the bounding circle
2191 // overlaps with the T half
2192 // -> dot > - sin(inc_angle)
2193 if (dot > - (inc_angle.sin + yac_angle_tol)) {
2194
2195 if (node->flags & T_IS_LEAF) {
2196
2197 ENSURE_ARRAY_SIZE(*local_point_ids, *local_point_ids_array_size,
2198 *num_local_point_ids + node->T_size);
2199
2200 // check all points in the T leaf
2201 struct point_id_xyz * leaf_points =
2202 (struct point_id_xyz *)(node->T);
2203 for (size_t i = 0; i < node->T_size; ++i) {
2204 struct sin_cos_angle angle =
2205 get_vector_angle_2(search_coord, leaf_points[i].coordinates_xyz);
2206 if (compare_angles(angle, inc_angle) < 1) {
2207 (*local_point_ids)[*num_local_point_ids] = leaf_points[i].idx;
2208 (*num_local_point_ids)++;
2209 }
2210 }
2211 } else {
2212 // recurse into T branch
2214 node->T, points + node->U_size, bnd_circle,
2215 local_point_ids, local_point_ids_array_size, num_local_point_ids);
2216 }
2217 }
2218}
2219
2221 struct point_sphere_part_search * search,
2222 size_t num_bnd_circles, const_bounding_circle_pointer bnd_circles,
2223 size_t ** local_point_ids, size_t * local_point_ids_array_size,
2224 size_t * num_local_point_ids) {
2225
2226 if (num_bnd_circles == 0) return;
2227
2228 if (search == NULL) {
2229 memset(
2230 num_local_point_ids, 0, num_bnd_circles * sizeof(*num_local_point_ids));
2231 return;
2232 }
2233
2234 struct point_sphere_part_node const * base_node = &(search->base_node);
2235 struct point_id_xyz const * points = search->points;
2236
2237 size_t total_num_local_point_ids = 0;
2238
2239 // for all bounding circles
2240 for (size_t i = 0; i < num_bnd_circles; ++i) {
2241
2242 size_t const start_count = total_num_local_point_ids;
2243
2244 // get local ids of all locally stored points that are located within the
2245 // current bounding circle
2247 base_node, points, &bnd_circles[i],
2248 local_point_ids, local_point_ids_array_size, &total_num_local_point_ids);
2249
2250 // compute the number of added local point ids
2251 num_local_point_ids[i] = total_num_local_point_ids - start_count;
2252 }
2253}
2254
2255static void search_point(struct sphere_part_node * node,
2256 double point[],
2257 size_t ** overlap_cells,
2258 size_t * overlap_cells_array_size,
2259 size_t * num_overlap_cells,
2260 struct overlaps * search_interval_tree_buffer,
2261 double prev_gc_norm_vector[]) {
2262
2263 double dot = point[0] * node->gc_norm_vector[0] +
2264 point[1] * node->gc_norm_vector[1] +
2265 point[2] * node->gc_norm_vector[2];
2266
2267 // angle < M_PI_2
2268 if (dot > -yac_angle_tol) {
2269
2270 if (node->flags & T_IS_LEAF) {
2271
2272 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
2273 *num_overlap_cells + node->T_size);
2274 memcpy(*overlap_cells + *num_overlap_cells, node->T,
2275 node->T_size * sizeof(**overlap_cells));
2276 *num_overlap_cells += node->T_size;
2277
2278 } else {
2279 search_point(node->T, point, overlap_cells,
2280 overlap_cells_array_size, num_overlap_cells,
2281 search_interval_tree_buffer, node->gc_norm_vector);
2282 }
2283 }
2284
2285 // angle > M_PI_2
2286 if (dot < yac_angle_tol) {
2287
2288 if (node->flags & U_IS_LEAF) {
2289
2290 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
2291 *num_overlap_cells + node->U_size);
2292 memcpy(*overlap_cells + *num_overlap_cells, node->U,
2293 node->U_size * sizeof(**overlap_cells));
2294 *num_overlap_cells += node->U_size;
2295
2296 } else {
2297 search_point(node->U, point, overlap_cells,
2298 overlap_cells_array_size, num_overlap_cells,
2299 search_interval_tree_buffer, node->gc_norm_vector);
2300 }
2301 }
2302
2303 // fabs(angle - M_PI_2) <= (node->I_angle)
2304 // fabs(cos(angle)) <= sin(node->I_angle)
2305 if (fabs(dot) <= node->I_angle.sin) {
2306
2307 if (node->flags & I_IS_INTERVAL_TREE) {
2308
2309 // project the point onto the current great circle
2310 double GCp[3], bVp[3];
2311 crossproduct_kahan(node->gc_norm_vector, point, GCp);
2312 crossproduct_kahan(GCp, node->gc_norm_vector, bVp);
2313
2314 struct interval search_interval;
2315 // if the projected point does not coincide with the norm vector of
2316 // the plane through the great circle
2317 if ((fabs(bVp[0]) > 1e-9) || (fabs(bVp[1]) > 1e-9) ||
2318 (fabs(bVp[2]) > 1e-9)) {
2319 normalise_vector(bVp);
2320 double base_angle = get_vector_angle(bVp, prev_gc_norm_vector);
2321 search_interval.left=base_angle;
2322 search_interval.right=base_angle;
2323 } else {
2324 search_interval.left = -M_PI;
2325 search_interval.right = M_PI;
2326 }
2327
2328 search_interval_tree_buffer->num_overlaps = 0;
2329
2331 search_interval, search_interval_tree_buffer);
2332
2333 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
2334 *num_overlap_cells +
2335 search_interval_tree_buffer->num_overlaps);
2336
2337 for (size_t i = 0; i < search_interval_tree_buffer->num_overlaps;
2338 ++i) {
2339 (*overlap_cells)[(*num_overlap_cells)+i] =
2340 node->I.ivt.head_node[
2341 search_interval_tree_buffer->overlap_iv[i]].value;
2342 }
2343
2344 *num_overlap_cells += search_interval_tree_buffer->num_overlaps;
2345
2346 } else {
2347
2348 ENSURE_ARRAY_SIZE(*overlap_cells, *overlap_cells_array_size,
2349 *num_overlap_cells + node->I_size);
2350 memcpy(*overlap_cells + *num_overlap_cells, node->I.list,
2351 node->I_size * sizeof(**overlap_cells));
2352 *num_overlap_cells += node->I_size;
2353 }
2354 }
2355}
2356
2358 struct bnd_sphere_part_search * search, yac_coordinate_pointer coordinates_xyz,
2359 size_t count, size_t ** cells, size_t * num_cells_per_coordinate) {
2360
2361 struct sphere_part_node * base_node = &(search->base_node);
2362
2363 size_t * temp_search_results = NULL;
2364 size_t temp_search_results_array_size = 0;
2365 size_t num_temp_search_results = 0;
2366
2367 struct overlaps search_interval_tree_buffer = {0, 0, NULL};
2368
2369 memset(
2370 num_cells_per_coordinate, 0, count * sizeof(*num_cells_per_coordinate));
2371 size_t * cells_ = NULL;
2372 size_t cells_array_size = 0;
2373 size_t num_cells = 0;
2374 ENSURE_ARRAY_SIZE(cells_, cells_array_size, count);
2375
2376 for (size_t i = 0; i < count; ++i) {
2377
2378 double * curr_coordinates_xyz = &(coordinates_xyz[i][0]);
2379
2380 num_temp_search_results = 0;
2381
2382 double gc_norm_vector[3] = {0.0,0.0,1.0};
2383
2384 search_point(base_node, curr_coordinates_xyz, &temp_search_results,
2385 &temp_search_results_array_size, &num_temp_search_results,
2386 &search_interval_tree_buffer, gc_norm_vector);
2387
2389 cells_, cells_array_size, num_cells + num_temp_search_results);
2390
2391 memcpy(cells_ + num_cells, temp_search_results,
2392 num_temp_search_results * sizeof(*temp_search_results));
2393 num_cells_per_coordinate[i] = num_temp_search_results;
2394 num_cells += num_temp_search_results;
2395 }
2396
2397 free(temp_search_results);
2398 free(search_interval_tree_buffer.overlap_iv);
2399
2400 *cells = xrealloc(cells_, num_cells * sizeof(*cells_));
2401}
2402
2404 struct bnd_sphere_part_search * search, struct bounding_circle * bnd_circles,
2405 size_t count, size_t ** cells, size_t * num_cells_per_bnd_circle) {
2406
2407 struct sphere_part_node * base_node = &(search->base_node);
2408
2409 size_t * temp_search_results = NULL;
2410 size_t temp_search_results_array_size = 0;
2411 size_t num_temp_search_results = 0;
2412
2413 struct overlaps search_interval_tree_buffer = {0, 0, NULL};
2414
2415 memset(
2416 num_cells_per_bnd_circle, 0, count * sizeof(*num_cells_per_bnd_circle));
2417 size_t * cells_ = NULL;
2418 size_t cells_array_size = 0;
2419 size_t num_cells = 0;
2420 ENSURE_ARRAY_SIZE(cells_, cells_array_size, count);
2421
2422 for (size_t i = 0; i < count; ++i) {
2423
2424 num_temp_search_results = 0;
2425
2426 double gc_norm_vector[3] = {0.0,0.0,1.0};
2427
2428 search_bnd_circle(base_node, bnd_circles[i], &temp_search_results,
2429 &temp_search_results_array_size, &num_temp_search_results,
2430 &search_interval_tree_buffer, gc_norm_vector);
2431
2433 cells_, cells_array_size, num_cells + num_temp_search_results);
2434
2435 memcpy(cells_ + num_cells, temp_search_results,
2436 num_temp_search_results * sizeof(*temp_search_results));
2437 num_cells_per_bnd_circle[i] = num_temp_search_results;
2438 num_cells += num_temp_search_results;
2439 }
2440
2441 free(temp_search_results);
2442 free(search_interval_tree_buffer.overlap_iv);
2443
2444 *cells = xrealloc(cells_, num_cells * sizeof(*cells_));
2445}
2446
2447static void free_sphere_part_tree (struct sphere_part_node tree) {
2448
2449 // free I_list
2450 if (tree.flags & I_IS_INTERVAL_TREE)
2451 free(tree.I.ivt.head_node);
2452
2453 if ((tree.flags & U_IS_LEAF) == 0) {
2454 free_sphere_part_tree(*(struct sphere_part_node*)(tree.U));
2455 free(tree.U);
2456 }
2457
2458 if ((tree.flags & T_IS_LEAF) == 0) {
2459 free_sphere_part_tree(*(struct sphere_part_node*)(tree.T));
2460 free(tree.T);
2461 }
2462}
2463
2465
2466 if ((tree->flags & U_IS_LEAF) == 0) {
2468 free(tree->U);
2469 }
2470
2471 if ((tree->flags & T_IS_LEAF) == 0) {
2473 free(tree->T);
2474 }
2475}
2476
2478 struct point_sphere_part_search * search) {
2479
2480 if (search == NULL) return;
2481
2483 free(search->points);
2484 free(search);
2485}
2486
2488
2489 if (search == NULL) return;
2490
2492 free(search->ids);
2493 free(search);
2494}
#define YAC_ASSERT(exp, msg)
struct bounding_circle const *const const_bounding_circle_pointer
#define ENSURE_ARRAY_SIZE(arrayp, curr_array_size, req_size)
static struct sin_cos_angle get_vector_angle_2(double const a[3], double const b[3])
Definition geometry.h:484
static double clamp_abs_one(double val)
Definition geometry.h:208
static const struct sin_cos_angle SIN_COS_ZERO
Definition geometry.h:36
static int points_are_identically(double const *a, double const *b)
Definition geometry.h:717
static const struct sin_cos_angle SIN_COS_M_PI
Definition geometry.h:41
static struct sin_cos_angle sum_angles_no_check(struct sin_cos_angle a, struct sin_cos_angle b)
Definition geometry.h:593
static void crossproduct_kahan(double const a[], double const b[], double cross[])
Definition geometry.h:405
static const struct sin_cos_angle SIN_COS_M_PI_2
Definition geometry.h:40
static int compare_angles(struct sin_cos_angle a, struct sin_cos_angle b)
Definition geometry.h:497
#define yac_angle_tol
Definition geometry.h:26
static void normalise_vector(double v[])
Definition geometry.h:743
static double get_vector_angle(double const a[3], double const b[3])
Definition geometry.h:463
static struct sin_cos_angle sin_cos_angle_new(double sin, double cos)
Definition geometry.h:474
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)
@ U_FLAG
@ T_FLAG
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 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, int *list_flag)
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
@ I_NODE
@ T_NODE
@ U_NODE
@ I_NODE_FULL
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)
@ I_list_tree_min_size
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)
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 void search_bnd_circle_points(struct point_sphere_part_node const *node, struct point_id_xyz const *points, struct bounding_circle const *bnd_circle, size_t **local_point_ids, size_t *local_point_ids_array_size, size_t *num_local_point_ids)
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)
void yac_point_sphere_part_search_bnd_circle(struct point_sphere_part_search *search, size_t num_bnd_circles, const_bounding_circle_pointer bnd_circles, size_t **local_point_ids, size_t *local_point_ids_array_size, size_t *num_local_point_ids)
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
@ I_IS_INTERVAL_TREE
@ T_IS_LEAF
@ U_IS_LEAF
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)
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
struct sin_cos_angle inc_angle
angle between the middle point and the boundary of the spherical cap
Definition geometry.h:53
double base_vector[3]
Definition geometry.h:51
double sq_crd
Definition geometry.h:56
struct interval range
double right
double left
size_t * overlap_iv
size_t num_overlaps
struct point_id_xyz point
int32_t coordinate_xyz[3]
double coordinates_xyz[3]
struct point_sphere_part_node base_node
struct point_id_xyz * points
double sin
Definition geometry.h:33
double cos
Definition geometry.h:33
double gc_norm_vector[3]
struct sin_cos_angle I_angle
union I_list I
struct bounding_circle bnd_circle
size_t num_cells[2]
static int mask[16]
struct interval_node * head_node
size_t * list
struct I_list::@56 ivt
size_t num_nodes
#define YAC_OMP_PARALLEL
#define YAC_OMP_FOR
double const (* yac_const_coordinate_pointer)[3]
Definition yac_types.h:22
YAC_INT yac_int
Definition yac_types.h:15
double(* yac_coordinate_pointer)[3]
Definition yac_types.h:21