Refactor eval_pathseg_euclidean() to use kurbo's faster/more accurate inv_arclen() (#3969)

This commit is contained in:
Keavon Chambers 2026-03-28 16:30:26 -07:00 committed by GitHub
parent e529f74495
commit 865e9713ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 4 additions and 28 deletions

View File

@ -6,7 +6,7 @@ use crate::vector::misc::{PointSpacingType, dvec2_to_point, point_to_dvec2};
use core_types::math::polynomial::pathseg_to_parametric_polynomial; use core_types::math::polynomial::pathseg_to_parametric_polynomial;
use glam::{DMat2, DVec2}; use glam::{DMat2, DVec2};
use kurbo::common::{solve_cubic, solve_quadratic}; use kurbo::common::{solve_cubic, solve_quadratic};
use kurbo::{BezPath, CubicBez, DEFAULT_ACCURACY, Line, ParamCurve, ParamCurveDeriv, PathEl, PathSeg, Point, QuadBez, Rect, Shape, Vec2}; use kurbo::{BezPath, CubicBez, DEFAULT_ACCURACY, Line, ParamCurve, ParamCurveArclen, ParamCurveDeriv, PathEl, PathSeg, Point, QuadBez, Rect, Shape, Vec2};
use std::f64::consts::{FRAC_PI_2, PI}; use std::f64::consts::{FRAC_PI_2, PI};
/// Splits the [`BezPath`] at segment index at `t` value which lie in the range of [0, 1]. /// 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
} }
} }
/// Finds the t value of point on the given path segment i.e fractional distance along the segment's total length. /// Finds the parametric `t` value on the given path segment corresponding to a fractional arc-length `distance` (01).
/// It uses a binary search to find the value `t` such that the ratio `length_up_to_t / total_length` approximates the input `distance`. /// Delegates to kurbo's `inv_arclen` which uses the ITP method with incremental arc-length computation.
pub fn eval_pathseg_euclidean(segment: PathSeg, distance: f64, accuracy: f64) -> f64 { pub fn eval_pathseg_euclidean(segment: PathSeg, distance: f64, accuracy: f64) -> f64 {
let mut low_t = 0.; segment.inv_arclen(distance.clamp(0., 1.) * segment.arclen(accuracy), accuracy)
let mut mid_t = 0.5;
let mut high_t = 1.;
let total_length = segment.perimeter(accuracy);
if !total_length.is_finite() || total_length <= f64::EPSILON {
return 0.;
}
let distance = distance.clamp(0., 1.);
while high_t - low_t > accuracy {
let current_length = segment.subsegment(0.0..mid_t).perimeter(accuracy);
let current_distance = current_length / total_length;
if current_distance > distance {
high_t = mid_t;
} else {
low_t = mid_t;
}
mid_t = (high_t + low_t) / 2.;
}
mid_t
} }
/// Converts from a bezpath (composed of multiple segments) to a point along a certain segment represented. /// Converts from a bezpath (composed of multiple segments) to a point along a certain segment represented.