Blender V4.3
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
6#include "BKE_attribute.hh"
8#include "BKE_curves.hh"
9#include "BKE_geometry_set.hh"
10#include "BKE_instances.hh"
11#include "BKE_mesh.hh"
12#include "BKE_pointcloud.hh"
13
14#include "BLI_array.hh"
15#include "BLI_array_utils.hh"
17
18#include "DNA_curves_types.h"
19#include "DNA_mesh_types.h"
21
22#include "GEO_reorder.hh"
23
24namespace blender::geometry {
25
26const MultiValueMap<bke::GeometryComponent::Type, bke::AttrDomain> &
28{
29 using namespace bke;
30 const static MultiValueMap<GeometryComponent::Type, AttrDomain> supported_types_and_domains =
31 []() {
33 supported_types_and_domains.add_multiple(
35 {AttrDomain::Point, AttrDomain::Edge, AttrDomain::Face});
36 supported_types_and_domains.add(GeometryComponent::Type::Curve, AttrDomain::Curve);
37 supported_types_and_domains.add(GeometryComponent::Type::PointCloud, AttrDomain::Point);
38 supported_types_and_domains.add(GeometryComponent::Type::Instance, AttrDomain::Instance);
39 return supported_types_and_domains;
40 }();
41 return supported_types_and_domains;
42}
43
45 const bke::AttrDomain domain,
46 const OffsetIndices<int> src_offsets,
47 const OffsetIndices<int> dst_offsets,
48 const Span<int> old_by_new_map,
49 bke::MutableAttributeAccessor dst_attributes)
50{
51 src_attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
52 if (iter.domain != domain) {
53 return;
54 }
55 if (iter.data_type == CD_PROP_STRING) {
56 return;
57 }
58 const GVArray src = *iter.get(domain);
60 iter.name, domain, iter.data_type);
61 if (!dst) {
62 return;
63 }
64
65 threading::parallel_for(old_by_new_map.index_range(), 1024, [&](const IndexRange range) {
66 for (const int new_i : range) {
67 const int old_i = old_by_new_map[new_i];
68 array_utils::copy(src.slice(src_offsets[old_i]), dst.span.slice(dst_offsets[new_i]));
69 }
70 });
71
72 dst.finish();
73 });
74}
75
76static Array<int> invert_permutation(const Span<int> permutation)
77{
78 Array<int> data(permutation.size());
79 threading::parallel_for(permutation.index_range(), 2048, [&](const IndexRange range) {
80 for (const int64_t i : range) {
81 data[permutation[i]] = i;
82 }
83 });
84 return data;
85}
86
87static void reorder_mesh_verts_exec(const Mesh &src_mesh,
88 const Span<int> old_by_new_map,
89 Mesh &dst_mesh)
90{
91 bke::gather_attributes(src_mesh.attributes(),
92 bke::AttrDomain::Point,
93 bke::AttrDomain::Point,
94 {},
95 old_by_new_map,
96 dst_mesh.attributes_for_write());
97 const Array<int> new_by_old_map = invert_permutation(old_by_new_map);
98 array_utils::gather(new_by_old_map.as_span(),
99 dst_mesh.edges().cast<int>(),
100 dst_mesh.edges_for_write().cast<int>());
101 array_utils::gather(
102 new_by_old_map.as_span(), dst_mesh.corner_verts(), dst_mesh.corner_verts_for_write());
103}
104
105static void reorder_mesh_edges_exec(const Mesh &src_mesh,
106 const Span<int> old_by_new_map,
107 Mesh &dst_mesh)
108{
109 bke::gather_attributes(src_mesh.attributes(),
110 bke::AttrDomain::Edge,
111 bke::AttrDomain::Edge,
112 {},
113 old_by_new_map,
114 dst_mesh.attributes_for_write());
115 const Array<int> new_by_old_map = invert_permutation(old_by_new_map);
116 array_utils::gather(
117 new_by_old_map.as_span(), dst_mesh.corner_edges(), dst_mesh.corner_edges_for_write());
118}
119
120static void reorder_mesh_faces_exec(const Mesh &src_mesh,
121 const Span<int> old_by_new_map,
122 Mesh &dst_mesh)
123{
124 bke::gather_attributes(src_mesh.attributes(),
125 bke::AttrDomain::Face,
126 bke::AttrDomain::Face,
127 {},
128 old_by_new_map,
129 dst_mesh.attributes_for_write());
130 const Span<int> old_offsets = src_mesh.face_offsets();
131 MutableSpan<int> new_offsets = dst_mesh.face_offsets_for_write();
132 offset_indices::gather_group_sizes(old_offsets, old_by_new_map, new_offsets);
133 offset_indices::accumulate_counts_to_offsets(new_offsets);
135 bke::AttrDomain::Corner,
136 old_offsets,
137 new_offsets.as_span(),
138 old_by_new_map,
139 dst_mesh.attributes_for_write());
140}
141
142static void reorder_mesh_exec(const Mesh &src_mesh,
143 const Span<int> old_by_new_map,
144 const bke::AttrDomain domain,
145 Mesh &dst_mesh)
146{
147 switch (domain) {
148 case bke::AttrDomain::Point:
149 reorder_mesh_verts_exec(src_mesh, old_by_new_map, dst_mesh);
150 break;
151 case bke::AttrDomain::Edge:
152 reorder_mesh_edges_exec(src_mesh, old_by_new_map, dst_mesh);
153 break;
154 case bke::AttrDomain::Face:
155 reorder_mesh_faces_exec(src_mesh, old_by_new_map, dst_mesh);
156 break;
157 default:
158 break;
159 }
160 dst_mesh.tag_positions_changed();
161 dst_mesh.tag_topology_changed();
162}
163
164static void reorder_points_exec(const PointCloud &src_pointcloud,
165 const Span<int> old_by_new_map,
166 PointCloud &dst_pointcloud)
167{
168 bke::gather_attributes(src_pointcloud.attributes(),
169 bke::AttrDomain::Point,
170 bke::AttrDomain::Point,
171 {},
172 old_by_new_map,
173 dst_pointcloud.attributes_for_write());
174 dst_pointcloud.tag_positions_changed();
175 dst_pointcloud.tag_radii_changed();
176}
177
178static void reorder_curves_exec(const bke::CurvesGeometry &src_curves,
179 const Span<int> old_by_new_map,
180 bke::CurvesGeometry &dst_curves)
181{
182 bke::gather_attributes(src_curves.attributes(),
183 bke::AttrDomain::Curve,
184 bke::AttrDomain::Curve,
185 {},
186 old_by_new_map,
187 dst_curves.attributes_for_write());
188
189 const Span<int> old_offsets = src_curves.offsets();
190 MutableSpan<int> new_offsets = dst_curves.offsets_for_write();
191 offset_indices::gather_group_sizes(old_offsets, old_by_new_map, new_offsets);
192 offset_indices::accumulate_counts_to_offsets(new_offsets);
193
195 bke::AttrDomain::Point,
196 old_offsets,
197 new_offsets.as_span(),
198 old_by_new_map,
199 dst_curves.attributes_for_write());
200 dst_curves.tag_topology_changed();
201}
202
203static void reorder_instaces_exec(const bke::Instances &src_instances,
204 const Span<int> old_by_new_map,
205 bke::Instances &dst_instances)
206{
207 bke::gather_attributes(src_instances.attributes(),
208 bke::AttrDomain::Instance,
209 bke::AttrDomain::Instance,
210 {},
211 old_by_new_map,
212 dst_instances.attributes_for_write());
213}
214
215static void clean_unused_attributes(const bke::AttributeFilter &attribute_filter,
217{
218 Vector<std::string> unused_ids;
219 attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
220 if (!bke::attribute_name_is_anonymous(iter.name)) {
221 return;
222 }
223 if (iter.data_type == CD_PROP_STRING) {
224 return;
225 }
226 if (!attribute_filter.allow_skip(iter.name)) {
227 return;
228 }
229 unused_ids.append(iter.name);
230 });
231
232 for (const std::string &unused_id : unused_ids) {
233 attributes.remove(unused_id);
234 }
235}
236
237Mesh *reorder_mesh(const Mesh &src_mesh,
238 Span<int> old_by_new_map,
239 bke::AttrDomain domain,
240 const bke::AttributeFilter &attribute_filter)
241{
242 Mesh *dst_mesh = BKE_mesh_copy_for_eval(src_mesh);
243 clean_unused_attributes(attribute_filter, dst_mesh->attributes_for_write());
244 reorder_mesh_exec(src_mesh, old_by_new_map, domain, *dst_mesh);
245 return dst_mesh;
246}
247
248PointCloud *reorder_points(const PointCloud &src_pointcloud,
249 Span<int> old_by_new_map,
250 const bke::AttributeFilter &attribute_filter)
251{
252 PointCloud *dst_pointcloud = BKE_pointcloud_copy_for_eval(&src_pointcloud);
253 clean_unused_attributes(attribute_filter, dst_pointcloud->attributes_for_write());
254 reorder_points_exec(src_pointcloud, old_by_new_map, *dst_pointcloud);
255 return dst_pointcloud;
256}
257
259 Span<int> old_by_new_map,
260 const bke::AttributeFilter &attribute_filter)
261{
262 bke::CurvesGeometry dst_curves = bke::CurvesGeometry(src_curves);
263 clean_unused_attributes(attribute_filter, dst_curves.attributes_for_write());
264 reorder_curves_exec(src_curves, old_by_new_map, dst_curves);
265 return dst_curves;
266}
267
268Curves *reorder_curves(const Curves &src_curves,
269 Span<int> old_by_new_map,
270 const bke::AttributeFilter &attribute_filter)
271{
272 const bke::CurvesGeometry src_curve_geometry = src_curves.geometry.wrap();
273 Curves *dst_curves = BKE_curves_copy_for_eval(&src_curves);
274 dst_curves->geometry.wrap() = reorder_curves_geometry(
275 src_curve_geometry, old_by_new_map, attribute_filter);
276 return dst_curves;
277}
278
280 Span<int> old_by_new_map,
281 const bke::AttributeFilter &attribute_filter)
282{
283 bke::Instances *dst_instances = new bke::Instances(src_instances);
284 clean_unused_attributes(attribute_filter, dst_instances->attributes_for_write());
285 reorder_instaces_exec(src_instances, old_by_new_map, *dst_instances);
286 return dst_instances;
287}
288
290 const Span<int> old_by_new_map,
291 const bke::AttrDomain domain,
292 const bke::AttributeFilter &attribute_filter)
293{
294 BLI_assert(!src_component.is_empty());
295
296 if (const bke::MeshComponent *src_mesh_component = dynamic_cast<const bke::MeshComponent *>(
297 &src_component))
298 {
299 Mesh *result_mesh = reorder_mesh(
300 *src_mesh_component->get(), old_by_new_map, domain, attribute_filter);
301 return bke::GeometryComponentPtr(new bke::MeshComponent(result_mesh));
302 }
303 else if (const bke::PointCloudComponent *src_points_component =
304 dynamic_cast<const bke::PointCloudComponent *>(&src_component))
305 {
306 PointCloud *result_point_cloud = reorder_points(
307 *src_points_component->get(), old_by_new_map, attribute_filter);
308 return bke::GeometryComponentPtr(new bke::PointCloudComponent(result_point_cloud));
309 }
310 else if (const bke::CurveComponent *src_curves_component =
311 dynamic_cast<const bke::CurveComponent *>(&src_component))
312 {
313 Curves *result_curves = reorder_curves(
314 *src_curves_component->get(), old_by_new_map, attribute_filter);
315 return bke::GeometryComponentPtr(new bke::CurveComponent(result_curves));
316 }
317 else if (const bke::InstancesComponent *src_instances_component =
318 dynamic_cast<const bke::InstancesComponent *>(&src_component))
319 {
320 bke::Instances *result_instances = reorder_instaces(
321 *src_instances_component->get(), old_by_new_map, attribute_filter);
322 return bke::GeometryComponentPtr(new bke::InstancesComponent(result_instances));
323 }
324
326 return {};
327}
328
329} // namespace blender::geometry
struct Curves * BKE_curves_copy_for_eval(const struct Curves *curves_src)
Low-level operations for curves.
Mesh * BKE_mesh_copy_for_eval(const Mesh &source)
General operations for point clouds.
PointCloud * BKE_pointcloud_copy_for_eval(const PointCloud *pointcloud_src)
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
@ CD_PROP_STRING
AttributeSet attributes
Span< T > as_span() const
Definition BLI_array.hh:232
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:662
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
void append(const T &value)
void remove(const int64_t index)
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader get() const
MutableAttributeAccessor attributes_for_write()
MutableSpan< int > offsets_for_write()
virtual bool is_empty() const
bke::MutableAttributeAccessor attributes_for_write()
bke::AttributeAccessor attributes() const
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
static void reorder_instaces_exec(const bke::Instances &src_instances, const Span< int > old_by_new_map, bke::Instances &dst_instances)
Definition reorder.cc:203
static void reorder_curves_exec(const bke::CurvesGeometry &src_curves, const Span< int > old_by_new_map, bke::CurvesGeometry &dst_curves)
Definition reorder.cc:178
static void reorder_mesh_faces_exec(const Mesh &src_mesh, const Span< int > old_by_new_map, Mesh &dst_mesh)
Definition reorder.cc:120
static Array< int > invert_permutation(const Span< int > permutation)
Definition reorder.cc:76
Mesh * reorder_mesh(const Mesh &src_mesh, Span< int > old_by_new_map, bke::AttrDomain domain, const bke::AttributeFilter &attribute_filter)
Definition reorder.cc:237
static void reorder_mesh_verts_exec(const Mesh &src_mesh, const Span< int > old_by_new_map, Mesh &dst_mesh)
Definition reorder.cc:87
static void clean_unused_attributes(const bke::AttributeFilter &attribute_filter, bke::MutableAttributeAccessor attributes)
Definition reorder.cc:215
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, bke::MutableAttributeAccessor dst_attributes)
Definition reorder.cc:44
PointCloud * reorder_points(const PointCloud &src_pointcloud, Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter)
Definition reorder.cc:248
static void reorder_mesh_exec(const Mesh &src_mesh, const Span< int > old_by_new_map, const bke::AttrDomain domain, Mesh &dst_mesh)
Definition reorder.cc:142
static void reorder_mesh_edges_exec(const Mesh &src_mesh, const Span< int > old_by_new_map, Mesh &dst_mesh)
Definition reorder.cc:105
static void reorder_points_exec(const PointCloud &src_pointcloud, const Span< int > old_by_new_map, PointCloud &dst_pointcloud)
Definition reorder.cc:164
bke::CurvesGeometry reorder_curves_geometry(const bke::CurvesGeometry &src_curves, Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter)
Definition reorder.cc:258
const MultiValueMap< bke::GeometryComponent::Type, bke::AttrDomain > & components_supported_reordering()
Definition reorder.cc:27
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:289
bke::Instances * reorder_instaces(const bke::Instances &src_instances, Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter)
Definition reorder.cc:279
Curves * reorder_curves(const Curves &src_curves, Span< int > old_by_new_map, const bke::AttributeFilter &attribute_filter)
Definition reorder.cc:268
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:95
CurvesGeometry geometry
bool allow_skip(const StringRef name) const