Blender V5.0
kdtree_impl.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "MEM_guardedalloc.h"
10
11#include "BLI_array.hh"
12#include "BLI_kdtree_impl.h"
13#include "BLI_math_base.h"
14#include "BLI_utildefines.h"
15#include "BLI_vector.hh"
16
17#include <algorithm>
18#include <cstring>
19
20#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
21
22#define _BLI_KDTREE_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1##MACRO_ARG2
23#define _BLI_KDTREE_CONCAT(MACRO_ARG1, MACRO_ARG2) _BLI_KDTREE_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
24#define BLI_kdtree_nd_(id) _BLI_KDTREE_CONCAT(KDTREE_PREFIX_ID, _##id)
25
26/* All these struct names are #defines with unique names, to avoid violating the one definition
27 * rule. Otherwise `MEM_malloc_array<KDTreeNode>` can get defined once for multiple dimensions,
28 * with different node sizes. */
29
32 float co[KD_DIMS];
33 int index;
34};
35
36struct KDTreeNode {
38 float co[KD_DIMS];
39 int index;
40 uint d; /* range is only (0..KD_DIMS - 1) */
41};
42
43struct KDTree {
48#ifndef NDEBUG
49 bool is_balanced; /* ensure we call balance first */
50 uint nodes_len_capacity; /* max size of the tree */
51#endif
52};
53
54#define KD_STACK_INIT 100 /* initial size for array (on the stack) */
55#define KD_NEAR_ALLOC_INC 100 /* alloc increment for collecting nearest */
56#define KD_FOUND_ALLOC_INC 50 /* alloc increment for collecting nearest */
57
58#define KD_NODE_UNSET ((uint) - 1)
59
64#define KD_NODE_ROOT_IS_INIT ((uint) - 2)
65
66/* -------------------------------------------------------------------- */
69
70static void copy_vn_vn(float v0[KD_DIMS], const float v1[KD_DIMS])
71{
72 for (uint j = 0; j < KD_DIMS; j++) {
73 v0[j] = v1[j];
74 }
75}
76
77static float len_squared_vnvn(const float v0[KD_DIMS], const float v1[KD_DIMS])
78{
79 float d = 0.0f;
80 for (uint j = 0; j < KD_DIMS; j++) {
81 d += square_f(v0[j] - v1[j]);
82 }
83 return d;
84}
85
86static float len_squared_vnvn_cb(const float co_kdtree[KD_DIMS],
87 const float co_search[KD_DIMS],
88 const void * /*user_data*/)
89{
90 return len_squared_vnvn(co_kdtree, co_search);
91}
92
94
98KDTree *BLI_kdtree_nd_(new)(uint nodes_len_capacity)
99{
100 KDTree *tree;
101
102 tree = MEM_callocN<KDTree>("KDTree");
103 tree->nodes = MEM_malloc_arrayN<KDTreeNode>(nodes_len_capacity, "KDTreeNode");
104 tree->nodes_len = 0;
106 tree->max_node_index = -1;
107
108#ifndef NDEBUG
109 tree->is_balanced = false;
110 tree->nodes_len_capacity = nodes_len_capacity;
111#endif
112
113 return tree;
114}
115
117{
118 if (tree) {
119 MEM_freeN(tree->nodes);
121 }
122}
123
127void BLI_kdtree_nd_(insert)(KDTree *tree, int index, const float co[KD_DIMS])
128{
129 KDTreeNode *node = &tree->nodes[tree->nodes_len++];
130
131#ifndef NDEBUG
132 BLI_assert(tree->nodes_len <= tree->nodes_len_capacity);
133#endif
134
135 /* NOTE: array isn't calloc'd,
136 * need to initialize all struct members */
137
138 node->left = node->right = KD_NODE_UNSET;
139 copy_vn_vn(node->co, co);
140 node->index = index;
141 node->d = 0;
142 tree->max_node_index = std::max(tree->max_node_index, index);
143
144#ifndef NDEBUG
145 tree->is_balanced = false;
146#endif
147}
148
149static uint kdtree_balance(KDTreeNode *nodes, uint nodes_len, uint axis, const uint ofs)
150{
151 KDTreeNode *node;
152 float co;
153 uint left, right, median, i, j;
154
155 if (nodes_len <= 0) {
156 return KD_NODE_UNSET;
157 }
158 if (nodes_len == 1) {
159 return 0 + ofs;
160 }
161
162 /* Quick-sort style sorting around median. */
163 left = 0;
164 right = nodes_len - 1;
165 median = nodes_len / 2;
166
167 while (right > left) {
168 co = nodes[right].co[axis];
169 i = left - 1;
170 j = right;
171
172 while (true) {
173 while (nodes[++i].co[axis] < co) { /* pass */
174 }
175 while (nodes[--j].co[axis] > co && j > left) { /* pass */
176 }
177
178 if (i >= j) {
179 break;
180 }
181
182 SWAP(KDTreeNode_head, *(KDTreeNode_head *)&nodes[i], *(KDTreeNode_head *)&nodes[j]);
183 }
184
185 SWAP(KDTreeNode_head, *(KDTreeNode_head *)&nodes[i], *(KDTreeNode_head *)&nodes[right]);
186 if (i >= median) {
187 right = i - 1;
188 }
189 if (i <= median) {
190 left = i + 1;
191 }
192 }
193
194 /* Set node and sort sub-nodes. */
195 node = &nodes[median];
196 node->d = axis;
197 axis = (axis + 1) % KD_DIMS;
198 node->left = kdtree_balance(nodes, median, axis, ofs);
199 node->right = kdtree_balance(
200 nodes + median + 1, (nodes_len - (median + 1)), axis, (median + 1) + ofs);
201
202 return median + ofs;
203}
204
206{
207 if (tree->root != KD_NODE_ROOT_IS_INIT) {
208 for (uint i = 0; i < tree->nodes_len; i++) {
209 tree->nodes[i].left = KD_NODE_UNSET;
210 tree->nodes[i].right = KD_NODE_UNSET;
211 }
212 }
213
214 tree->root = kdtree_balance(tree->nodes, tree->nodes_len, 0, 0);
215
216#ifndef NDEBUG
217 tree->is_balanced = true;
218#endif
219}
220
221static uint *realloc_nodes(uint *stack, uint *stack_len_capacity, const bool is_alloc)
222{
223 uint *stack_new = MEM_malloc_arrayN<uint>(*stack_len_capacity + KD_NEAR_ALLOC_INC,
224 "KDTree.treestack");
225 memcpy(stack_new, stack, *stack_len_capacity * sizeof(uint));
226 // memset(stack_new + *stack_len_capacity, 0, sizeof(uint) * KD_NEAR_ALLOC_INC);
227 if (is_alloc) {
228 MEM_freeN(stack);
229 }
230 *stack_len_capacity += KD_NEAR_ALLOC_INC;
231 return stack_new;
232}
233
238 const float co[KD_DIMS],
239 KDTreeNearest *r_nearest)
240{
241 const KDTreeNode *nodes = tree->nodes;
242 const KDTreeNode *root, *min_node;
243 uint *stack, stack_default[KD_STACK_INIT];
244 float min_dist, cur_dist;
245 uint stack_len_capacity, cur = 0;
246
247#ifndef NDEBUG
248 BLI_assert(tree->is_balanced == true);
249#endif
250
251 if (UNLIKELY(tree->root == KD_NODE_UNSET)) {
252 return -1;
253 }
254
255 stack = stack_default;
256 stack_len_capacity = KD_STACK_INIT;
257
258 root = &nodes[tree->root];
259 min_node = root;
260 min_dist = len_squared_vnvn(root->co, co);
261
262 if (co[root->d] < root->co[root->d]) {
263 if (root->right != KD_NODE_UNSET) {
264 stack[cur++] = root->right;
265 }
266 if (root->left != KD_NODE_UNSET) {
267 stack[cur++] = root->left;
268 }
269 }
270 else {
271 if (root->left != KD_NODE_UNSET) {
272 stack[cur++] = root->left;
273 }
274 if (root->right != KD_NODE_UNSET) {
275 stack[cur++] = root->right;
276 }
277 }
278
279 while (cur--) {
280 const KDTreeNode *node = &nodes[stack[cur]];
281
282 cur_dist = node->co[node->d] - co[node->d];
283
284 if (cur_dist < 0.0f) {
285 cur_dist = -cur_dist * cur_dist;
286
287 if (-cur_dist < min_dist) {
288 cur_dist = len_squared_vnvn(node->co, co);
289 if (cur_dist < min_dist) {
290 min_dist = cur_dist;
291 min_node = node;
292 }
293 if (node->left != KD_NODE_UNSET) {
294 stack[cur++] = node->left;
295 }
296 }
297 if (node->right != KD_NODE_UNSET) {
298 stack[cur++] = node->right;
299 }
300 }
301 else {
302 cur_dist = cur_dist * cur_dist;
303
304 if (cur_dist < min_dist) {
305 cur_dist = len_squared_vnvn(node->co, co);
306 if (cur_dist < min_dist) {
307 min_dist = cur_dist;
308 min_node = node;
309 }
310 if (node->right != KD_NODE_UNSET) {
311 stack[cur++] = node->right;
312 }
313 }
314 if (node->left != KD_NODE_UNSET) {
315 stack[cur++] = node->left;
316 }
317 }
318 if (UNLIKELY(cur + KD_DIMS > stack_len_capacity)) {
319 stack = realloc_nodes(stack, &stack_len_capacity, stack_default != stack);
320 }
321 }
322
323 if (r_nearest) {
324 r_nearest->index = min_node->index;
325 r_nearest->dist = sqrtf(min_dist);
326 copy_vn_vn(r_nearest->co, min_node->co);
327 }
328
329 if (stack != stack_default) {
330 MEM_freeN(stack);
331 }
332
333 return min_node->index;
334}
335
337 const KDTree *tree,
338 const float co[KD_DIMS],
339 int (*filter_cb)(void *user_data, int index, const float co[KD_DIMS], float dist_sq),
340 void *user_data,
341 KDTreeNearest *r_nearest)
342{
343 const KDTreeNode *nodes = tree->nodes;
344 const KDTreeNode *min_node = nullptr;
345
346 uint *stack, stack_default[KD_STACK_INIT];
347 float min_dist = FLT_MAX, cur_dist;
348 uint stack_len_capacity, cur = 0;
349
350#ifndef NDEBUG
351 BLI_assert(tree->is_balanced == true);
352#endif
353
354 if (UNLIKELY(tree->root == KD_NODE_UNSET)) {
355 return -1;
356 }
357
358 stack = stack_default;
359 stack_len_capacity = int(ARRAY_SIZE(stack_default));
360
361#define NODE_TEST_NEAREST(node) \
362 { \
363 const float dist_sq = len_squared_vnvn((node)->co, co); \
364 if (dist_sq < min_dist) { \
365 const int result = filter_cb(user_data, (node)->index, (node)->co, dist_sq); \
366 if (result == 1) { \
367 min_dist = dist_sq; \
368 min_node = node; \
369 } \
370 else if (result == 0) { \
371 /* pass */ \
372 } \
373 else { \
374 BLI_assert(result == -1); \
375 goto finally; \
376 } \
377 } \
378 } \
379 ((void)0)
380
381 stack[cur++] = tree->root;
382
383 while (cur--) {
384 const KDTreeNode *node = &nodes[stack[cur]];
385
386 cur_dist = node->co[node->d] - co[node->d];
387
388 if (cur_dist < 0.0f) {
389 cur_dist = -cur_dist * cur_dist;
390
391 if (-cur_dist < min_dist) {
392 NODE_TEST_NEAREST(node);
393
394 if (node->left != KD_NODE_UNSET) {
395 stack[cur++] = node->left;
396 }
397 }
398 if (node->right != KD_NODE_UNSET) {
399 stack[cur++] = node->right;
400 }
401 }
402 else {
403 cur_dist = cur_dist * cur_dist;
404
405 if (cur_dist < min_dist) {
406 NODE_TEST_NEAREST(node);
407
408 if (node->right != KD_NODE_UNSET) {
409 stack[cur++] = node->right;
410 }
411 }
412 if (node->left != KD_NODE_UNSET) {
413 stack[cur++] = node->left;
414 }
415 }
416 if (UNLIKELY(cur + KD_DIMS > stack_len_capacity)) {
417 stack = realloc_nodes(stack, &stack_len_capacity, stack_default != stack);
418 }
419 }
420
421#undef NODE_TEST_NEAREST
422
423finally:
424 if (stack != stack_default) {
425 MEM_freeN(stack);
426 }
427
428 if (min_node) {
429 if (r_nearest) {
430 r_nearest->index = min_node->index;
431 r_nearest->dist = sqrtf(min_dist);
432 copy_vn_vn(r_nearest->co, min_node->co);
433 }
434
435 return min_node->index;
436 }
437 return -1;
438}
439
441 uint *nearest_len,
442 const uint nearest_len_capacity,
443 const int index,
444 const float dist,
445 const float co[KD_DIMS])
446{
447 uint i;
448
449 if (*nearest_len < nearest_len_capacity) {
450 (*nearest_len)++;
451 }
452
453 for (i = *nearest_len - 1; i > 0; i--) {
454 if (dist >= nearest[i - 1].dist) {
455 break;
456 }
457 nearest[i] = nearest[i - 1];
458 }
459
460 nearest[i].index = index;
461 nearest[i].dist = dist;
462 copy_vn_vn(nearest[i].co, co);
463}
464
466 const KDTree *tree,
467 const float co[KD_DIMS],
468 KDTreeNearest r_nearest[],
469 const uint nearest_len_capacity,
470 float (*len_sq_fn)(const float co_search[KD_DIMS],
471 const float co_test[KD_DIMS],
472 const void *user_data),
473 const void *user_data)
474{
475 const KDTreeNode *nodes = tree->nodes;
476 const KDTreeNode *root;
477 uint *stack, stack_default[KD_STACK_INIT];
478 float cur_dist;
479 uint stack_len_capacity, cur = 0;
480 uint i, nearest_len = 0;
481
482#ifndef NDEBUG
483 BLI_assert(tree->is_balanced == true);
484#endif
485
486 if (UNLIKELY((tree->root == KD_NODE_UNSET) || nearest_len_capacity == 0)) {
487 return 0;
488 }
489
490 if (len_sq_fn == nullptr) {
491 len_sq_fn = len_squared_vnvn_cb;
492 BLI_assert(user_data == nullptr);
493 }
494
495 stack = stack_default;
496 stack_len_capacity = int(ARRAY_SIZE(stack_default));
497
498 root = &nodes[tree->root];
499
500 cur_dist = len_sq_fn(co, root->co, user_data);
502 r_nearest, &nearest_len, nearest_len_capacity, root->index, cur_dist, root->co);
503
504 if (co[root->d] < root->co[root->d]) {
505 if (root->right != KD_NODE_UNSET) {
506 stack[cur++] = root->right;
507 }
508 if (root->left != KD_NODE_UNSET) {
509 stack[cur++] = root->left;
510 }
511 }
512 else {
513 if (root->left != KD_NODE_UNSET) {
514 stack[cur++] = root->left;
515 }
516 if (root->right != KD_NODE_UNSET) {
517 stack[cur++] = root->right;
518 }
519 }
520
521 while (cur--) {
522 const KDTreeNode *node = &nodes[stack[cur]];
523
524 cur_dist = node->co[node->d] - co[node->d];
525
526 if (cur_dist < 0.0f) {
527 cur_dist = -cur_dist * cur_dist;
528
529 if (nearest_len < nearest_len_capacity || -cur_dist < r_nearest[nearest_len - 1].dist) {
530 cur_dist = len_sq_fn(co, node->co, user_data);
531
532 if (nearest_len < nearest_len_capacity || cur_dist < r_nearest[nearest_len - 1].dist) {
534 r_nearest, &nearest_len, nearest_len_capacity, node->index, cur_dist, node->co);
535 }
536
537 if (node->left != KD_NODE_UNSET) {
538 stack[cur++] = node->left;
539 }
540 }
541 if (node->right != KD_NODE_UNSET) {
542 stack[cur++] = node->right;
543 }
544 }
545 else {
546 cur_dist = cur_dist * cur_dist;
547
548 if (nearest_len < nearest_len_capacity || cur_dist < r_nearest[nearest_len - 1].dist) {
549 cur_dist = len_sq_fn(co, node->co, user_data);
550 if (nearest_len < nearest_len_capacity || cur_dist < r_nearest[nearest_len - 1].dist) {
552 r_nearest, &nearest_len, nearest_len_capacity, node->index, cur_dist, node->co);
553 }
554
555 if (node->right != KD_NODE_UNSET) {
556 stack[cur++] = node->right;
557 }
558 }
559 if (node->left != KD_NODE_UNSET) {
560 stack[cur++] = node->left;
561 }
562 }
563 if (UNLIKELY(cur + KD_DIMS > stack_len_capacity)) {
564 stack = realloc_nodes(stack, &stack_len_capacity, stack_default != stack);
565 }
566 }
567
568 for (i = 0; i < nearest_len; i++) {
569 r_nearest[i].dist = sqrtf(r_nearest[i].dist);
570 }
571
572 if (stack != stack_default) {
573 MEM_freeN(stack);
574 }
575
576 return (int)nearest_len;
577}
578
580 const float co[KD_DIMS],
581 KDTreeNearest r_nearest[],
582 uint nearest_len_capacity)
583{
585 tree, co, r_nearest, nearest_len_capacity, nullptr, nullptr);
586}
587
588static int nearest_cmp_dist(const void *a, const void *b)
589{
590 const KDTreeNearest *kda = static_cast<const KDTreeNearest *>(a);
591 const KDTreeNearest *kdb = static_cast<const KDTreeNearest *>(b);
592
593 if (kda->dist < kdb->dist) {
594 return -1;
595 }
596 if (kda->dist > kdb->dist) {
597 return 1;
598 }
599 return 0;
600}
601static void nearest_add_in_range(KDTreeNearest **r_nearest,
602 uint nearest_index,
603 uint *nearest_len_capacity,
604 const int index,
605 const float dist,
606 const float co[KD_DIMS])
607{
608 KDTreeNearest *to;
609
610 if (UNLIKELY(nearest_index >= *nearest_len_capacity)) {
611 *r_nearest = static_cast<KDTreeNearest *>(MEM_reallocN_id(
612 *r_nearest, (*nearest_len_capacity += KD_FOUND_ALLOC_INC) * sizeof(KDTreeNode), __func__));
613 }
614
615 to = (*r_nearest) + nearest_index;
616
617 to->index = index;
618 to->dist = sqrtf(dist);
619 copy_vn_vn(to->co, co);
620}
621
623 const KDTree *tree,
624 const float co[KD_DIMS],
625 KDTreeNearest **r_nearest,
626 const float range,
627 float (*len_sq_fn)(const float co_search[KD_DIMS],
628 const float co_test[KD_DIMS],
629 const void *user_data),
630 const void *user_data)
631{
632 const KDTreeNode *nodes = tree->nodes;
633 uint *stack, stack_default[KD_STACK_INIT];
634 KDTreeNearest *nearest = nullptr;
635 const float range_sq = range * range;
636 float dist_sq;
637 uint stack_len_capacity, cur = 0;
638 uint nearest_len = 0, nearest_len_capacity = 0;
639
640#ifndef NDEBUG
641 BLI_assert(tree->is_balanced == true);
642#endif
643
644 if (UNLIKELY(tree->root == KD_NODE_UNSET)) {
645 return 0;
646 }
647
648 if (len_sq_fn == nullptr) {
649 len_sq_fn = len_squared_vnvn_cb;
650 BLI_assert(user_data == nullptr);
651 }
652
653 stack = stack_default;
654 stack_len_capacity = int(ARRAY_SIZE(stack_default));
655
656 stack[cur++] = tree->root;
657
658 while (cur--) {
659 const KDTreeNode *node = &nodes[stack[cur]];
660
661 if (co[node->d] + range < node->co[node->d]) {
662 if (node->left != KD_NODE_UNSET) {
663 stack[cur++] = node->left;
664 }
665 }
666 else if (co[node->d] - range > node->co[node->d]) {
667 if (node->right != KD_NODE_UNSET) {
668 stack[cur++] = node->right;
669 }
670 }
671 else {
672 dist_sq = len_sq_fn(co, node->co, user_data);
673 if (dist_sq <= range_sq) {
675 &nearest, nearest_len++, &nearest_len_capacity, node->index, dist_sq, node->co);
676 }
677
678 if (node->left != KD_NODE_UNSET) {
679 stack[cur++] = node->left;
680 }
681 if (node->right != KD_NODE_UNSET) {
682 stack[cur++] = node->right;
683 }
684 }
685
686 if (UNLIKELY(cur + KD_DIMS > stack_len_capacity)) {
687 stack = realloc_nodes(stack, &stack_len_capacity, stack_default != stack);
688 }
689 }
690
691 if (stack != stack_default) {
692 MEM_freeN(stack);
693 }
694
695 if (nearest_len) {
696 qsort(nearest, nearest_len, sizeof(KDTreeNearest), nearest_cmp_dist);
697 }
698
699 *r_nearest = nearest;
700
701 return (int)nearest_len;
702}
703
705 const float co[KD_DIMS],
706 KDTreeNearest **r_nearest,
707 float range)
708{
710 tree, co, r_nearest, range, nullptr, nullptr);
711}
712
714 const KDTree *tree,
715 const float co[KD_DIMS],
716 float range,
717 bool (*search_cb)(void *user_data, int index, const float co[KD_DIMS], float dist_sq),
718 void *user_data)
719{
720 const KDTreeNode *nodes = tree->nodes;
721
722 uint *stack, stack_default[KD_STACK_INIT];
723 float range_sq = range * range, dist_sq;
724 uint stack_len_capacity, cur = 0;
725
726#ifndef NDEBUG
727 BLI_assert(tree->is_balanced == true);
728#endif
729
730 if (UNLIKELY(tree->root == KD_NODE_UNSET)) {
731 return;
732 }
733
734 stack = stack_default;
735 stack_len_capacity = int(ARRAY_SIZE(stack_default));
736
737 stack[cur++] = tree->root;
738
739 while (cur--) {
740 const KDTreeNode *node = &nodes[stack[cur]];
741
742 if (co[node->d] + range < node->co[node->d]) {
743 if (node->left != KD_NODE_UNSET) {
744 stack[cur++] = node->left;
745 }
746 }
747 else if (co[node->d] - range > node->co[node->d]) {
748 if (node->right != KD_NODE_UNSET) {
749 stack[cur++] = node->right;
750 }
751 }
752 else {
753 dist_sq = len_squared_vnvn(node->co, co);
754 if (dist_sq <= range_sq) {
755 if (search_cb(user_data, node->index, node->co, dist_sq) == false) {
756 goto finally;
757 }
758 }
759
760 if (node->left != KD_NODE_UNSET) {
761 stack[cur++] = node->left;
762 }
763 if (node->right != KD_NODE_UNSET) {
764 stack[cur++] = node->right;
765 }
766 }
767
768 if (UNLIKELY(cur + KD_DIMS > stack_len_capacity)) {
769 stack = realloc_nodes(stack, &stack_len_capacity, stack_default != stack);
770 }
771 }
772
773finally:
774 if (stack != stack_default) {
775 MEM_freeN(stack);
776 }
777}
778
784{
785 const KDTreeNode *nodes = tree->nodes;
786 blender::Vector<int> order(tree->max_node_index + 1, -1);
787 for (uint i = 0; i < tree->nodes_len; i++) {
788 order[nodes[i].index] = (int)i;
789 }
790 return order;
791}
792
793/* -------------------------------------------------------------------- */
796
798 /* Static */
800 float range;
801 float range_sq;
804
805 /* Per Search */
808};
809
811{
812 const KDTreeNode *node = &p->nodes[i];
813 if (p->search_co[node->d] + p->range <= node->co[node->d]) {
814 if (node->left != KD_NODE_UNSET) {
815 deduplicate_recursive(p, node->left);
816 }
817 }
818 else if (p->search_co[node->d] - p->range >= node->co[node->d]) {
819 if (node->right != KD_NODE_UNSET) {
821 }
822 }
823 else {
824 if ((p->search != node->index) && (p->duplicates[node->index] == -1)) {
825 if (len_squared_vnvn(node->co, p->search_co) <= p->range_sq) {
826 p->duplicates[node->index] = (int)p->search;
827 *p->duplicates_found += 1;
828 }
829 }
830 if (node->left != KD_NODE_UNSET) {
831 deduplicate_recursive(p, node->left);
832 }
833 if (node->right != KD_NODE_UNSET) {
835 }
836 }
837}
838
840 const float range,
841 const bool use_index_order,
842 int *duplicates)
843{
844 int found = 0;
845
846 DeDuplicateParams p = {};
847 p.nodes = tree->nodes;
848 p.range = range;
849 p.range_sq = square_f(range);
850 p.duplicates = duplicates;
851 p.duplicates_found = &found;
852
853 if (use_index_order) {
855 for (int i = 0; i < tree->max_node_index + 1; i++) {
856 const int node_index = order[i];
857 if (node_index == -1) {
858 continue;
859 }
860 const int index = i;
861 if (ELEM(duplicates[index], -1, index)) {
862 p.search = index;
863 copy_vn_vn(p.search_co, tree->nodes[node_index].co);
864 int found_prev = found;
865 deduplicate_recursive(&p, tree->root);
866 if (found != found_prev) {
867 /* Prevent chains of doubles. */
868 duplicates[index] = index;
869 }
870 }
871 }
872 }
873 else {
874 for (uint i = 0; i < tree->nodes_len; i++) {
875 const uint node_index = i;
876 const int index = p.nodes[node_index].index;
877 if (ELEM(duplicates[index], -1, index)) {
878 p.search = index;
879 copy_vn_vn(p.search_co, tree->nodes[node_index].co);
880 int found_prev = found;
881 deduplicate_recursive(&p, tree->root);
882 if (found != found_prev) {
883 /* Prevent chains of doubles. */
884 duplicates[index] = index;
885 }
886 }
887 }
888 }
889 return found;
890}
891
893
894/* -------------------------------------------------------------------- */
897
899 const float range,
900 int *duplicates,
901 const bool has_self_index,
902 int (*duplicates_cb)(void *user_data,
903 const int *cluster,
904 int cluster_num),
905 void *user_data)
906{
907 BLI_assert(tree->is_balanced);
908 if (UNLIKELY(tree->root == KD_NODE_UNSET)) {
909 return 0;
910 }
911
912 /* Use `index_to_node_index` so coordinates are looked up in order first to last. */
913 const uint nodes_len = tree->nodes_len;
914 blender::Array<int> index_to_node_index(tree->max_node_index + 1);
915 for (uint i = 0; i < nodes_len; i++) {
916 index_to_node_index[tree->nodes[i].index] = int(i);
917 }
918
919 int found = 0;
920
921 /* First pass, handle merging into self-index (if any exist). */
922 if (has_self_index) {
923 blender::Array<float> duplicates_dist_sq(tree->max_node_index + 1);
924 for (uint i = 0; i < nodes_len; i++) {
925 const int node_index = tree->nodes[i].index;
926 if (node_index != duplicates[node_index]) {
927 continue;
928 }
929 const float *search_co = tree->nodes[index_to_node_index[node_index]].co;
930 auto accumulate_neighbors_fn =
931 [&duplicates, &node_index, &duplicates_dist_sq, &found](
932 int neighbor_index, const float * /*co*/, const float dist_sq) -> bool {
933 const int target_index = duplicates[neighbor_index];
934 if (target_index == -1) {
935 duplicates[neighbor_index] = node_index;
936 duplicates_dist_sq[neighbor_index] = dist_sq;
937 found += 1;
938 }
939 /* Don't steal from self references. */
940 else if (target_index != neighbor_index) {
941 float &dist_sq_best = duplicates_dist_sq[neighbor_index];
942 /* Steal the target if it's closer. */
943 if ((dist_sq < dist_sq_best) ||
944 /* Pick the lowest index as a tie breaker for a deterministic result. */
945 ((dist_sq == dist_sq_best) && (node_index < target_index)))
946 {
947 dist_sq_best = dist_sq;
948 duplicates[neighbor_index] = node_index;
949 }
950 }
951 return true;
952 };
953
954 BLI_kdtree_nd_(range_search_cb_cpp)(tree, search_co, range, accumulate_neighbors_fn);
955 }
956 }
957
958 /* Second pass, de-duplicate clusters that weren't handled in the first pass. */
959
960 /* Could be inline, declare here to avoid re-allocation. */
961 blender::Vector<int> cluster;
962 for (uint i = 0; i < nodes_len; i++) {
963 const int node_index = tree->nodes[i].index;
964 if (duplicates[node_index] != -1) {
965 continue;
966 }
967
968 BLI_assert(cluster.is_empty());
969 const float *search_co = tree->nodes[index_to_node_index[node_index]].co;
970 auto accumulate_neighbors_fn = [&duplicates, &cluster](int neighbor_index,
971 const float * /*co*/,
972 const float /*dist_sq*/) -> bool {
973 if (duplicates[neighbor_index] == -1) {
974 cluster.append(neighbor_index);
975 }
976 return true;
977 };
978
979 BLI_kdtree_nd_(range_search_cb_cpp)(tree, search_co, range, accumulate_neighbors_fn);
980 if (cluster.is_empty()) {
981 continue;
982 }
983 found += int(cluster.size());
984 cluster.append(node_index);
985
986 const int cluster_index = duplicates_cb(user_data, cluster.data(), int(cluster.size()));
987 BLI_assert(uint(cluster_index) < uint(cluster.size()));
988 const int target_index = cluster[cluster_index];
989 for (const int cluster_node_index : cluster) {
990 duplicates[cluster_node_index] = target_index;
991 }
992 cluster.clear();
993 }
994
995 return found;
996}
997
999
1000/* -------------------------------------------------------------------- */
1003
1004static int kdtree_cmp_bool(const bool a, const bool b)
1005{
1006 if (a == b) {
1007 return 0;
1008 }
1009 return b ? -1 : 1;
1010}
1011
1012static int kdtree_node_cmp_deduplicate(const void *n0_p, const void *n1_p)
1013{
1014 const KDTreeNode *n0 = static_cast<const KDTreeNode *>(n0_p);
1015 const KDTreeNode *n1 = static_cast<const KDTreeNode *>(n1_p);
1016 for (uint j = 0; j < KD_DIMS; j++) {
1017 if (n0->co[j] < n1->co[j]) {
1018 return -1;
1019 }
1020 if (n0->co[j] > n1->co[j]) {
1021 return 1;
1022 }
1023 }
1024
1025 if (n0->d != KD_DIMS && n1->d != KD_DIMS) {
1026 /* Two nodes share identical `co`
1027 * Both are still valid.
1028 * Cast away `const` and tag one of them as invalid. */
1029 ((KDTreeNode *)n1)->d = KD_DIMS;
1030 }
1031
1032 /* Keep sorting until each unique value has one and only one valid node. */
1033 return kdtree_cmp_bool(n0->d == KD_DIMS, n1->d == KD_DIMS);
1034}
1035
1037{
1038#ifndef NDEBUG
1039 tree->is_balanced = false;
1040#endif
1041 qsort(tree->nodes, (size_t)tree->nodes_len, sizeof(*tree->nodes), kdtree_node_cmp_deduplicate);
1042 uint j = 0;
1043 for (uint i = 0; i < tree->nodes_len; i++) {
1044 if (tree->nodes[i].d != KD_DIMS) {
1045 if (i != j) {
1046 tree->nodes[j] = tree->nodes[i];
1047 }
1048 j++;
1049 }
1050 }
1051 tree->nodes_len = j;
1052 return (int)tree->nodes_len;
1053}
1054
#define BLI_assert(a)
Definition BLI_assert.h:46
#define KDTreeNearest
Definition BLI_kdtree.h:16
#define KDTree
Definition BLI_kdtree.h:15
#define KD_DIMS
Definition BLI_kdtree.h:13
A KD-tree for nearest neighbor search.
void BLI_kdtree_nd_ range_search_cb_cpp(const KDTree *tree, const float co[KD_DIMS], const float distance, const Fn &fn)
void BLI_kdtree_nd_ int BLI_kdtree_nd_ int BLI_kdtree_nd_ find_nearest_n(const KDTree *tree, const float co[KD_DIMS], KDTreeNearest *r_nearest, uint nearest_len_capacity) ATTR_NONNULL(1
void BLI_kdtree_nd_ free(KDTree *tree)
int BLI_kdtree_nd_ calc_duplicates_fast(const KDTree *tree, float range, bool use_index_order, int *duplicates)
void BLI_kdtree_nd_ range_search_cb(const KDTree *tree, const float co[KD_DIMS], float range, bool(*search_cb)(void *user_data, int index, const float co[KD_DIMS], float dist_sq), void *user_data)
void BLI_kdtree_nd_ int BLI_kdtree_nd_ find_nearest(const KDTree *tree, const float co[KD_DIMS], KDTreeNearest *r_nearest) ATTR_NONNULL(1
int BLI_kdtree_nd_ find_nearest_cb(const KDTree *tree, const float co[KD_DIMS], int(*filter_cb)(void *user_data, int index, const float co[KD_DIMS], float dist_sq), void *user_data, KDTreeNearest *r_nearest)
int BLI_kdtree_nd_ calc_duplicates_cb(const KDTree *tree, const float range, int *duplicates, bool has_self_index, int(*deduplicate_cb)(void *user_data, const int *cluster, int cluster_num), void *user_data)
int BLI_kdtree_nd_ find_nearest_n_with_len_squared_cb(const KDTree *tree, const float co[KD_DIMS], KDTreeNearest *r_nearest, uint nearest_len_capacity, float(*len_sq_fn)(const float co_search[KD_DIMS], const float co_test[KD_DIMS], const void *user_data), const void *user_data) ATTR_NONNULL(1
int BLI_kdtree_nd_ deduplicate(KDTree *tree)
void BLI_kdtree_nd_ int BLI_kdtree_nd_ int BLI_kdtree_nd_ int BLI_kdtree_nd_ range_search(const KDTree *tree, const float co[KD_DIMS], KDTreeNearest **r_nearest, float range) ATTR_NONNULL(1
void BLI_kdtree_nd_ balance(KDTree *tree) ATTR_NONNULL(1)
int BLI_kdtree_nd_ int BLI_kdtree_nd_ range_search_with_len_squared_cb(const KDTree *tree, const float co[KD_DIMS], KDTreeNearest **r_nearest, float range, float(*len_sq_fn)(const float co_search[KD_DIMS], const float co_test[KD_DIMS], const void *user_data), const void *user_data) ATTR_NONNULL(1
void BLI_kdtree_nd_ insert(KDTree *tree, int index, const float co[KD_DIMS]) ATTR_NONNULL(1
MINLINE float square_f(float a)
unsigned int uint
#define ARRAY_SIZE(arr)
#define SWAP(type, a, b)
#define UNLIKELY(x)
#define ELEM(...)
Read Guarded memory(de)allocation.
int64_t size() const
void append(const T &value)
bool is_empty() const
nullptr float
KDTree_3d * tree
#define KDTreeNode
Definition kdtree_1d.cc:12
#define KDTreeNode_head
Definition kdtree_1d.cc:13
static int kdtree_cmp_bool(const bool a, const bool b)
#define KD_NEAR_ALLOC_INC
Definition kdtree_impl.h:55
#define KD_NODE_ROOT_IS_INIT
Definition kdtree_impl.h:64
static uint kdtree_balance(KDTreeNode *nodes, uint nodes_len, uint axis, const uint ofs)
#define NODE_TEST_NEAREST(node)
static int kdtree_node_cmp_deduplicate(const void *n0_p, const void *n1_p)
static void copy_vn_vn(float v0[KD_DIMS], const float v1[KD_DIMS])
Definition kdtree_impl.h:70
static void nearest_ordered_insert(KDTreeNearest *nearest, uint *nearest_len, const uint nearest_len_capacity, const int index, const float dist, const float co[KD_DIMS])
static void deduplicate_recursive(const DeDuplicateParams *p, uint i)
#define KD_NODE_UNSET
Definition kdtree_impl.h:58
static uint * realloc_nodes(uint *stack, uint *stack_len_capacity, const bool is_alloc)
static int nearest_cmp_dist(const void *a, const void *b)
#define KD_FOUND_ALLOC_INC
Definition kdtree_impl.h:56
static float len_squared_vnvn_cb(const float co_kdtree[KD_DIMS], const float co_search[KD_DIMS], const void *)
Definition kdtree_impl.h:86
static void nearest_add_in_range(KDTreeNearest **r_nearest, uint nearest_index, uint *nearest_len_capacity, const int index, const float dist, const float co[KD_DIMS])
#define KD_STACK_INIT
Definition kdtree_impl.h:54
static float len_squared_vnvn(const float v0[KD_DIMS], const float v1[KD_DIMS])
Definition kdtree_impl.h:77
#define BLI_kdtree_nd_(id)
Definition kdtree_impl.h:24
static blender::Vector< int > kdtree_order(const KDTree *tree)
void *(* MEM_reallocN_id)(void *vmemh, size_t len, const char *str)
Definition mallocn.cc:40
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static int left
#define sqrtf
#define FLT_MAX
Definition stdcycles.h:14
const KDTreeNode * nodes
float search_co[KD_DIMS]
float co[KD_DIMS]
float co[KD_DIMS]
Definition kdtree_impl.h:32
float co[KD_DIMS]
Definition kdtree_impl.h:38
uint root
Definition kdtree_impl.h:46
bool is_balanced
Definition kdtree_impl.h:49
uint nodes_len_capacity
Definition kdtree_impl.h:50
uint nodes_len
Definition kdtree_impl.h:45
KDTreeNode * nodes
Definition kdtree_impl.h:44
int max_node_index
Definition kdtree_impl.h:47
i
Definition text_draw.cc:230