Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2017-09-03 15:34:49 +0300
committerCampbell Barton <ideasman42@gmail.com>2018-01-31 01:56:53 +0300
commitd7c7ce2a7b44b247d75931028342ea17f49aa50e (patch)
tree9986529a9992d6c4d6285340307a842934f74e98
parentde563552da3ccbb7edb778c7d0dd906068cf7031 (diff)
BLI_kdtree: utility function to remove doubles
-rw-r--r--source/blender/blenlib/BLI_kdtree.h4
-rw-r--r--source/blender/blenlib/intern/BLI_kdtree.c120
2 files changed, 124 insertions, 0 deletions
diff --git a/source/blender/blenlib/BLI_kdtree.h b/source/blender/blenlib/BLI_kdtree.h
index aa54e1c823c..18908f8c551 100644
--- a/source/blender/blenlib/BLI_kdtree.h
+++ b/source/blender/blenlib/BLI_kdtree.h
@@ -66,6 +66,10 @@ void BLI_kdtree_range_search_cb(
const KDTree *tree, const float co[3], float range,
bool (*search_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data);
+int BLI_kdtree_calc_duplicates_fast(
+ const KDTree *tree, const float range, bool use_index_order,
+ int *doubles);
+
/* Normal use is deprecated */
/* remove __normal functions when last users drop */
int BLI_kdtree_find_nearest_n__normal(
diff --git a/source/blender/blenlib/intern/BLI_kdtree.c b/source/blender/blenlib/intern/BLI_kdtree.c
index a81f9b28b83..84ac339cc4d 100644
--- a/source/blender/blenlib/intern/BLI_kdtree.c
+++ b/source/blender/blenlib/intern/BLI_kdtree.c
@@ -674,3 +674,123 @@ finally:
if (stack != defaultstack)
MEM_freeN(stack);
}
+
+/**
+ * Use when we want to loop over nodes ordered by index.
+ * Requires indices to be aligned with nodes.
+ */
+static uint *kdtree_order(const KDTree *tree)
+{
+ const KDTreeNode *nodes = tree->nodes;
+ uint *order = MEM_mallocN(sizeof(uint) * tree->totnode, __func__);
+ for (uint i = 0; i < tree->totnode; i++) {
+ order[nodes[i].index] = i;
+ }
+ return order;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name BLI_kdtree_calc_duplicates_fast
+ * \{ */
+
+struct DeDuplicateParams {
+ /* Static */
+ const KDTreeNode *nodes;
+ float range;
+ float range_sq;
+ int *duplicates;
+ int *duplicates_found;
+
+ /* Per Search */
+ float search_co[3];
+ int search;
+};
+
+static void deduplicate_recursive(const struct DeDuplicateParams *p, uint i)
+{
+ const KDTreeNode *node = &p->nodes[i];
+ if (p->search_co[node->d] + p->range <= node->co[node->d]) {
+ if (node->left != KD_NODE_UNSET) {
+ deduplicate_recursive(p, node->left);
+ }
+ }
+ else if (p->search_co[node->d] - p->range >= node->co[node->d]) {
+ if (node->right != KD_NODE_UNSET) {
+ deduplicate_recursive(p, node->right);
+ }
+ }
+ else {
+ if ((p->search != node->index) && (p->duplicates[node->index] == -1)) {
+ if (compare_len_squared_v3v3(node->co, p->search_co, p->range_sq)) {
+ p->duplicates[node->index] = (int)p->search;
+ *p->duplicates_found += 1;
+ }
+ }
+ if (node->left != KD_NODE_UNSET) {
+ deduplicate_recursive(p, node->left);
+ }
+ if (node->right != KD_NODE_UNSET) {
+ deduplicate_recursive(p, node->right);
+ }
+ }
+}
+
+/**
+ * Find duplicate points in \a range.
+ * Favors speed over quality since it doesn't find the best target vertex for merging.
+ * Nodes are looped over, duplicates are added when found.
+ * Nevertheless results are predictable.
+ *
+ * \param range: Coordinates in this range are candidates to be merged.
+ * \param use_index_order: Loop over the coordinates ordered by #KDTreeNode.index
+ * At the expense of some performance, this ensures the layout of the tree doesn't influence
+ * the iteration order.
+ * \param duplicates: An array of int's the length of #KDTree.totnode
+ * Values initialized to -1 are candidates to me merged.
+ * Setting the index to it's own position in the array prevents it from being touched,
+ * although it can still be used as a target.
+ * \returns The numebr of merges found (includes any merges already in the \a duplicates array).
+ *
+ * \note Merging is always a single step (target indices wont be marked for merging).
+ */
+int BLI_kdtree_calc_duplicates_fast(
+ const KDTree *tree, const float range, bool use_index_order,
+ int *duplicates)
+{
+ int found = 0;
+ struct DeDuplicateParams p = {
+ .nodes = tree->nodes,
+ .range = range,
+ .range_sq = range * range,
+ .duplicates = duplicates,
+ .duplicates_found = &found,
+ };
+
+ if (use_index_order) {
+ uint *order = kdtree_order(tree);
+ for (uint i = 0; i < tree->totnode; i++) {
+ const uint node_index = order[i];
+ const int index = (int)i;
+ if (ELEM(duplicates[index], -1, index)) {
+ p.search = index;
+ copy_v3_v3(p.search_co, tree->nodes[node_index].co);
+ deduplicate_recursive(&p, tree->root);
+ }
+ }
+ MEM_freeN(order);
+ }
+ else {
+ for (uint i = 0; i < tree->totnode; i++) {
+ const uint node_index = i;
+ const int index = p.nodes[node_index].index;
+ if (ELEM(duplicates[index], -1, index)) {
+ p.search = index;
+ copy_v3_v3(p.search_co, tree->nodes[node_index].co);
+ deduplicate_recursive(&p, tree->root);
+ }
+ }
+ }
+ return found;
+}
+
+/** \} */