16 const int start_in_range = start_index - range.first();
17 const int offset_in_range = start_in_range + offset;
18 const int mod_offset = offset_in_range % range.size();
19 if (mod_offset >= 0) {
20 return range[mod_offset];
22 return range.last(-(mod_offset + 1));
33 .
description(
"The index of the control point to evaluate. Defaults to the current index");
35 "The number of control points along the curve to traverse");
37 .field_source_reference_all()
39 "Whether the input control point plus the offset is a valid index of the "
42 .field_source_reference_all()
44 "The index of the control point plus the offset within the entire "
55 : GeometryFieldInput(
CPPType::get<
int>(),
"Offset Point in Curve"),
56 index_(std::move(index)),
57 offset_(std::move(offset))
71 const OffsetIndices points_by_curve = curves.points_by_curve();
73 const Array<int> parent_curves = curves.point_to_curve_map();
76 evaluator.
add(index_);
77 evaluator.add(offset_);
79 const VArray<int> indices = evaluator.get_evaluated<
int>(0);
80 const VArray<int> offsets = evaluator.get_evaluated<
int>(1);
83 mask.foreach_index([&](
const int i_selection) {
84 const int i_point = std::clamp(indices[i_selection], 0, curves.points_num() - 1);
85 const int i_curve = parent_curves[i_point];
86 const IndexRange curve_points = points_by_curve[i_curve];
87 const int offset_point = i_point + offsets[i_selection];
89 if (cyclic[i_curve]) {
91 curve_points, i_point, offsets[i_selection]);
94 output[i_selection] = std::clamp(offset_point, 0, curves.points_num() - 1);
114 : GeometryFieldInput(
CPPType::get<bool>(),
"Offset Valid"),
115 index_(std::move(index)),
116 offset_(std::move(offset))
131 const OffsetIndices points_by_curve = curves.points_by_curve();
132 const Array<int> parent_curves = curves.point_to_curve_map();
135 evaluator.
add(index_);
136 evaluator.add(offset_);
137 evaluator.evaluate();
138 const VArray<int> indices = evaluator.get_evaluated<
int>(0);
139 const VArray<int> offsets = evaluator.get_evaluated<
int>(1);
142 mask.foreach_index([&](
const int i_selection) {
143 const int i_point = indices[i_selection];
144 if (!curves.points_range().contains(i_point)) {
145 output[i_selection] = false;
149 const int i_curve = parent_curves[i_point];
150 const IndexRange curve_points = points_by_curve[i_curve];
151 if (cyclic[i_curve]) {
152 output[i_selection] =
true;
155 output[i_selection] = curve_points.
contains(i_point + offsets[i_selection]);
172 if (
params.output_is_required(
"Point Index")) {
173 Field<int> curve_point_field{std::make_shared<ControlPointNeighborFieldInput>(index, offset)};
174 params.set_output(
"Point Index", std::move(curve_point_field));
176 if (
params.output_is_required(
"Is Valid Offset")) {
177 Field<bool> valid_field{std::make_shared<OffsetValidFieldInput>(index, offset)};
178 params.set_output(
"Is Valid Offset", std::move(valid_field));
186 &ntype, GEO_NODE_OFFSET_POINT_IN_CURVE,
"Offset Point in Curve",
NODE_CLASS_INPUT);
Low-level operations for curves.
#define NOD_REGISTER_NODE(REGISTER_FUNC)
constexpr bool contains(int64_t value) const
static VArray ForContainer(ContainerT container)
int add(GField field, GVArray *varray_ptr)
virtual void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const
const FieldNode & node() const
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
void node_register_type(bNodeType *ntype)
static void node_geo_exec(GeoNodeExecParams params)
static void node_declare(NodeDeclarationBuilder &b)
static void node_register()
int apply_offset_in_cyclic_range(IndexRange range, int start_index, int offset)
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
NodeGeometryExecFunction geometry_node_execute
NodeDeclareFunction declare