Blender V4.3
node_geo_curve_topology_points_of_curve.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_curves.hh"
6
7#include "BLI_array_utils.hh"
8#include "BLI_task.hh"
9
10#include "node_geometry_util.hh"
11
13
15{
16 b.add_input<decl::Int>("Curve Index")
17 .implicit_field(implicit_field_inputs::index)
18 .description("The curve to retrieve data from. Defaults to the curve from the context");
19 b.add_input<decl::Float>("Weights").supports_field().hide_value().description(
20 "Values used to sort the curve's points. Uses indices by default");
21 b.add_input<decl::Int>("Sort Index")
22 .min(0)
23 .supports_field()
24 .description("Which of the sorted points to output");
25 b.add_output<decl::Int>("Point Index")
26 .field_source_reference_all()
27 .description("A point of the curve, chosen by the sort index");
28 b.add_output<decl::Int>("Total").field_source().reference_pass({0}).description(
29 "The number of points in the curve");
30}
31
33 const Field<int> curve_index_;
34 const Field<int> sort_index_;
35 const Field<float> sort_weight_;
36
37 public:
38 PointsOfCurveInput(Field<int> curve_index, Field<int> sort_index, Field<float> sort_weight)
39 : bke::GeometryFieldInput(CPPType::get<int>(), "Point of Curve"),
40 curve_index_(std::move(curve_index)),
41 sort_index_(std::move(sort_index)),
42 sort_weight_(std::move(sort_weight))
43 {
45 }
46
48 const IndexMask &mask) const final
49 {
50 const bke::CurvesGeometry *curves_ptr = context.curves_or_strokes();
51 if (!curves_ptr) {
52 return {};
53 }
54 const bke::CurvesGeometry &curves = *curves_ptr;
55
56 const OffsetIndices points_by_curve = curves.points_by_curve();
57
58 fn::FieldEvaluator evaluator{context, &mask};
59 evaluator.add(curve_index_);
60 evaluator.add(sort_index_);
61 evaluator.evaluate();
62 const VArray<int> curve_indices = evaluator.get_evaluated<int>(0);
63 const VArray<int> indices_in_sort = evaluator.get_evaluated<int>(1);
64
65 const bke::GeometryFieldContext point_context{context, AttrDomain::Point};
66 fn::FieldEvaluator point_evaluator{point_context, curves.points_num()};
67 point_evaluator.add(sort_weight_);
68 point_evaluator.evaluate();
69 const VArray<float> all_sort_weights = point_evaluator.get_evaluated<float>(0);
70 const bool use_sorting = !all_sort_weights.is_single();
71
72 Array<int> point_of_curve(mask.min_array_size());
73 mask.foreach_segment(GrainSize(256), [&](const IndexMaskSegment segment) {
74 /* Reuse arrays to avoid allocation. */
75 Array<float> sort_weights;
76 Array<int> sort_indices;
77
78 for (const int selection_i : segment) {
79 const int curve_i = curve_indices[selection_i];
80 const int index_in_sort = indices_in_sort[selection_i];
81 if (!curves.curves_range().contains(curve_i)) {
82 point_of_curve[selection_i] = 0;
83 continue;
84 }
85 const IndexRange points = points_by_curve[curve_i];
86
87 const int index_in_sort_wrapped = mod_i(index_in_sort, points.size());
88 if (use_sorting) {
89 /* Retrieve the weights for each point. */
90 sort_weights.reinitialize(points.size());
91 all_sort_weights.materialize_compressed(IndexMask(points),
92 sort_weights.as_mutable_span());
93
94 /* Sort a separate array of compressed indices corresponding to the compressed weights.
95 * This allows using `materialize_compressed` to avoid virtual function call overhead
96 * when accessing values in the sort weights. However, it means a separate array of
97 * indices within the compressed array is necessary for sorting. */
98 sort_indices.reinitialize(points.size());
100 std::stable_sort(sort_indices.begin(), sort_indices.end(), [&](int a, int b) {
101 return sort_weights[a] < sort_weights[b];
102 });
103 point_of_curve[selection_i] = points[sort_indices[index_in_sort_wrapped]];
104 }
105 else {
106 point_of_curve[selection_i] = points[index_in_sort_wrapped];
107 }
108 }
109 });
110
111 return VArray<int>::ForContainer(std::move(point_of_curve));
112 }
113
114 void for_each_field_input_recursive(FunctionRef<void(const FieldInput &)> fn) const override
115 {
116 curve_index_.node().for_each_field_input_recursive(fn);
117 sort_index_.node().for_each_field_input_recursive(fn);
118 sort_weight_.node().for_each_field_input_recursive(fn);
119 }
120
121 uint64_t hash() const override
122 {
123 return 26978695677882;
124 }
125
126 bool is_equal_to(const fn::FieldNode &other) const override
127 {
128 if (const auto *typed = dynamic_cast<const PointsOfCurveInput *>(&other)) {
129 return typed->curve_index_ == curve_index_ && typed->sort_index_ == sort_index_ &&
130 typed->sort_weight_ == sort_weight_;
131 }
132 return false;
133 }
134
135 std::optional<AttrDomain> preferred_domain(const GeometryComponent & /*component*/) const final
136 {
137 return AttrDomain::Curve;
138 }
139};
140
142 public:
143 CurvePointCountInput() : bke::CurvesFieldInput(CPPType::get<int>(), "Curve Point Count")
144 {
146 }
147
149 const AttrDomain domain,
150 const IndexMask & /*mask*/) const final
151 {
152 if (domain != AttrDomain::Curve) {
153 return {};
154 }
155 const OffsetIndices points_by_curve = curves.points_by_curve();
156 return VArray<int>::ForFunc(curves.curves_num(), [points_by_curve](const int64_t curve_i) {
157 return points_by_curve[curve_i].size();
158 });
159 }
160
161 uint64_t hash() const final
162 {
163 return 903847569873762;
164 }
165
166 bool is_equal_to(const fn::FieldNode &other) const final
167 {
168 return dynamic_cast<const CurvePointCountInput *>(&other) != nullptr;
169 }
170
171 std::optional<AttrDomain> preferred_domain(const bke::CurvesGeometry & /*curves*/) const final
172 {
173 return AttrDomain::Curve;
174 }
175};
176
182static bool use_start_point_special_case(const Field<int> &curve_index,
183 const Field<int> &sort_index,
184 const Field<float> &sort_weights)
185{
186 if (!dynamic_cast<const fn::IndexFieldInput *>(&curve_index.node())) {
187 return false;
188 }
189 if (sort_index.node().depends_on_input() || sort_weights.node().depends_on_input()) {
190 return false;
191 }
192 return fn::evaluate_constant_field(sort_index) == 0;
193}
194
196 public:
197 CurveStartPointInput() : bke::CurvesFieldInput(CPPType::get<int>(), "Point of Curve")
198 {
200 }
201
203 const AttrDomain domain,
204 const IndexMask & /*mask*/) const final
205 {
206 return curves.adapt_domain(VArray<int>::ForSpan(curves.offsets()), AttrDomain::Curve, domain);
207 }
208
209 uint64_t hash() const final
210 {
211 return 2938459815345;
212 }
213
214 bool is_equal_to(const fn::FieldNode &other) const final
215 {
216 return dynamic_cast<const CurveStartPointInput *>(&other) != nullptr;
217 }
218
219 std::optional<AttrDomain> preferred_domain(const bke::CurvesGeometry & /*curves*/) const final
220 {
221 return AttrDomain::Curve;
222 }
223};
224
226{
227 const Field<int> curve_index = params.extract_input<Field<int>>("Curve Index");
228 if (params.output_is_required("Total")) {
229 params.set_output("Total",
230 Field<int>(std::make_shared<bke::EvaluateAtIndexInput>(
231 curve_index,
232 Field<int>(std::make_shared<CurvePointCountInput>()),
233 AttrDomain::Curve)));
234 }
235 if (params.output_is_required("Point Index")) {
236 Field<int> sort_index = params.extract_input<Field<int>>("Sort Index");
237 Field<float> sort_weight = params.extract_input<Field<float>>("Weights");
238 if (use_start_point_special_case(curve_index, sort_index, sort_weight)) {
239 params.set_output("Point Index", Field<int>(std::make_shared<CurveStartPointInput>()));
240 }
241 else {
242 params.set_output("Point Index",
243 Field<int>(std::make_shared<PointsOfCurveInput>(
244 curve_index, std::move(sort_index), std::move(sort_weight))));
245 }
246 }
247}
248
249static void node_register()
250{
251 static blender::bke::bNodeType ntype;
253 &ntype, GEO_NODE_CURVE_TOPOLOGY_POINTS_OF_CURVE, "Points of Curve", NODE_CLASS_INPUT);
255 ntype.declare = node_declare;
257}
259
260} // namespace blender::nodes::node_geo_curve_topology_points_of_curve_cc
Low-level operations for curves.
#define NODE_CLASS_INPUT
Definition BKE_node.hh:404
MINLINE int mod_i(int i, int n)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
const T * end() const
Definition BLI_array.hh:314
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
const T * begin() const
Definition BLI_array.hh:310
void materialize_compressed(const IndexMask &mask, MutableSpan< T > r_span) const
static VArray ForContainer(ContainerT container)
static VArray ForFunc(const int64_t size, GetFunc get_func)
int add(GField field, GVArray *varray_ptr)
Definition field.cc:756
virtual void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const
Definition field.cc:587
bool depends_on_input() const
Definition FN_field.hh:556
const FieldNode & node() const
Definition FN_field.hh:137
GVArray get_varray_for_context(const bke::CurvesGeometry &curves, const AttrDomain domain, const IndexMask &) const final
std::optional< AttrDomain > preferred_domain(const bke::CurvesGeometry &) const final
GVArray get_varray_for_context(const bke::CurvesGeometry &curves, const AttrDomain domain, const IndexMask &) const final
std::optional< AttrDomain > preferred_domain(const bke::CurvesGeometry &) const final
GVArray get_varray_for_context(const bke::GeometryFieldContext &context, const IndexMask &mask) const final
void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const override
PointsOfCurveInput(Field< int > curve_index, Field< int > sort_index, Field< float > sort_weight)
local_group_size(16, 16) .push_constant(Type b
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void fill_index_range(MutableSpan< T > span, const T start=0)
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
void evaluate_constant_field(const GField &field, void *r_value)
Definition field.cc:498
void index(const bNode &, void *r_value)
static bool use_start_point_special_case(const Field< int > &curve_index, const Field< int > &sort_index, const Field< float > &sort_weights)
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
#define min(a, b)
Definition sort.c:32
__int64 int64_t
Definition stdint.h:89
unsigned __int64 uint64_t
Definition stdint.h:90
Defines a node type.
Definition BKE_node.hh:218
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:339
NodeDeclareFunction declare
Definition BKE_node.hh:347