Blender V5.0
reorder.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_attribute.hh"
8#include "BKE_curves.hh"
9#include "BKE_curves_utils.hh"
10#include "BKE_deform.hh"
11#include "BKE_geometry_set.hh"
12#include "BKE_instances.hh"
13#include "BKE_mesh.hh"
14#include "BKE_pointcloud.hh"
15
16#include "BLI_array.hh"
17#include "BLI_array_utils.hh"
19
20#include "DNA_curves_types.h"
21#include "DNA_mesh_types.h"
23
24#include "GEO_reorder.hh"
25
26namespace blender::geometry {
27
28const MultiValueMap<bke::GeometryComponent::Type, bke::AttrDomain> &
30{
31 using namespace bke;
32 const static MultiValueMap<GeometryComponent::Type, AttrDomain> supported_types_and_domains =
33 []() {
35 supported_types_and_domains.add_multiple(
36 GeometryComponent::Type::Mesh,
37 {AttrDomain::Point, AttrDomain::Edge, AttrDomain::Face});
38 supported_types_and_domains.add(GeometryComponent::Type::Curve, AttrDomain::Curve);
39 supported_types_and_domains.add(GeometryComponent::Type::PointCloud, AttrDomain::Point);
40 supported_types_and_domains.add(GeometryComponent::Type::Instance, AttrDomain::Instance);
41 return supported_types_and_domains;
42 }();
43 return supported_types_and_domains;
44}
45
47 const bke::AttrDomain domain,
48 const OffsetIndices<int> src_offsets,
49 const OffsetIndices<int> dst_offsets,
50 const Span<int> old_by_new_map,
51 const bke::AttributeFilter &attribute_filter,
52 bke::MutableAttributeAccessor dst_attributes)
53{
54 src_attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
55 if (iter.domain != domain) {
56 return;
57 }
58 if (iter.data_type == bke::AttrType::String) {
59 return;
60 }
61 if (attribute_filter.allow_skip(iter.name)) {
62 return;
63 }
64 const GVArray src = *iter.get(domain);
66 iter.name, domain, iter.data_type);
67 if (!dst) {
68 return;
69 }
70
71 threading::parallel_for(old_by_new_map.index_range(), 1024, [&](const IndexRange range) {
72 for (const int new_i : range) {
73 const int old_i = old_by_new_map[new_i];
74 array_utils::copy(src.slice(src_offsets[old_i]), dst.span.slice(dst_offsets[new_i]));
75 }
76 });
77
78 dst.finish();
79 });
80}
81
82static Array<int> invert_permutation(const Span<int> permutation)
83{
84 Array<int> data(permutation.size());
85 threading::parallel_for(permutation.index_range(), 2048, [&](const IndexRange range) {
86 for (const int64_t i : range) {
87 data[permutation[i]] = i;
88 }
89 });
90 return data;
91}
92
93static void copy_and_reorder_mesh_verts(const Mesh &src_mesh,
94 const Span<int> old_by_new_map,
95 const bke::AttributeFilter &attribute_filter,
96 Mesh &dst_mesh)
97{
98 const bke::AttributeAccessor src_attributes = src_mesh.attributes();
99 bke::MutableAttributeAccessor dst_attributes = dst_mesh.attributes_for_write();
100
101 bke::gather_attributes(src_attributes,
104 attribute_filter,
105 old_by_new_map,
106 dst_attributes);
107
108 bke::copy_attributes(src_attributes,
111 bke::attribute_filter_with_skip_ref(attribute_filter, {".edge_verts"}),
112 dst_attributes);
113
114 bke::copy_attributes(src_attributes,
117 attribute_filter,
118 dst_attributes);
119
121 &dst_mesh.runtime->face_offsets_sharing_info);
123 src_mesh.runtime->face_offsets_sharing_info,
124 &dst_mesh.face_offset_indices,
125 &dst_mesh.runtime->face_offsets_sharing_info);
126
127 bke::copy_attributes(src_attributes,
130 bke::attribute_filter_with_skip_ref(attribute_filter, {".corner_vert"}),
131 dst_attributes);
132
133 const Array<int> new_by_old_map = invert_permutation(old_by_new_map);
134
135 dst_attributes.add<int2>(".edge_verts", bke::AttrDomain::Edge, bke::AttributeInitConstruct());
136 array_utils::gather(new_by_old_map.as_span(),
137 src_mesh.edges().cast<int>(),
138 dst_mesh.edges_for_write().cast<int>());
139
140 dst_attributes.add<int>(".corner_vert", bke::AttrDomain::Corner, bke::AttributeInitConstruct());
142 new_by_old_map.as_span(), src_mesh.corner_verts(), dst_mesh.corner_verts_for_write());
143}
144
145static void copy_and_reorder_mesh_edges(const Mesh &src_mesh,
146 const Span<int> old_by_new_map,
147 const bke::AttributeFilter &attribute_filter,
148 Mesh &dst_mesh)
149{
150 const bke::AttributeAccessor src_attributes = src_mesh.attributes();
151 bke::MutableAttributeAccessor dst_attributes = dst_mesh.attributes_for_write();
152
153 bke::copy_attributes(src_attributes,
156 attribute_filter,
157 dst_attributes);
158
159 bke::gather_attributes(src_attributes,
162 attribute_filter,
163 old_by_new_map,
164 dst_attributes);
165
166 bke::copy_attributes(src_attributes,
169 attribute_filter,
170 dst_attributes);
171
173 &dst_mesh.runtime->face_offsets_sharing_info);
175 src_mesh.runtime->face_offsets_sharing_info,
176 &dst_mesh.face_offset_indices,
177 &dst_mesh.runtime->face_offsets_sharing_info);
178
179 bke::copy_attributes(src_attributes,
182 bke::attribute_filter_with_skip_ref(attribute_filter, {".corner_edge"}),
183 dst_attributes);
184
185 const Array<int> new_by_old_map = invert_permutation(old_by_new_map);
186
187 dst_attributes.add<int>(".corner_edge", bke::AttrDomain::Corner, bke::AttributeInitConstruct());
189 new_by_old_map.as_span(), src_mesh.corner_edges(), dst_mesh.corner_edges_for_write());
190}
191
192static void copy_and_reorder_mesh_faces(const Mesh &src_mesh,
193 const Span<int> old_by_new_map,
194 const bke::AttributeFilter &attribute_filter,
195 Mesh &dst_mesh)
196{
197 const bke::AttributeAccessor src_attributes = src_mesh.attributes();
198 bke::MutableAttributeAccessor dst_attributes = dst_mesh.attributes_for_write();
199
200 bke::copy_attributes(src_attributes,
203 attribute_filter,
204 dst_attributes);
205
206 bke::copy_attributes(src_attributes,
209 attribute_filter,
210 dst_attributes);
211
212 bke::gather_attributes(src_attributes,
215 attribute_filter,
216 old_by_new_map,
217 dst_attributes);
218
219 const Span<int> old_offsets = src_mesh.face_offsets();
220 MutableSpan<int> new_offsets = dst_mesh.face_offsets_for_write();
221 offset_indices::gather_group_sizes(old_offsets, old_by_new_map, new_offsets);
225 old_offsets,
226 new_offsets.as_span(),
227 old_by_new_map,
228 attribute_filter,
229 dst_attributes);
230}
231
232static void copy_and_reorder_mesh(const Mesh &src_mesh,
233 const Span<int> old_by_new_map,
234 const bke::AttrDomain domain,
235 const bke::AttributeFilter &attribute_filter,
236 Mesh &dst_mesh)
237{
238 switch (domain) {
240 copy_and_reorder_mesh_verts(src_mesh, old_by_new_map, attribute_filter, dst_mesh);
241 break;
243 copy_and_reorder_mesh_edges(src_mesh, old_by_new_map, attribute_filter, dst_mesh);
244 break;
246 copy_and_reorder_mesh_faces(src_mesh, old_by_new_map, attribute_filter, dst_mesh);
247 break;
248 default:
249 break;
250 }
251 dst_mesh.tag_positions_changed();
252 dst_mesh.tag_topology_changed();
253}
254
255static void copy_and_reorder_points(const PointCloud &src_pointcloud,
256 const Span<int> old_by_new_map,
257 const bke::AttributeFilter &attribute_filter,
258 PointCloud &dst_pointcloud)
259{
260 bke::gather_attributes(src_pointcloud.attributes(),
263 attribute_filter,
264 old_by_new_map,
265 dst_pointcloud.attributes_for_write());
266 dst_pointcloud.tag_positions_changed();
267 dst_pointcloud.tag_radii_changed();
268}
269
270static void copy_and_reorder_curves(const bke::CurvesGeometry &src_curves,
271 const Span<int> old_by_new_map,
272 const bke::AttributeFilter &attribute_filter,
273 bke::CurvesGeometry &dst_curves)
274{
278 attribute_filter,
279 old_by_new_map,
280 dst_curves.attributes_for_write());
281
282 const Span<int> old_offsets = src_curves.offsets();
283 MutableSpan<int> new_offsets = dst_curves.offsets_for_write();
284 offset_indices::gather_group_sizes(old_offsets, old_by_new_map, new_offsets);
286
289 old_offsets,
290 new_offsets.as_span(),
291 old_by_new_map,
292 attribute_filter,
293 dst_curves.attributes_for_write());
294 dst_curves.tag_topology_changed();
295 if (src_curves.nurbs_has_custom_knots()) {
297 IndexMaskMemory memory;
299 src_curves, IndexMask::from_indices(old_by_new_map, memory), 0, dst_curves);
300 }
301}
302
303static void copy_and_reorder_instaces(const bke::Instances &src_instances,
304 const Span<int> old_by_new_map,
305 const bke::AttributeFilter &attribute_filter,
306 bke::Instances &dst_instances)
307{
308 dst_instances.resize(src_instances.instances_num());
309
310 bke::gather_attributes(src_instances.attributes(),
313 attribute_filter,
314 old_by_new_map,
315 dst_instances.attributes_for_write());
316
317 for (const bke::InstanceReference &reference : src_instances.references()) {
318 dst_instances.add_reference(reference);
319 }
320 BLI_assert(src_instances.references() == dst_instances.references());
321
322 const Span<float4x4> old_transforms = src_instances.transforms();
323 MutableSpan<float4x4> new_transforms = dst_instances.transforms_for_write();
324 array_utils::gather(old_transforms, old_by_new_map, new_transforms);
325}
326
327Mesh *reorder_mesh(const Mesh &src_mesh,
328 Span<int> old_by_new_map,
329 bke::AttrDomain domain,
330 const bke::AttributeFilter &attribute_filter)
331{
333 src_mesh.verts_num, src_mesh.edges_num, src_mesh.faces_num, src_mesh.corners_num);
334 BKE_mesh_copy_parameters_for_eval(dst_mesh, &src_mesh);
335 copy_and_reorder_mesh(src_mesh, old_by_new_map, domain, attribute_filter, *dst_mesh);
336 return dst_mesh;
337}
338
339PointCloud *reorder_points(const PointCloud &src_pointcloud,
340 Span<int> old_by_new_map,
341 const bke::AttributeFilter &attribute_filter)
342{
343 PointCloud *dst_pointcloud = bke::pointcloud_new_no_attributes(src_pointcloud.totpoint);
344 copy_and_reorder_points(src_pointcloud, old_by_new_map, attribute_filter, *dst_pointcloud);
345 return dst_pointcloud;
346}
347
349 Span<int> old_by_new_map,
350 const bke::AttributeFilter &attribute_filter)
351{
353 src_curves.curves_num());
355 copy_and_reorder_curves(src_curves, old_by_new_map, attribute_filter, dst_curves);
356 return dst_curves;
357}
358
359Curves *reorder_curves(const Curves &src_curves,
360 Span<int> old_by_new_map,
361 const bke::AttributeFilter &attribute_filter)
362{
363 const bke::CurvesGeometry src_curve_geometry = src_curves.geometry.wrap();
364 Curves *dst_curves = bke::curves_new_nomain(0, 0);
365 dst_curves->geometry.wrap() = reorder_curves_geometry(
366 src_curve_geometry, old_by_new_map, attribute_filter);
367 return dst_curves;
368}
369
371 Span<int> old_by_new_map,
372 const bke::AttributeFilter &attribute_filter)
373{
374 bke::Instances *dst_instances = new bke::Instances(src_instances);
375 copy_and_reorder_instaces(src_instances, old_by_new_map, attribute_filter, *dst_instances);
376 return dst_instances;
377}
378
380 const Span<int> old_by_new_map,
381 const bke::AttrDomain domain,
382 const bke::AttributeFilter &attribute_filter)
383{
384 BLI_assert(!src_component.is_empty());
385
386 if (const bke::MeshComponent *src_mesh_component = dynamic_cast<const bke::MeshComponent *>(
387 &src_component))
388 {
389 Mesh *result_mesh = reorder_mesh(
390 *src_mesh_component->get(), old_by_new_map, domain, attribute_filter);
391 return bke::GeometryComponentPtr(new bke::MeshComponent(result_mesh));
392 }
393 if (const bke::PointCloudComponent *src_points_component =
394 dynamic_cast<const bke::PointCloudComponent *>(&src_component))
395 {
396 PointCloud *result_pointcloud = reorder_points(
397 *src_points_component->get(), old_by_new_map, attribute_filter);
398 return bke::GeometryComponentPtr(new bke::PointCloudComponent(result_pointcloud));
399 }
400 if (const bke::CurveComponent *src_curves_component = dynamic_cast<const bke::CurveComponent *>(
401 &src_component))
402 {
403 Curves *result_curves = reorder_curves(
404 *src_curves_component->get(), old_by_new_map, attribute_filter);
405 return bke::GeometryComponentPtr(new bke::CurveComponent(result_curves));
406 }
407 if (const bke::InstancesComponent *src_instances_component =
408 dynamic_cast<const bke::InstancesComponent *>(&src_component))
409 {
410 bke::Instances *result_instances = reorder_instaces(
411 *src_instances_component->get(), old_by_new_map, attribute_filter);
412 return bke::GeometryComponentPtr(new bke::InstancesComponent(result_instances));
413 }
414
416 return {};
417}
418
419} // namespace blender::geometry
Low-level operations for curves.
Low-level operations for curves.
support for deformation groups and hooks.
void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
Definition deform.cc:73
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
General operations for point clouds.
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
BMesh const char void * data
AttributeSet attributes
static IndexMask from_indices(Span< T > indices, IndexMaskMemory &memory)
void add_multiple(const Key &key, Span< Value > values)
void add(const Key &key, const Value &value)
constexpr Span< T > as_span() const
Definition BLI_span.hh:661
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader get() const
MutableAttributeAccessor attributes_for_write()
AttributeAccessor attributes() const
MutableSpan< int > offsets_for_write()
bool nurbs_has_custom_knots() const
virtual bool is_empty() const
int add_reference(const InstanceReference &reference)
Definition instances.cc:261
Span< float4x4 > transforms() const
Definition instances.cc:228
Span< InstanceReference > references() const
Definition instances.cc:275
void resize(int capacity)
Definition instances.cc:191
bke::MutableAttributeAccessor attributes_for_write()
Definition instances.cc:69
bke::AttributeAccessor attributes() const
Definition instances.cc:64
int instances_num() const
Definition instances.cc:393
MutableSpan< float4x4 > transforms_for_write()
Definition instances.cc:235
bool add(const StringRef attribute_id, const AttrDomain domain, const AttrType data_type, const AttributeInit &initializer)
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, AttrType data_type)
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
void gather_custom_knots(const bke::CurvesGeometry &src, const IndexMask &src_curves, int dst_curve_offset, bke::CurvesGeometry &dst)
ImplicitSharingPtr< GeometryComponent > GeometryComponentPtr
void copy_attributes(const AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, MutableAttributeAccessor dst_attributes)
void gather_attributes(AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, const IndexMask &selection, MutableAttributeAccessor dst_attributes)
auto attribute_filter_with_skip_ref(AttributeFilter filter, const Span< StringRef > skip)
CurvesGeometry curves_new_no_attributes(int point_num, int curve_num)
Mesh * mesh_new_no_attributes(int verts_num, int edges_num, int faces_num, int corners_num)
PointCloud * pointcloud_new_no_attributes(int totpoint)
Curves * curves_new_nomain(int points_num, int curves_num)
static void reorder_attributes_group_to_group(const bke::AttributeAccessor src_attributes, const bke::AttrDomain domain, const OffsetIndices< int > src_offsets, const OffsetIndices< int > dst_offsets, const Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter, bke::MutableAttributeAccessor dst_attributes)
Definition reorder.cc:46
static void copy_and_reorder_instaces(const bke::Instances &src_instances, const Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter, bke::Instances &dst_instances)
Definition reorder.cc:303
static Array< int > invert_permutation(const Span< int > permutation)
Definition randomize.cc:35
Mesh * reorder_mesh(const Mesh &src_mesh, Span< int > old_by_new_map, bke::AttrDomain domain, const bke::AttributeFilter &attribute_filter)
Definition reorder.cc:327
PointCloud * reorder_points(const PointCloud &src_pointcloud, Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter)
Definition reorder.cc:339
static void copy_and_reorder_points(const PointCloud &src_pointcloud, const Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter, PointCloud &dst_pointcloud)
Definition reorder.cc:255
static void copy_and_reorder_curves(const bke::CurvesGeometry &src_curves, const Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter, bke::CurvesGeometry &dst_curves)
Definition reorder.cc:270
static void copy_and_reorder_mesh_verts(const Mesh &src_mesh, const Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter, Mesh &dst_mesh)
Definition reorder.cc:93
bke::CurvesGeometry reorder_curves_geometry(const bke::CurvesGeometry &src_curves, Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter)
Definition reorder.cc:348
const MultiValueMap< bke::GeometryComponent::Type, bke::AttrDomain > & components_supported_reordering()
Definition reorder.cc:29
static void copy_and_reorder_mesh_faces(const Mesh &src_mesh, const Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter, Mesh &dst_mesh)
Definition reorder.cc:192
static void copy_and_reorder_mesh_edges(const Mesh &src_mesh, const Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter, Mesh &dst_mesh)
Definition reorder.cc:145
bke::GeometryComponentPtr reordered_component(const bke::GeometryComponent &src_component, Span< int > old_by_new_map, bke::AttrDomain domain, const bke::AttributeFilter &attribute_filter)
Definition reorder.cc:379
bke::Instances * reorder_instaces(const bke::Instances &src_instances, Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter)
Definition reorder.cc:370
static void copy_and_reorder_mesh(const Mesh &src_mesh, const Span< int > old_by_new_map, const bke::AttrDomain domain, const bke::AttributeFilter &attribute_filter, Mesh &dst_mesh)
Definition reorder.cc:232
Curves * reorder_curves(const Curves &src_curves, Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter)
Definition reorder.cc:359
void copy_shared_pointer(T *src_ptr, const ImplicitSharingInfo *src_sharing_info, T **r_dst_ptr, const ImplicitSharingInfo **r_dst_sharing_info)
void free_shared_data(T **data, const ImplicitSharingInfo **sharing_info)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
void gather_group_sizes(OffsetIndices< int > offsets, const IndexMask &mask, MutableSpan< int > sizes)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
VecBase< int32_t, 2 > int2
ListBase vertex_group_names
CurvesGeometry geometry
int corners_num
int edges_num
MeshRuntimeHandle * runtime
int * face_offset_indices
int faces_num
int verts_num
bool allow_skip(const StringRef name) const