21 const float merge_distance,
27 const int src_size = positions.size();
31 KDTree_3d *
tree = BLI_kdtree_3d_new(selection.size());
32 selection.foreach_index_optimized<
int64_t>(
34 BLI_kdtree_3d_balance(
tree);
39 Array<int> selection_merge_indices(selection.size(), -1);
40 const int duplicate_count = BLI_kdtree_3d_calc_duplicates_fast(
41 tree, merge_distance,
false, selection_merge_indices.
data());
42 BLI_kdtree_3d_free(
tree);
45 const int dst_size = src_size - duplicate_count;
55 selection.foreach_index([&](
const int src_index,
const int pos) {
56 const int merge_index = selection_merge_indices[
pos];
57 if (merge_index != -1) {
58 const int src_merge_index = selection[merge_index];
59 merge_indices[src_index] = src_merge_index;
65 int merged_points = 0;
68 src_to_dst_indices[i] = i - merged_points;
69 if (merge_indices[i] != i) {
78 const int merge_index = merge_indices[i];
79 const int dst_index = src_to_dst_indices[merge_index];
80 point_merge_counts[dst_index]++;
87 map_offsets_data[i] = offset;
88 offset += point_merge_counts[i];
90 map_offsets_data.
last() = offset;
93 point_merge_counts.
fill(0);
99 const int merge_index = merge_indices[i];
100 const int dst_index = src_to_dst_indices[merge_index];
102 merge_map_indices[map_offsets[dst_index].first() + point_merge_counts[dst_index]] = i;
103 point_merge_counts[dst_index]++;
115 for (
const int i_dst :
range) {
116 dst.span[i_dst] = src[map_offsets[i_dst].first()];
125 for (
const StringRef id : attribute_ids) {
132 using T = decltype(dummy);
133 if constexpr (!std::is_void_v<bke::attribute_math::DefaultMixer<T>>) {
134 bke::SpanAttributeWriter<T> dst_attribute =
135 dst_attributes.lookup_or_add_for_write_only_span<T>(id, bke::AttrDomain::Point);
136 VArraySpan<T> src = src_attribute.varray.typed<T>();
138 threading::parallel_for(IndexRange(dst_size), 1024, [&](IndexRange range) {
139 for (const int i_dst : range) {
142 bke::attribute_math::DefaultMixer<T> mixer{dst_attribute.span.slice(i_dst, 1)};
144 Span<int> src_merge_indices = merge_map_indices.as_span().slice(map_offsets[i_dst]);
145 for (const int i_src : src_merge_indices) {
146 mixer.mix_in(0, src[i_src]);
153 dst_attribute.finish();
160 return dst_pointcloud;