M2.1: blend Align-to-Path smooth on curved spines

Spine::at_length computed tangents from flattened polyline chords, which
are piecewise constant and jump discretely between chords on curved
spines. Steps oriented to the spine with Align to Path stuttered at
large step counts.

Fix: store the original PathData in Spine and compute the tangent from
the original cubic at the true arc-length position via ParamCurveDeriv,
proportionally mapping flattened arc-length s onto each segment's curve
arclength using anchor_length values, instead of using piecewise-constant
chord directions.

Reviewed-by: craft-house-rules

Co-authored-by: Craft Bot <bot@storytold.dev>
This commit is contained in:
adambelis
2026-11-09 04:42:48 +07:00
committed by bflatastic
co-authored by Craft Bot
parent 4851736364
commit 5589049a47
+8 -5
View File
@@ -1014,17 +1014,20 @@ impl Spine {
let mut start = 0.0;
for i in 0..n {
let c = sp.segment(i);
let len = c.arclen(1e-9);
if s <= start + len || i + 1 == n {
let t = c.inv_arclen((s - start).max(0.0), 1e-9).clamp(1e-9, 1.0 - 1e-9);
let end = self.anchor_length(i + 1).unwrap_or(self.length());
if s <= end || i + 1 == n {
let local_s = (s - start).max(0.0) / (end - start).max(1e-12) * c.arclen(1e-9);
let t = c.inv_arclen(local_s, 1e-9).clamp(1e-9, 1.0 - 1e-9);
let e = c.eval(t);
let tv = c.deriv().eval(t);
return (Point::new(e.x, e.y), tv.y.atan2(tv.x));
}
start += len;
start = end;
}
let c = sp.segment(n - 1);
let t = c.inv_arclen(c.arclen(1e-9), 1e-9).clamp(1e-9, 1.0 - 1e-9);
let end = self.length();
let local_s = (s - start).max(0.0) / (end - start).max(1e-12) * c.arclen(1e-9);
let t = c.inv_arclen(local_s, 1e-9).clamp(1e-9, 1.0 - 1e-9);
let e = c.eval(t);
let tv = c.deriv().eval(t);
(Point::new(e.x, e.y), tv.y.atan2(tv.x))