17 "For points, the portion of the spline's total length at the control point. For "
18 "Splines, the factor of that spline within the entire curve");
20 "For points, the distance along the control point's spline, For splines, the "
21 "distance along the entire curve");
23 "Each control point's index on its spline");
51 const int last_index = curves.
curves_num() - 1;
53 last_index, cyclic[last_index]);
54 if (total_length > 0.0f) {
55 const float factor = 1.0f / total_length;
56 for (
float &value : lengths) {
65 lengths[
i] =
i / (lengths.
size() - 1.0f);
94 for (const int i_curve : range) {
95 const IndexRange points = points_by_curve[i_curve];
96 const bool is_cyclic = cyclic[i_curve];
97 const Span<float> evaluated_lengths = curves.evaluated_lengths_for_curve(i_curve, is_cyclic);
98 MutableSpan<float> lengths = result.as_mutable_span().slice(points);
99 lengths.first() = 0.0f;
100 const float last_evaluated_length = evaluated_lengths.is_empty() ? 0.0f :
101 evaluated_lengths.last();
104 switch (types[i_curve]) {
105 case CURVE_TYPE_CATMULL_ROM: {
106 const int resolution = resolutions[i_curve];
107 for (const int i : IndexRange(points.size()).drop_back(1)) {
108 lengths[i + 1] = evaluated_lengths[resolution * (i + 1) - 1];
110 total = last_evaluated_length;
113 case CURVE_TYPE_POLY:
114 lengths.drop_front(1).copy_from(evaluated_lengths.take_front(lengths.size() - 1));
115 total = last_evaluated_length;
117 case CURVE_TYPE_BEZIER: {
118 const Span<int> offsets = curves.bezier_evaluated_offsets_for_curve(i_curve);
119 for (const int i : IndexRange(points.size()).drop_back(1)) {
120 lengths[i + 1] = evaluated_lengths[offsets[i + 1] - 1];
122 total = last_evaluated_length;
125 case CURVE_TYPE_NURBS: {
126 const Span<float3> positions = curves.positions().slice(points);
128 for (const int i : positions.index_range().drop_back(1)) {
130 length += math::distance(positions[i], positions[i + 1]);
132 lengths.last() = length;
134 length += math::distance(positions.first(), positions.last());
140 postprocess_lengths_for_curve(lengths, total);
148 if (total_curve_length > 0.0f) {
149 const float factor = 1.0f / total_curve_length;
154 else if (lengths.
size() == 1) {
164 lengths[
i] =
i / (lengths.
size() - 1.0f);
176 :
bke::CurvesFieldInput(
CPPType::get<
float>(),
"Spline Parameter node")
186 case AttrDomain::Point:
188 case AttrDomain::Curve:
220 case AttrDomain::Point:
223 case AttrDomain::Curve:
253 if (domain != AttrDomain::Point) {
257 const OffsetIndices points_by_curve = curves.points_by_curve();
259 for (const int i_curve : range) {
260 MutableSpan<int> indices = result.as_mutable_span().slice(points_by_curve[i_curve]);
261 array_utils::fill_index_range(indices);
279 return AttrDomain::Point;
285 Field<float> parameter_field{std::make_shared<CurveParameterFieldInput>()};
286 Field<float> length_field{std::make_shared<CurveLengthParameterFieldInput>()};
287 Field<int> index_on_spline_field{std::make_shared<IndexOnSplineFieldInput>()};
288 params.set_output(
"Factor", std::move(parameter_field));
289 params.set_output(
"Length", std::move(length_field));
290 params.set_output(
"Index", std::move(index_on_spline_field));
297 ntype.
ui_name =
"Spline Parameter";
298 ntype.
ui_description =
"Retrieve how far along each spline a control point is";
Low-level operations for curves.
#define GEO_NODE_CURVE_SPLINE_PARAMETER
#define BLI_assert_unreachable()
#define NOD_REGISTER_NODE(REGISTER_FUNC)
unsigned long long int uint64_t
static VArray from_container(ContainerT container)
const T & last(const int64_t n=0) const
IndexRange index_range() const
constexpr int64_t size() const
constexpr MutableSpan drop_front(const int64_t n) const
constexpr IndexRange index_range() const
OffsetIndices< int > points_by_curve() const
IndexRange curves_range() const
VArray< int > resolution() const
float evaluated_length_total_for_curve(int curve_index, bool cyclic) const
void ensure_evaluated_lengths() const
VArray< int8_t > curve_types() const
VArray< bool > cyclic() const
float length(VecOp< float, D >) RET
void node_register_type(bNodeType &ntype)
static void node_register()
static void node_declare(NodeDeclarationBuilder &b)
static Array< float > calculate_point_lengths(const bke::CurvesGeometry &curves, const FunctionRef< void(MutableSpan< float >, float)> postprocess_lengths_for_curve)
static Array< float > calculate_point_parameters(const bke::CurvesGeometry &curves)
static void node_geo_exec(GeoNodeExecParams params)
static Array< float > accumulated_lengths_curve_domain(const bke::CurvesGeometry &curves)
static void convert_lengths_to_factors(MutableSpan< float > lengths, const float total_curve_length)
static Array< float > calculate_curve_parameters(const bke::CurvesGeometry &curves)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
std::string ui_description
NodeGeometryExecFunction geometry_node_execute
const char * enum_name_legacy
NodeDeclareFunction declare