Skip to content

Commit 865e971

Browse files
authored
Refactor eval_pathseg_euclidean() to use kurbo's faster/more accurate inv_arclen() (#3969)
1 parent e529f74 commit 865e971

File tree

1 file changed

+4
-28
lines changed

1 file changed

+4
-28
lines changed

node-graph/libraries/vector-types/src/vector/algorithms/bezpath_algorithms.rs

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::vector::misc::{PointSpacingType, dvec2_to_point, point_to_dvec2};
66
use core_types::math::polynomial::pathseg_to_parametric_polynomial;
77
use glam::{DMat2, DVec2};
88
use kurbo::common::{solve_cubic, solve_quadratic};
9-
use kurbo::{BezPath, CubicBez, DEFAULT_ACCURACY, Line, ParamCurve, ParamCurveDeriv, PathEl, PathSeg, Point, QuadBez, Rect, Shape, Vec2};
9+
use kurbo::{BezPath, CubicBez, DEFAULT_ACCURACY, Line, ParamCurve, ParamCurveArclen, ParamCurveDeriv, PathEl, PathSeg, Point, QuadBez, Rect, Shape, Vec2};
1010
use std::f64::consts::{FRAC_PI_2, PI};
1111

1212
/// Splits the [`BezPath`] at segment index at `t` value which lie in the range of [0, 1].
@@ -342,34 +342,10 @@ pub(crate) fn pathseg_length_centroid_and_length(segment: PathSeg, accuracy: Opt
342342
}
343343
}
344344

345-
/// Finds the t value of point on the given path segment i.e fractional distance along the segment's total length.
346-
/// It uses a binary search to find the value `t` such that the ratio `length_up_to_t / total_length` approximates the input `distance`.
345+
/// Finds the parametric `t` value on the given path segment corresponding to a fractional arc-length `distance` (0–1).
346+
/// Delegates to kurbo's `inv_arclen` which uses the ITP method with incremental arc-length computation.
347347
pub fn eval_pathseg_euclidean(segment: PathSeg, distance: f64, accuracy: f64) -> f64 {
348-
let mut low_t = 0.;
349-
let mut mid_t = 0.5;
350-
let mut high_t = 1.;
351-
352-
let total_length = segment.perimeter(accuracy);
353-
354-
if !total_length.is_finite() || total_length <= f64::EPSILON {
355-
return 0.;
356-
}
357-
358-
let distance = distance.clamp(0., 1.);
359-
360-
while high_t - low_t > accuracy {
361-
let current_length = segment.subsegment(0.0..mid_t).perimeter(accuracy);
362-
let current_distance = current_length / total_length;
363-
364-
if current_distance > distance {
365-
high_t = mid_t;
366-
} else {
367-
low_t = mid_t;
368-
}
369-
mid_t = (high_t + low_t) / 2.;
370-
}
371-
372-
mid_t
348+
segment.inv_arclen(distance.clamp(0., 1.) * segment.arclen(accuracy), accuracy)
373349
}
374350

375351
/// Converts from a bezpath (composed of multiple segments) to a point along a certain segment represented.

0 commit comments

Comments
 (0)