Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc')
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc387
1 files changed, 29 insertions, 358 deletions
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
index 500804e41f0..a92479bc5f1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
@@ -1,12 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
-
-#include "BLI_task.hh"
+#include "BKE_curves.hh"
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GEO_set_curve_type.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_curve_spline_type_cc {
@@ -29,332 +29,14 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
- data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
+ data->spline_type = CURVE_TYPE_POLY;
node->storage = data;
}
-template<typename T>
-static void scale_input_assign(const Span<T> src,
- const int scale,
- const int offset,
- MutableSpan<T> dst)
-{
- for (const int i : dst.index_range()) {
- dst[i] = src[i * scale + offset];
- }
-}
-
-template<typename T>
-static void scale_output_assign(const Span<T> src,
- const int scale,
- const int offset,
- MutableSpan<T> dst)
-{
- for (const int i : src.index_range()) {
- dst[i * scale + offset] = src[i];
- }
-}
-
-template<typename T>
-static void nurbs_to_bezier_assign(const Span<T> src,
- const MutableSpan<T> dst,
- const KnotsMode knots_mode)
-{
- switch (knots_mode) {
- case NURBS_KNOT_MODE_BEZIER:
- scale_input_assign<T>(src, 3, 1, dst);
- break;
- case NURBS_KNOT_MODE_NORMAL:
- for (const int i : dst.index_range()) {
- dst[i] = src[(i + 1) % src.size()];
- }
- break;
- case NURBS_KNOT_MODE_ENDPOINT_BEZIER:
- case NURBS_KNOT_MODE_ENDPOINT:
- for (const int i : dst.index_range().drop_back(1).drop_front(1)) {
- dst[i] = src[i + 1];
- }
- dst.first() = src.first();
- dst.last() = src.last();
- break;
- }
-}
-
-template<typename CopyFn>
-static void copy_attributes(const Spline &input_spline, Spline &output_spline, CopyFn copy_fn)
-{
- input_spline.attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src = input_spline.attributes.get_for_read(attribute_id);
- BLI_assert(src);
- if (!output_spline.attributes.create(attribute_id, meta_data.data_type)) {
- BLI_assert_unreachable();
- return false;
- }
- std::optional<GMutableSpan> dst = output_spline.attributes.get_for_write(attribute_id);
- if (!dst) {
- BLI_assert_unreachable();
- return false;
- }
-
- copy_fn(*src, *dst);
-
- return true;
- },
- ATTR_DOMAIN_POINT);
-}
-
-static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_positions,
- const KnotsMode knots_mode)
-{
- const int nurbs_positions_num = nurbs_positions.size();
- Vector<float3> handle_positions;
- if (knots_mode == NURBS_KNOT_MODE_BEZIER) {
- for (const int i : IndexRange(nurbs_positions_num)) {
- if (i % 3 == 1) {
- continue;
- }
- handle_positions.append(nurbs_positions[i]);
- }
- if (nurbs_positions_num % 3 == 1) {
- handle_positions.pop_last();
- }
- else if (nurbs_positions_num % 3 == 2) {
- const int last_index = nurbs_positions_num - 1;
- handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
- }
- }
- else {
- const bool is_periodic = knots_mode == NURBS_KNOT_MODE_NORMAL;
- if (is_periodic) {
- handle_positions.append(nurbs_positions[1] +
- ((nurbs_positions[0] - nurbs_positions[1]) / 3));
- }
- else {
- handle_positions.append(2 * nurbs_positions[0] - nurbs_positions[1]);
- handle_positions.append(nurbs_positions[1]);
- }
- const int segments_num = nurbs_positions_num - 1;
- const bool ignore_interior_segment = segments_num == 3 && is_periodic == false;
- if (ignore_interior_segment == false) {
- const float mid_offset = (float)(segments_num - 1) / 2.0f;
- for (const int i : IndexRange(1, segments_num - 2)) {
- const int divisor = is_periodic ?
- 3 :
- std::min(3, (int)(-std::abs(i - mid_offset) + mid_offset + 1.0f));
- const float3 &p1 = nurbs_positions[i];
- const float3 &p2 = nurbs_positions[i + 1];
- const float3 displacement = (p2 - p1) / divisor;
- const int num_handles_on_segment = divisor < 3 ? 1 : 2;
- for (int j : IndexRange(1, num_handles_on_segment)) {
- handle_positions.append(p1 + (displacement * j));
- }
- }
- }
- const int last_index = nurbs_positions_num - 1;
- if (is_periodic) {
- handle_positions.append(
- nurbs_positions[last_index - 1] +
- ((nurbs_positions[last_index] - nurbs_positions[last_index - 1]) / 3));
- }
- else {
- handle_positions.append(nurbs_positions[last_index - 1]);
- handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
- }
- }
- return handle_positions;
-}
-
-static Array<float3> create_nurbs_to_bezier_positions(const Span<float3> nurbs_positions,
- const Span<float3> handle_positions,
- const KnotsMode knots_mode)
-{
- if (knots_mode == NURBS_KNOT_MODE_BEZIER) {
- /* Every third NURBS position (starting from index 1) should be converted to Bezier position */
- const int scale = 3;
- const int offset = 1;
- Array<float3> bezier_positions((nurbs_positions.size() + offset) / scale);
- scale_input_assign(nurbs_positions, scale, offset, bezier_positions.as_mutable_span());
- return bezier_positions;
- }
-
- Array<float3> bezier_positions(handle_positions.size() / 2);
- for (const int i : IndexRange(bezier_positions.size())) {
- bezier_positions[i] = math::interpolate(
- handle_positions[i * 2], handle_positions[i * 2 + 1], 0.5f);
- }
- return bezier_positions;
-}
-
-static SplinePtr convert_to_poly_spline(const Spline &input)
-{
- std::unique_ptr<PolySpline> output = std::make_unique<PolySpline>();
- output->resize(input.positions().size());
- output->positions().copy_from(input.positions());
- output->radii().copy_from(input.radii());
- output->tilts().copy_from(input.tilts());
- Spline::copy_base_settings(input, *output);
- output->attributes = input.attributes;
- return output;
-}
-
-static SplinePtr poly_to_nurbs(const Spline &input)
-{
- std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
- output->resize(input.positions().size());
- output->positions().copy_from(input.positions());
- output->radii().copy_from(input.radii());
- output->tilts().copy_from(input.tilts());
- output->weights().fill(1.0f);
- output->set_resolution(12);
- output->set_order(4);
- Spline::copy_base_settings(input, *output);
- output->knots_mode = NURBS_KNOT_MODE_BEZIER;
- output->attributes = input.attributes;
- return output;
-}
-
-static SplinePtr bezier_to_nurbs(const Spline &input)
-{
- const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(input);
- std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
- output->resize(input.size() * 3);
-
- scale_output_assign(bezier_spline.handle_positions_left(), 3, 0, output->positions());
- scale_output_assign(input.radii(), 3, 0, output->radii());
- scale_output_assign(input.tilts(), 3, 0, output->tilts());
-
- scale_output_assign(bezier_spline.positions(), 3, 1, output->positions());
- scale_output_assign(input.radii(), 3, 1, output->radii());
- scale_output_assign(input.tilts(), 3, 1, output->tilts());
-
- scale_output_assign(bezier_spline.handle_positions_right(), 3, 2, output->positions());
- scale_output_assign(input.radii(), 3, 2, output->radii());
- scale_output_assign(input.tilts(), 3, 2, output->tilts());
-
- Spline::copy_base_settings(input, *output);
- output->weights().fill(1.0f);
- output->set_resolution(12);
- output->set_order(4);
- output->set_cyclic(input.is_cyclic());
- output->knots_mode = NURBS_KNOT_MODE_BEZIER;
- output->attributes.reallocate(output->size());
- copy_attributes(input, *output, [](GSpan src, GMutableSpan dst) {
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- scale_output_assign<T>(src.typed<T>(), 3, 0, dst.typed<T>());
- scale_output_assign<T>(src.typed<T>(), 3, 1, dst.typed<T>());
- scale_output_assign<T>(src.typed<T>(), 3, 2, dst.typed<T>());
- });
- });
- return output;
-}
-
-static SplinePtr poly_to_bezier(const Spline &input)
-{
- std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
- output->resize(input.size());
- output->positions().copy_from(input.positions());
- output->radii().copy_from(input.radii());
- output->tilts().copy_from(input.tilts());
- output->handle_types_left().fill(BEZIER_HANDLE_VECTOR);
- output->handle_types_right().fill(BEZIER_HANDLE_VECTOR);
- output->set_resolution(12);
- Spline::copy_base_settings(input, *output);
- output->attributes = input.attributes;
- return output;
-}
-
-static SplinePtr nurbs_to_bezier(const Spline &input)
-{
- const NURBSpline &nurbs_spline = static_cast<const NURBSpline &>(input);
- Span<float3> nurbs_positions;
- Vector<float3> nurbs_positions_vector;
- KnotsMode knots_mode;
- if (nurbs_spline.is_cyclic()) {
- nurbs_positions_vector = nurbs_spline.positions();
- nurbs_positions_vector.append(nurbs_spline.positions()[0]);
- nurbs_positions_vector.append(nurbs_spline.positions()[1]);
- nurbs_positions = nurbs_positions_vector;
- knots_mode = NURBS_KNOT_MODE_NORMAL;
- }
- else {
- nurbs_positions = nurbs_spline.positions();
- knots_mode = nurbs_spline.knots_mode;
- }
- const Vector<float3> handle_positions = create_nurbs_to_bezier_handles(nurbs_positions,
- knots_mode);
- BLI_assert(handle_positions.size() % 2 == 0);
- const Array<float3> bezier_positions = create_nurbs_to_bezier_positions(
- nurbs_positions, handle_positions.as_span(), knots_mode);
- BLI_assert(handle_positions.size() == bezier_positions.size() * 2);
-
- std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
- output->resize(bezier_positions.size());
- output->positions().copy_from(bezier_positions);
- nurbs_to_bezier_assign(nurbs_spline.radii(), output->radii(), knots_mode);
- nurbs_to_bezier_assign(nurbs_spline.tilts(), output->tilts(), knots_mode);
- scale_input_assign(handle_positions.as_span(), 2, 0, output->handle_positions_left());
- scale_input_assign(handle_positions.as_span(), 2, 1, output->handle_positions_right());
- output->handle_types_left().fill(BEZIER_HANDLE_ALIGN);
- output->handle_types_right().fill(BEZIER_HANDLE_ALIGN);
- output->set_resolution(nurbs_spline.resolution());
- Spline::copy_base_settings(nurbs_spline, *output);
- output->attributes.reallocate(output->size());
- copy_attributes(nurbs_spline, *output, [knots_mode](GSpan src, GMutableSpan dst) {
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- nurbs_to_bezier_assign(src.typed<T>(), dst.typed<T>(), knots_mode);
- });
- });
- return output;
-}
-
-static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params)
-{
- switch (input.type()) {
- case CURVE_TYPE_BEZIER:
- return input.copy();
- case CURVE_TYPE_POLY:
- return poly_to_bezier(input);
- case CURVE_TYPE_NURBS:
- if (input.size() < 4) {
- params.error_message_add(
- NodeWarningType::Info,
- TIP_("NURBS must have minimum of 4 points for Bezier Conversion"));
- return input.copy();
- }
- return nurbs_to_bezier(input);
- case CURVE_TYPE_CATMULL_ROM: {
- BLI_assert_unreachable();
- return {};
- }
- }
- BLI_assert_unreachable();
- return {};
-}
-
-static SplinePtr convert_to_nurbs(const Spline &input)
-{
- switch (input.type()) {
- case CURVE_TYPE_NURBS:
- return input.copy();
- case CURVE_TYPE_BEZIER:
- return bezier_to_nurbs(input);
- case CURVE_TYPE_POLY:
- return poly_to_nurbs(input);
- case CURVE_TYPE_CATMULL_ROM:
- BLI_assert_unreachable();
- return {};
- }
- BLI_assert_unreachable();
- return {};
-}
-
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSplineType &storage = node_storage(params.node());
- const GeometryNodeSplineType dst_type = (const GeometryNodeSplineType)storage.spline_type;
+ const CurveType dst_type = CurveType(storage.spline_type);
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -363,45 +45,34 @@ static void node_geo_exec(GeoNodeExecParams params)
if (!geometry_set.has_curves()) {
return;
}
+ const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
+ const Curves &src_curves_id = *src_component.get_for_read();
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
+ if (src_curves.is_single_type(dst_type)) {
+ return;
+ }
- const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
- *curve_component->get_for_read());
- GeometryComponentFieldContext field_context{*curve_component, ATTR_DOMAIN_CURVE};
- const int domain_num = curve_component->attribute_domain_num(ATTR_DOMAIN_CURVE);
-
- Span<SplinePtr> src_splines = curve->splines();
+ GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
+ fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (selection.is_empty()) {
+ return;
+ }
- fn::FieldEvaluator selection_evaluator{field_context, domain_num};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
+ if (geometry::try_curves_conversion_in_place(
+ selection, dst_type, [&]() -> bke::CurvesGeometry & {
+ return bke::CurvesGeometry::wrap(geometry_set.get_curves_for_write()->geometry);
+ })) {
+ return;
+ }
- std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
- new_curve->resize(src_splines.size());
+ bke::CurvesGeometry dst_curves = geometry::convert_curves(src_curves, selection, dst_type);
- threading::parallel_for(src_splines.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- if (selection[i]) {
- switch (dst_type) {
- case GEO_NODE_SPLINE_TYPE_POLY:
- new_curve->splines()[i] = convert_to_poly_spline(*src_splines[i]);
- break;
- case GEO_NODE_SPLINE_TYPE_BEZIER:
- new_curve->splines()[i] = convert_to_bezier(*src_splines[i], params);
- break;
- case GEO_NODE_SPLINE_TYPE_NURBS:
- new_curve->splines()[i] = convert_to_nurbs(*src_splines[i]);
- break;
- }
- }
- else {
- new_curve->splines()[i] = src_splines[i]->copy();
- }
- }
- });
- new_curve->attributes = curve->attributes;
- geometry_set.replace_curves(curve_eval_to_curves(*new_curve));
+ Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
+ bke::curves_copy_parameters(src_curves_id, *dst_curves_id);
+ geometry_set.replace_curves(dst_curves_id);
});
params.set_output("Curve", std::move(geometry_set));