37 float overshoot_point_param = used_percent_length * (new_size - 1);
38 if (start_points[curve]) {
44 int index2 =
math::ceil(overshoot_point_param);
51 positions[new_curve[index2]],
52 fmodf(overshoot_point_param, 1.0f));
53 result -= positions[new_curve.
first()];
55 result = positions[new_curve[1]] - positions[new_curve[0]];
57 positions[new_curve[0]] += result * (-use_start_lengths[
curve] /
math::length(result));
60 if (end_points[curve]) {
61 int index1 = new_size - 1 -
math::floor(overshoot_point_param);
62 int index2 = new_size - 1 -
math::ceil(overshoot_point_param);
64 positions[new_curve[index2]],
65 fmodf(overshoot_point_param, 1.0f));
66 result -= positions[new_curve.
last()];
68 result = positions[new_curve[new_size - 2]] - positions[new_curve[new_size - 1]];
70 positions[new_curve[new_size - 1]] += result *
83 const float max_angle,
84 const float segment_influence,
85 const bool invert_curvature,
89 const int first_old_index = start_points[
curve] ? start_points[
curve] : 0;
90 const int last_old_index = points_by_curve[
curve].
size() - 1 + first_old_index;
91 const int orig_totpoints = points_by_curve[
curve].
size();
95 const float overshoot_parameter = used_percent_length * (orig_totpoints - 2);
96 int overshoot_pointcount =
math::ceil(overshoot_parameter);
97 overshoot_pointcount =
math::clamp(overshoot_pointcount, 1, orig_totpoints - 2);
101 for (
int k = 0; k < 2; k++) {
102 if ((k == 0 && !start_points[curve]) || (k == 1 && !end_points[curve])) {
106 const int start_i = k == 0 ? first_old_index : last_old_index;
107 const int dir_i = 1 - k * 2;
109 vec1 = positions[new_curve[start_i + dir_i]] - positions[new_curve[start_i]];
110 total_angle =
float3({0, 0, 0});
112 float segment_length;
115 float overshoot_length = 0.0f;
120 for (
int i = start_i; j < overshoot_pointcount; i += dir_i, j++) {
122 float fac =
math::min(overshoot_parameter - j, 1.0f);
126 vec1 = positions[new_curve[i + dir_i * 2]] - positions[new_curve[i + dir_i]];
133 const float added_len = (segment_length +
len) * 0.5f * fac;
134 overshoot_length += added_len;
135 segment_length =
len;
137 if (angle > max_angle) {
140 if (angle >
M_PI * 0.995f) {
144 angle *=
math::pow(added_len, segment_influence);
151 if (
UNLIKELY(overshoot_length == 0.0f)) {
156 vec1 = positions[new_curve[start_i]] - positions[new_curve[start_i + dir_i]];
160 float curvature =
normalize_v3(total_angle) / overshoot_length;
164 if (invert_curvature) {
165 curvature = -curvature;
167 const float dist = k == 0 ? use_start_lengths[
curve] : use_end_lengths[
curve];
168 const int extra_point_count = k == 0 ? start_points[
curve] : end_points[
curve];
169 const float angle_step = curvature * dist / extra_point_count;
170 float step_length = dist / extra_point_count;
171 if (
math::abs(angle_step) > FLT_EPSILON) {
173 step_length *= sin(angle_step * 0.5f) / (angle_step * 0.5f);
176 total_angle =
float3({0, 0, 0});
190 (curvature * prev_length - angle_step) / 2.0f);
195 for (
int i = start_i - dir_i, j = 0; j < extra_point_count; i -= dir_i, j++) {
197 positions[new_curve[i]] = vec1 + positions[new_curve[i + dir_i]];
206 const float overshoot_fac,
207 const bool follow_curvature,
208 const float point_density,
209 const float segment_influence,
210 const float max_angle,
211 const bool invert_curvature,
219 const int src_curves_num = src_curves.
curves_num();
228 selection.foreach_index([&](
const int curve) {
229 use_start_lengths[
curve] = start_lengths[
curve];
233 use_start_lengths[
curve] *= total_length;
234 use_end_lengths[
curve] *= total_length;
235 start_points[
curve] = 1;
236 end_points[
curve] = 1;
243 if (!follow_curvature) {
244 dst_curves = std::move(src_curves);
251 selection.foreach_index([&](
const int curve) {
252 int point_count = points_by_curve[
curve].
size();
253 dst_points_by_curve[
curve] = point_count;
255 if (point_count <= 2) {
256 start_points[
curve] = 0;
257 end_points[
curve] = 0;
261 const int count_start = (use_start_lengths[
curve] > 0) ?
262 math::ceil(use_start_lengths[curve] * point_density) :
264 const int count_end = (use_end_lengths[
curve] > 0) ?
265 math::ceil(use_end_lengths[curve] * point_density) :
267 dst_points_by_curve[
curve] += count_start;
268 dst_points_by_curve[
curve] += count_end;
269 start_points[
curve] = count_start;
270 end_points[
curve] = count_end;
274 int target_point_count = dst_points_by_curve.
last();
277 Array<int> dst_to_src_point(target_point_count);
279 const int point_count = points_by_curve[
curve].
size();
283 if (point_count <= 2) {
284 for (
const int point_i : new_points_by_curve.
index_range()) {
285 new_points_by_curve[point_i] = points_by_curve[
curve][point_i];
289 if (start_points[curve] > 0) {
291 starts.
fill(points_by_curve[curve].first());
292 local_front = start_points[
curve];
294 if (end_points[curve] > 0) {
296 new_points_by_curve.
size() - end_points[
curve], end_points[
curve]);
297 ends.
fill(points_by_curve[curve].last());
300 for (
const int point_i : original_points.
index_range()) {
301 original_points[point_i] = points_by_curve[
curve][point_i];
305 dst_curves.
resize(target_point_count, src_curves_num);
311 gather_attributes(src_attributes,
323 for (const int curve : curves_range) {
324 const IndexRange new_curve = new_points_by_curve[curve];
325 int new_size = new_curve.size();
328 const float used_percent_length = math::clamp(
329 isfinite(overshoot_fac) ? overshoot_fac : 0.1f, 1e-4f, 1.0f);
331 if (!follow_curvature || new_size == 2) {
332 extend_curves_straight(used_percent_length,
338 use_start_lengths.as_span(),
339 use_end_lengths.as_span(),
342 else if (start_points[curve] > 0 || end_points[curve] > 0) {
343 extend_curves_curved(used_percent_length,
344 start_points.as_span(),
345 end_points.as_span(),
349 use_start_lengths.as_span(),
350 use_end_lengths.as_span(),
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
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
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)
static void extend_curves_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_curves_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)
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)
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)
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))
VecBase< float, 3 > float3