17 const float merge_distance,
27 KDTree_3d *
tree = BLI_kdtree_3d_new(selection.
size());
31 BLI_kdtree_3d_balance(
tree);
37 const int duplicate_count = BLI_kdtree_3d_calc_duplicates_fast(
38 tree, merge_distance,
false, selection_merge_indices.
data());
39 BLI_kdtree_3d_free(
tree);
42 const int dst_size = src_size - duplicate_count;
54 for (
const int i : selection_merge_indices.
index_range()) {
55 const int merge_index = selection_merge_indices[i];
56 if (merge_index != -1) {
57 const int src_merge_index = selection[merge_index];
58 const int src_index = selection[i];
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]++;
88 offset += point_merge_counts[i];
92 point_merge_counts.
fill(0);
98 const int merge_index = merge_indices[i];
99 const int dst_index = src_to_dst_indices[merge_index];
101 const IndexRange points(map_offsets[dst_index],
102 map_offsets[dst_index + 1] - map_offsets[dst_index]);
104 point_merge_indices[point_merge_counts[dst_index]] = i;
105 point_merge_counts[dst_index]++;
117 for (
const int i_dst : range) {
118 const IndexRange points(map_offsets[i_dst], map_offsets[i_dst + 1] - map_offsets[i_dst]);
119 dst.span[i_dst] =
src[points.
first()];
129 if (!
id.should_be_kept()) {
135 using T = decltype(dummy);
136 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
137 bke::SpanAttributeWriter<T> dst_attribute =
138 dst_attributes.lookup_or_add_for_write_only_span<T>(id, ATTR_DOMAIN_POINT);
139 VArraySpan<T> src = src_attribute.varray.typed<T>();
141 threading::parallel_for(IndexRange(dst_size), 1024, [&](IndexRange range) {
142 for (const int i_dst : range) {
145 attribute_math::DefaultMixer<T> mixer{dst_attribute.span.slice(i_dst, 1)};
147 const IndexRange points(map_offsets[i_dst],
148 map_offsets[i_dst + 1] - map_offsets[i_dst]);
149 Span<int> src_merge_indices = merge_map.as_span().slice(points);
150 for (const int i_src : src_merge_indices) {
151 mixer.mix_in(0, src[i_src]);
158 dst_attribute.finish();
163 return dst_pointcloud;
General operations for point clouds.
struct PointCloud * BKE_pointcloud_new_nomain(int totpoint)
A KD-tree for nearest neighbor search.
const T & last(const int64_t n=0) const
IndexRange index_range() const
void fill(const T &value) const
MutableSpan< T > as_mutable_span()
const CPPType & type() const
IndexRange index_range() const
constexpr int64_t first() const
void remove_contained(const Key &key)
bool contains(const Key &key) const
Set< AttributeIDRef > all_ids() const
GAttributeReader lookup(const AttributeIDRef &attribute_id) const
GVArray lookup_or_default(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, const void *default_value=nullptr) const
GSpanAttributeWriter lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
SyclQueue void void * src
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
AttributeAccessor pointcloud_attributes(const PointCloud &pointcloud)
MutableAttributeAccessor pointcloud_attributes_for_write(PointCloud &pointcloud)
PointCloud * point_merge_by_distance(const PointCloud &src_points, const float merge_distance, const IndexMask selection)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
vec_base< float, 3 > float3
MutableSpan< float3 > positions