diff options
Diffstat (limited to 'source/blender/geometry/intern/mesh_to_curve_convert.cc')
-rw-r--r-- | source/blender/geometry/intern/mesh_to_curve_convert.cc | 152 |
1 files changed, 51 insertions, 101 deletions
diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc index 121a1b5de39..0c2377fde6d 100644 --- a/source/blender/geometry/intern/mesh_to_curve_convert.cc +++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc @@ -2,7 +2,6 @@ #include "BLI_array.hh" #include "BLI_set.hh" -#include "BLI_string_ref.hh" #include "BLI_task.hh" #include "DNA_mesh_types.h" @@ -10,85 +9,48 @@ #include "BKE_attribute_access.hh" #include "BKE_attribute_math.hh" +#include "BKE_curves.hh" #include "BKE_geometry_set.hh" -#include "BKE_spline.hh" #include "GEO_mesh_to_curve.hh" namespace blender::geometry { template<typename T> -static void copy_attribute_to_points(const VArray<T> &source_data, - Span<int> map, - MutableSpan<T> dest_data) +static void copy_with_map(const VArray<T> &src, Span<int> map, MutableSpan<T> dst) { - for (const int point_index : map.index_range()) { - const int vert_index = map[point_index]; - dest_data[point_index] = source_data[vert_index]; - } + devirtualize_varray(src, [&](const auto &src) { + threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) { + for (const int i : range) { + const int vert_index = map[i]; + dst[i] = src[vert_index]; + } + }); + }); } -static std::unique_ptr<CurveEval> create_curve_from_vert_indices( - const MeshComponent &mesh_component, Span<Vector<int>> vert_indices, IndexRange cyclic_splines) +static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_component, + const Span<int> vert_indices, + const Span<int> curve_offsets, + const IndexRange cyclic_splines) { - std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>(); - curve->resize(vert_indices.size()); - - MutableSpan<SplinePtr> splines = curve->splines(); + Curves *curves_id = bke::curves_new_nomain(vert_indices.size(), curve_offsets.size()); + bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry); + curves.offsets().drop_back(1).copy_from(curve_offsets); + curves.offsets().last() = vert_indices.size(); + curves.curve_types().fill(CURVE_TYPE_POLY); - for (const int i : vert_indices.index_range()) { - splines[i] = std::make_unique<PolySpline>(); - splines[i]->resize(vert_indices[i].size()); - } - for (const int i : cyclic_splines) { - splines[i]->set_cyclic(true); - } + curves.cyclic().fill(false); + curves.cyclic().slice(cyclic_splines).fill(true); Set<bke::AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids(); - /* Copy builtin control point attributes. */ - if (source_attribute_ids.contains("tilt")) { - const VArray<float> tilt_attribute = mesh_component.attribute_get_for_read<float>( - "tilt", ATTR_DOMAIN_POINT, 0.0f); - threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) { - for (const int i : range) { - copy_attribute_to_points<float>(tilt_attribute, vert_indices[i], splines[i]->tilts()); - } - }); - source_attribute_ids.remove_contained("tilt"); - } - else { - for (SplinePtr &spline : splines) { - spline->tilts().fill(0.0f); - } - } - - if (source_attribute_ids.contains("radius")) { - const VArray<float> radius_attribute = mesh_component.attribute_get_for_read<float>( - "radius", ATTR_DOMAIN_POINT, 1.0f); - threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) { - for (const int i : range) { - copy_attribute_to_points<float>(radius_attribute, vert_indices[i], splines[i]->radii()); - } - }); - source_attribute_ids.remove_contained("radius"); - } - else { - for (SplinePtr &spline : splines) { - spline->radii().fill(1.0f); - } - } - - VArray<float3> mesh_positions = mesh_component.attribute_get_for_read( - "position", ATTR_DOMAIN_POINT, float3(0)); - threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { - for (const int i : range) { - copy_attribute_to_points(mesh_positions, vert_indices[i], splines[i]->positions()); - } - }); + CurveComponent curves_component; + curves_component.replace(curves_id, GeometryOwnershipType::Editable); for (const bke::AttributeIDRef &attribute_id : source_attribute_ids) { - if (mesh_component.attribute_is_builtin(attribute_id)) { + if (mesh_component.attribute_is_builtin(attribute_id) && + !curves_component.attribute_is_builtin(attribute_id)) { /* Don't copy attributes that are built-in on meshes but not on curves. */ continue; } @@ -105,33 +67,24 @@ static std::unique_ptr<CurveEval> create_curve_from_vert_indices( continue; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute.type()); - - threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { - for (const int i : range) { - /* Create attribute on the spline points. */ - splines[i]->attributes.create(attribute_id, data_type); - std::optional<fn::GMutableSpan> spline_attribute = splines[i]->attributes.get_for_write( - attribute_id); - BLI_assert(spline_attribute); - - /* Copy attribute based on the map for this spline. */ - attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) { - using T = decltype(dummy); - copy_attribute_to_points<T>( - mesh_attribute.typed<T>(), vert_indices[i], spline_attribute->typed<T>()); - }); - } + /* Copy attribute based on the map for this spline. */ + attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) { + using T = decltype(dummy); + bke::OutputAttribute_Typed<T> attribute = + curves_component.attribute_try_get_for_output_only<T>(attribute_id, ATTR_DOMAIN_POINT); + copy_with_map<T>(mesh_attribute.typed<T>(), vert_indices, attribute.as_span()); + attribute.save(); }); } - curve->assert_valid_point_attributes(); - return curve; + return curves_id; } struct CurveFromEdgesOutput { /** The indices in the mesh for each control point of each result splines. */ - Vector<Vector<int>> vert_indices; + Vector<int> vert_indices; + /** The first index of each curve in the result. */ + Vector<int> curve_offsets; /** A subset of splines that should be set cyclic. */ IndexRange cyclic_splines; }; @@ -139,7 +92,9 @@ struct CurveFromEdgesOutput { static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts, Span<std::pair<int, int>> edges) { - Vector<Vector<int>> vert_indices; + Vector<int> vert_indices; + vert_indices.reserve(edges.size()); + Vector<int> curve_offsets; /* Compute the number of edges connecting to each vertex. */ Array<int> neighbor_count(verts.size(), 0); @@ -191,15 +146,16 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts, continue; } - Vector<int> spline_indices; - spline_indices.append(current_vert); + /* Start a new curve in the output. */ + curve_offsets.append(vert_indices.size()); + vert_indices.append(current_vert); /* Follow connected edges until we read a vertex with more than two connected edges. */ while (true) { int last_vert = current_vert; current_vert = next_vert; - spline_indices.append(current_vert); + vert_indices.append(current_vert); unused_edges[current_vert]--; unused_edges[last_vert]--; @@ -212,13 +168,11 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts, const int next_b = neighbors[offset + 1]; next_vert = (last_vert == next_a) ? next_b : next_a; } - - vert_indices.append(std::move(spline_indices)); } } /* All splines added after this are cyclic. */ - const int cyclic_start = vert_indices.size(); + const int cyclic_start = curve_offsets.size(); /* All remaining edges are part of cyclic splines (we skipped vertices with two edges before). */ for (const int start_vert : verts.index_range()) { @@ -229,16 +183,15 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts, int current_vert = start_vert; int next_vert = neighbors[neighbor_offsets[current_vert]]; - Vector<int> spline_indices; - - spline_indices.append(current_vert); + curve_offsets.append(vert_indices.size()); + vert_indices.append(current_vert); /* Follow connected edges until we loop back to the start vertex. */ while (next_vert != start_vert) { const int last_vert = current_vert; current_vert = next_vert; - spline_indices.append(current_vert); + vert_indices.append(current_vert); unused_edges[current_vert]--; unused_edges[last_vert]--; @@ -247,13 +200,11 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts, const int next_b = neighbors[offset + 1]; next_vert = (last_vert == next_a) ? next_b : next_a; } - - vert_indices.append(std::move(spline_indices)); } - const int final_size = vert_indices.size(); + const IndexRange cyclic_curves = curve_offsets.index_range().drop_front(cyclic_start); - return {std::move(vert_indices), IndexRange(cyclic_start, final_size - cyclic_start)}; + return {std::move(vert_indices), std::move(curve_offsets), cyclic_curves}; } /** @@ -270,8 +221,7 @@ static Vector<std::pair<int, int>> get_selected_edges(const Mesh &mesh, const In return selected_edges; } -std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_component, - const IndexMask selection) +Curves *mesh_to_curve_convert(const MeshComponent &mesh_component, const IndexMask selection) { const Mesh &mesh = *mesh_component.get_for_read(); Vector<std::pair<int, int>> selected_edges = get_selected_edges(*mesh_component.get_for_read(), @@ -280,7 +230,7 @@ std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_compo selected_edges); return create_curve_from_vert_indices( - mesh_component, output.vert_indices, output.cyclic_splines); + mesh_component, output.vert_indices, output.curve_offsets, output.cyclic_splines); } } // namespace blender::geometry |