Cleanup: Remove spline add_point method, refactor mesh to curve node

It's better to calculate the size of a spline before creating it, and this
should simplify refactoring to a data structure that stores all point
attribute contiguously (see T94193). The mesh to curve conversion is
simplified slightly now, it creates the curve output after gathering all
of the result vertex indices. This should be more efficient too, since
it only grows an index vector for each spline, not a whole spline.
This commit is contained in:
Hans Goudey 2021-12-22 17:39:35 -06:00
parent c593db5a2f
commit 60c59d7d61
Notes: blender-bot 2023-02-14 11:42:40 +01:00
Referenced by commit 1931387799, Fix: Curve trim node test failure
6 changed files with 67 additions and 106 deletions

View File

@ -330,17 +330,6 @@ class BezierSpline final : public Spline {
int resolution() const;
void set_resolution(const int value);
/**
* \warning Call #reallocate on the spline's attributes after adding all points.
*/
void add_point(const blender::float3 position,
const HandleType handle_type_left,
const blender::float3 handle_position_left,
const HandleType handle_type_right,
const blender::float3 handle_position_right,
const float radius,
const float tilt);
void resize(const int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
@ -567,14 +556,6 @@ class NURBSpline final : public Spline {
uint8_t order() const;
void set_order(const uint8_t value);
/**
* \warning Call #reallocate on the spline's attributes after adding all points.
*/
void add_point(const blender::float3 position,
const float radius,
const float tilt,
const float weight);
bool check_valid_size_and_order() const;
int knots_size() const;
@ -634,11 +615,6 @@ class PolySpline final : public Spline {
int size() const final;
/**
* \warning Call #reallocate on the spline's attributes after adding all points.
*/
void add_point(const blender::float3 position, const float radius, const float tilt);
void resize(const int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;

View File

@ -762,7 +762,10 @@ static CurveEval get_curve_single_vert()
{
CurveEval curve;
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
spline->add_point(float3(0), 0, 0.0f);
spline->resize(1.0f);
spline->positions().fill(float3(0));
spline->radii().fill(1.0f);
spline->tilts().fill(0.0f);
curve.add_spline(std::move(spline));
return curve;

View File

@ -70,24 +70,6 @@ void BezierSpline::set_resolution(const int value)
this->mark_cache_invalid();
}
void BezierSpline::add_point(const float3 position,
const HandleType handle_type_left,
const float3 handle_position_left,
const HandleType handle_type_right,
const float3 handle_position_right,
const float radius,
const float tilt)
{
handle_types_left_.append(handle_type_left);
handle_positions_left_.append(handle_position_left);
positions_.append(position);
handle_types_right_.append(handle_type_right);
handle_positions_right_.append(handle_position_right);
radii_.append(radius);
tilts_.append(tilt);
this->mark_cache_invalid();
}
void BezierSpline::resize(const int size)
{
handle_types_left_.resize(size);

View File

@ -81,19 +81,6 @@ void NURBSpline::set_order(const uint8_t value)
this->mark_cache_invalid();
}
void NURBSpline::add_point(const float3 position,
const float radius,
const float tilt,
const float weight)
{
positions_.append(position);
radii_.append(radius);
tilts_.append(tilt);
weights_.append(weight);
knots_dirty_ = true;
this->mark_cache_invalid();
}
void NURBSpline::resize(const int size)
{
positions_.resize(size);

View File

@ -45,14 +45,6 @@ int PolySpline::size() const
return size;
}
void PolySpline::add_point(const float3 position, const float radius, const float tilt)
{
positions_.append(position);
radii_.append(radius);
tilts_.append(tilt);
this->mark_cache_invalid();
}
void PolySpline::resize(const int size)
{
positions_.resize(size);

View File

@ -16,6 +16,7 @@
#include "BLI_array.hh"
#include "BLI_set.hh"
#include "BLI_string_ref.hh"
#include "BLI_task.hh"
#include "DNA_mesh_types.h"
@ -41,11 +42,22 @@ static void copy_attribute_to_points(const VArray<T> &source_data,
}
}
static void copy_attributes_to_points(CurveEval &curve,
const MeshComponent &mesh_component,
Span<Vector<int>> point_to_vert_maps)
static std::unique_ptr<CurveEval> create_curve_from_vert_indices(
const MeshComponent &mesh_component, Span<Vector<int>> vert_indices, IndexRange cyclic_splines)
{
MutableSpan<SplinePtr> splines = curve.splines();
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
curve->resize(vert_indices.size());
MutableSpan<SplinePtr> splines = curve->splines();
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);
}
Set<bke::AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids();
/* Copy builtin control point attributes. */
@ -54,28 +66,40 @@ static void copy_attributes_to_points(CurveEval &curve,
"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, point_to_vert_maps[i], splines[i]->tilts());
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, point_to_vert_maps[i], splines[i]->radii());
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);
}
}
for (const bke::AttributeIDRef &attribute_id : source_attribute_ids) {
/* Don't copy attributes that are built-in on meshes but not on curves. */
if (mesh_component.attribute_is_builtin(attribute_id)) {
continue;
/* Don't copy attributes that are built-in on meshes but not on curves,
* except for the position attribute. */
if (!(attribute_id == "position")) {
continue;
}
}
if (!attribute_id.should_be_kept()) {
@ -104,24 +128,27 @@ static void copy_attributes_to_points(CurveEval &curve,
attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) {
using T = decltype(dummy);
copy_attribute_to_points<T>(
mesh_attribute.typed<T>(), point_to_vert_maps[i], spline_attribute->typed<T>());
mesh_attribute.typed<T>(), vert_indices[i], spline_attribute->typed<T>());
});
}
});
}
curve.assert_valid_point_attributes();
curve->assert_valid_point_attributes();
return curve;
}
struct CurveFromEdgesOutput {
std::unique_ptr<CurveEval> curve;
Vector<Vector<int>> point_to_vert_maps;
/** The indices in the mesh for each control point of each result splines. */
Vector<Vector<int>> vert_indices;
/** A subset of splines that should be set cyclic. */
IndexRange cyclic_splines;
};
static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int, int>> edges)
static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
Span<std::pair<int, int>> edges)
{
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
Vector<Vector<int>> point_to_vert_maps;
Vector<Vector<int>> vert_indices;
/* Compute the number of edges connecting to each vertex. */
Array<int> neighbor_count(verts.size(), 0);
@ -173,19 +200,15 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int
continue;
}
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
Vector<int> point_to_vert_map;
spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
point_to_vert_map.append(current_vert);
Vector<int> spline_indices;
spline_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->add_point(verts[current_vert].co, 1.0f, 0.0f);
point_to_vert_map.append(current_vert);
spline_indices.append(current_vert);
unused_edges[current_vert]--;
unused_edges[last_vert]--;
@ -199,12 +222,13 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int
next_vert = (last_vert == next_a) ? next_b : next_a;
}
spline->attributes.reallocate(spline->size());
curve->add_spline(std::move(spline));
point_to_vert_maps.append(std::move(point_to_vert_map));
vert_indices.append(std::move(spline_indices));
}
}
/* All splines added after this are cyclic. */
const int cyclic_start = vert_indices.size();
/* All remaining edges are part of cyclic splines (we skipped vertices with two edges before). */
for (const int start_vert : verts.index_range()) {
if (unused_edges[start_vert] != 2) {
@ -214,20 +238,16 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int
int current_vert = start_vert;
int next_vert = neighbors[neighbor_offsets[current_vert]];
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
Vector<int> point_to_vert_map;
spline->set_cyclic(true);
Vector<int> spline_indices;
spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
point_to_vert_map.append(current_vert);
spline_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->add_point(verts[current_vert].co, 1.0f, 0.0f);
point_to_vert_map.append(current_vert);
spline_indices.append(current_vert);
unused_edges[current_vert]--;
unused_edges[last_vert]--;
@ -237,13 +257,12 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int
next_vert = (last_vert == next_a) ? next_b : next_a;
}
spline->attributes.reallocate(spline->size());
curve->add_spline(std::move(spline));
point_to_vert_maps.append(std::move(point_to_vert_map));
vert_indices.append(std::move(spline_indices));
}
curve->attributes.reallocate(curve->splines().size());
return {std::move(curve), std::move(point_to_vert_maps)};
const int final_size = vert_indices.size();
return {std::move(vert_indices), IndexRange(cyclic_start, final_size - cyclic_start)};
}
/**
@ -266,9 +285,11 @@ std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_compo
const Mesh &mesh = *mesh_component.get_for_read();
Vector<std::pair<int, int>> selected_edges = get_selected_edges(*mesh_component.get_for_read(),
selection);
CurveFromEdgesOutput output = edges_to_curve({mesh.mvert, mesh.totvert}, selected_edges);
copy_attributes_to_points(*output.curve, mesh_component, output.point_to_vert_maps);
return std::move(output.curve);
CurveFromEdgesOutput output = edges_to_curve_point_indices({mesh.mvert, mesh.totvert},
selected_edges);
return create_curve_from_vert_indices(
mesh_component, output.vert_indices, output.cyclic_splines);
}
} // namespace blender::geometry