34 float overshoot_point_param = used_percent_length * (new_size - 1);
35 if (start_points[curve]) {
41 int index2 =
math::ceil(overshoot_point_param);
48 positions[new_curve[index2]],
49 fmodf(overshoot_point_param, 1.0f));
52 result = positions[new_curve[1]] - positions[new_curve[0]];
57 if (end_points[curve]) {
58 int index1 = new_size - 1 -
math::floor(overshoot_point_param);
59 int index2 = new_size - 1 -
math::ceil(overshoot_point_param);
61 positions[new_curve[index2]],
62 fmodf(overshoot_point_param, 1.0f));
65 result = positions[new_curve[new_size - 2]] - positions[new_curve[new_size - 1]];
67 positions[new_curve[new_size - 1]] +=
result *
80 const float max_angle,
81 const float segment_influence,
82 const bool invert_curvature,
86 const int first_old_index = start_points[curve] ? start_points[curve] : 0;
87 const int last_old_index = points_by_curve[curve].
size() - 1 + first_old_index;
88 const int orig_totpoints = points_by_curve[curve].
size();
92 const float overshoot_parameter = used_percent_length * (orig_totpoints - 2);
93 int overshoot_pointcount =
math::ceil(overshoot_parameter);
94 overshoot_pointcount =
math::clamp(overshoot_pointcount, 1, orig_totpoints - 2);
98 for (
int k = 0; k < 2; k++) {
99 if ((k == 0 && !start_points[curve]) || (k == 1 && !end_points[curve])) {
103 const int start_i = k == 0 ? first_old_index : last_old_index;
104 const int dir_i = 1 - k * 2;
106 vec1 = positions[new_curve[start_i + dir_i]] - positions[new_curve[start_i]];
107 total_angle =
float3({0, 0, 0});
109 float segment_length;
112 float overshoot_length = 0.0f;
117 for (
int i = start_i; j < overshoot_pointcount;
i += dir_i, j++) {
119 float fac =
math::min(overshoot_parameter - j, 1.0f);
123 vec1 = positions[new_curve[
i + dir_i * 2]] - positions[new_curve[
i + dir_i]];
130 const float added_len = (segment_length +
len) * 0.5f * fac;
131 overshoot_length += added_len;
132 segment_length =
len;
134 if (
angle > max_angle) {
148 if (
UNLIKELY(overshoot_length == 0.0f)) {
153 vec1 = positions[new_curve[start_i]] - positions[new_curve[start_i + dir_i]];
157 float curvature =
normalize_v3(total_angle) / overshoot_length;
161 if (invert_curvature) {
162 curvature = -curvature;
164 const float dist = k == 0 ? use_start_lengths[curve] : use_end_lengths[curve];
165 const int extra_point_count = k == 0 ? start_points[curve] : end_points[curve];
166 const float angle_step = curvature * dist / extra_point_count;
167 float step_length = dist / extra_point_count;
168 if (
math::abs(angle_step) > FLT_EPSILON) {
170 step_length *=
sin(angle_step * 0.5f) / (angle_step * 0.5f);
173 total_angle =
float3({0, 0, 0});
187 (curvature * prev_length - angle_step) / 2.0f);
192 for (
int i = start_i - dir_i, j = 0; j < extra_point_count;
i -= dir_i, j++) {
194 positions[new_curve[
i]] = vec1 + positions[new_curve[
i + dir_i]];
203 const float overshoot_fac,
204 const bool follow_curvature,
205 const float point_density,
206 const float segment_influence,
207 const float max_angle,
208 const bool invert_curvature,
219 const int src_curves_num = src_curves.
curves_num();
234 use_start_lengths[curve] = start_lengths[curve];
235 use_end_lengths[curve] = end_lengths[curve];
238 use_start_lengths[curve] *= total_length;
239 use_end_lengths[curve] *= total_length;
245 if (!follow_curvature) {
247 dst_curves = std::move(src_curves);
260 const int point_count = dst_points_by_curve[curve];
261 if (point_count <= 2) {
263 start_points[curve] = 1;
264 end_points[curve] = 1;
268 const int count_start = (use_start_lengths[curve] > 0) ?
269 math::ceil(use_start_lengths[curve] * point_density) :
271 const int count_end = (use_end_lengths[curve] > 0) ?
272 math::ceil(use_end_lengths[curve] * point_density) :
274 dst_points_by_curve[curve] += count_start;
275 dst_points_by_curve[curve] += count_end;
276 start_points[curve] = count_start;
277 end_points[curve] = count_end;
281 int target_point_count = dst_points_by_curve.
last();
284 Array<int> dst_to_src_point(target_point_count);
286 const int point_count = points_by_curve[curve].
size();
290 if (point_count <= 2) {
291 for (
const int point_i : new_points_by_curve.
index_range()) {
292 new_points_by_curve[point_i] = points_by_curve[curve][point_i];
296 if (follow_curvature) {
298 starts.
fill(points_by_curve[curve].first());
299 local_front = start_points[curve];
301 new_points_by_curve.
size() - end_points[curve], end_points[curve]);
302 ends.
fill(points_by_curve[curve].last());
305 for (
const int point_i : original_points.
index_range()) {
306 original_points[point_i] = points_by_curve[curve][point_i];
310 dst_curves.
resize(target_point_count, src_curves_num);
316 gather_attributes(src_attributes,
328 for (const int curve : curves_range) {
329 const IndexRange new_curve = new_points_by_curve[curve];
330 int new_size = new_curve.size();
333 const float used_percent_length = math::clamp(
334 isfinite(overshoot_fac) ? overshoot_fac : 0.1f, 1e-4f, 1.0f);
336 if (!follow_curvature || new_size == 2) {
337 extend_curve_straight(used_percent_length,
339 start_points.as_span(),
340 end_points.as_span(),
343 use_start_lengths.as_span(),
344 use_end_lengths.as_span(),
347 else if (start_points[curve] > 0 || end_points[curve] > 0) {
348 extend_curve_curved(used_percent_length,
349 start_points.as_span(),
350 end_points.as_span(),
354 use_start_lengths.as_span(),
355 use_end_lengths.as_span(),
363 if (src_curves.nurbs_has_custom_knots()) {
Low-level operations for curves.
Low-level operations for curves.
MINLINE float normalize_v3(float n[3])
GeometryNodeCurveSampleMode
@ GEO_NODE_CURVE_SAMPLE_FACTOR
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
MutableSpan< T > as_mutable_span()
constexpr int64_t first() const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr void fill(const T &value) const
constexpr IndexRange index_range() const
constexpr T & last(const int64_t n=0) const
MutableSpan< float3 > positions_for_write()
OffsetIndices< int > points_by_curve() const
IndexRange curves_range() const
MutableAttributeAccessor attributes_for_write()
void resize(int points_num, int curves_num)
AttributeAccessor attributes() const
float evaluated_length_total_for_curve(int curve_index, bool cyclic) const
MutableSpan< int > offsets_for_write()
void ensure_evaluated_lengths() const
void foreach_index(Fn &&fn) const
void update_custom_knot_modes(const IndexMask &mask, const KnotsMode mode_for_regular, const KnotsMode mode_for_cyclic, bke::CurvesGeometry &curves)
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
static void extend_curve_straight(const float used_percent_length, const float new_size, const Span< int > start_points, const Span< int > end_points, const int curve, const IndexRange new_curve, const Span< float > use_start_lengths, const Span< float > use_end_lengths, MutableSpan< float3 > positions)
static void extend_curve_curved(const float used_percent_length, const Span< int > start_points, const Span< int > end_points, const OffsetIndices< int > points_by_curve, const int curve, const IndexRange new_curve, const Span< float > use_start_lengths, const Span< float > use_end_lengths, const float max_angle, const float segment_influence, const bool invert_curvature, MutableSpan< float3 > positions)
bke::CurvesGeometry extend_curves(bke::CurvesGeometry &src_curves, const IndexMask &selection, const VArray< float > &start_lengths, const VArray< float > &end_lengths, float overshoot_fac, bool follow_curvature, float point_density, float segment_influence, float max_angle, bool invert_curvature, GeometryNodeCurveSampleMode sample_mode, const bke::AttributeFilter &attribute_filter)
void masked_fill(MutableSpan< T > data, const T &value, const IndexMask &mask)
QuaternionBase< float > Quaternion
T pow(const T &x, const T &power)
T clamp(const T &a, const T &min, const T &max)
QuaternionBase< T > to_quaternion(const AxisAngleBase< T, AngleT > &axis_angle)
T length(const VecBase< T, Size > &a)
AngleRadianBase< T > angle_between(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
AxisAngleBase< float, AngleRadianBase< float > > AxisAngle
QuaternionBase< T > normalize_and_get_length(const QuaternionBase< T > &q, T &out_length)
T min(const T &a, const T &b)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
T interpolate(const T &a, const T &b, const FactorT &t)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
T max(const T &a, const T &b)
MatT from_rotation(const RotationT &rotation)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void copy_group_sizes(OffsetIndices< int > offsets, const IndexMask &mask, MutableSpan< int > sizes)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3