Open zdila opened 8 months ago
One way could be: iterate over segments of BezPath
and compare their arclen with desired distance obtained from initial offset and (accumulated) spacings.
This solution is probably bit naive for Bezier segments as pointed out here. But it should work as expected for purely linear paths, like ways in OpenStreetMap data.
use kurbo::{BezPath, ParamCurve, ParamCurveArclen, ParamCurveDeriv, PathSeg, Point, Vec2};
fn eval_spacing(path: &BezPath, start_offset: f64, spacing: f64) -> Vec<(Point, Vec2)> {
let mut target_length = start_offset;
let mut prev_length = 0.0;
let mut result = vec![];
for seg in path.segments() {
let seg_length = seg.arclen(1e-3);
// are we inside current segment?
while (target_length - prev_length) <= seg_length {
// local t parameter for segment in range 0.0..1.0
let t = (target_length - prev_length) / seg_length;
// obtain curve point and tangent
let p = seg.eval(t);
let tangent = match seg {
PathSeg::Quad(s) => s.deriv().eval(t).to_vec2(),
PathSeg::Cubic(s) => s.deriv().eval(t).to_vec2(),
PathSeg::Line(s) => s.deriv().eval(t).to_vec2(),
};
result.push((p, tangent));
// move to next spacing
target_length += spacing;
}
// mark covered length
prev_length += seg_length;
}
result
}
There is maybe better way to obtain tangent, but it is already late evening here >.>
Traits ParamCurve
, ParamCurveArclen
and ParamCurveDeriv
are needed for eval
, arclen
and deriv
functions.
So I've forgot about inv_arclen
method. That one should return correct t
values even for Bezier segments.
So instead of line
let t = (target_length - prev_length) / seg_length;
it should be:
let t = seg.inv_arclen(target_length - prev_length, 1e-3);
Obviously one could pass higher accuracy.
Thank you.
Traits ParamCurve, ParamCurveArclen and ParamCurveDeriv are needed for eval, arclen and deriv functions.
Some of these should be implementable for BezPath. Probably not ParamCurveDeriv
, but certainly the others. Would there be any interest in having that happen?
Implementing ParamCurveArclen for BezPath is going to be pretty inefficient, especially for the inverse arclengths (it will have to traverse the entire path). Fundamentally this problem is very much the same as the dash iterator for stroking, the best approach is probably to adapt that.
Hello,
(How) Is it possible to get coordinates and tangents from kurbo::BezPath of evenly spaced points on a curve if I have a start offset and spacing? I would like to implement something like Mapnik's MarkersSymbolizer.