mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-08 16:30:41 +00:00
Merge pull request #5393 from storytold/fix/sec-arclen-guarded-measures
Geometry: anchor positions and Simplify measure curves through the guarded arc length
This commit is contained in:
@@ -278,7 +278,7 @@ impl SubPath {
|
||||
}
|
||||
let mut pos = vec![0.0];
|
||||
for i in 0..self.segment_count() {
|
||||
let len = kurbo::ParamCurveArclen::arclen(&self.segment(i), 1e-3);
|
||||
let len = measured_arclen(&PathSeg::Cubic(self.segment(i)), 1e-3);
|
||||
pos.push(pos.last().copied().unwrap_or(0.0) + len);
|
||||
}
|
||||
pos
|
||||
@@ -621,7 +621,7 @@ const MEASURE_LIMIT: f64 = 1e9;
|
||||
|
||||
/// The length of `seg` to `accuracy`; 0 for a segment whose control points are not finite or past
|
||||
/// [`MEASURE_LIMIT`].
|
||||
pub(crate) fn measured_arclen(seg: &PathSeg, accuracy: f64) -> f64 {
|
||||
pub fn measured_arclen(seg: &PathSeg, accuracy: f64) -> f64 {
|
||||
let ok = |p: Point| p.x.is_finite() && p.y.is_finite() && p.x.abs() <= MEASURE_LIMIT && p.y.abs() <= MEASURE_LIMIT;
|
||||
let fits = match seg {
|
||||
PathSeg::Line(l) => ok(l.p0) && ok(l.p1),
|
||||
@@ -838,6 +838,13 @@ mod tests {
|
||||
assert_eq!(c.kind, AnchorKind::Corner);
|
||||
}
|
||||
|
||||
/// Handles too large to measure give the curve no length instead of subdividing it without end.
|
||||
#[test]
|
||||
fn anchor_positions_of_an_unmeasurable_curve_are_finite() {
|
||||
let p = curve(Point::new(100.0, 1e300), Point::new(300.0, -1e300));
|
||||
assert_eq!(p.subpaths[0].anchor_arc_positions(), [0.0, 0.0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn length_of_square() {
|
||||
assert!((square().length() - 40.0).abs() < 1e-6);
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use kurbo::{CubicBez, ParamCurveArclen, Point, Rect, Vec2};
|
||||
use kurbo::{CubicBez, PathSeg, Point, Rect, Vec2};
|
||||
use vectorcraft_geom::path::measured_arclen;
|
||||
use vectorcraft_geom::{Anchor, AnchorKind, PathData, SubPath};
|
||||
|
||||
use crate::boolean::{Seg, segs_to_subpath};
|
||||
@@ -115,7 +116,8 @@ fn simplify_run(run: &[Seg], opts: &SimplifyOptions) -> Vec<Seg> {
|
||||
}
|
||||
let mut pts = Vec::new();
|
||||
for (k, s) in piece.iter().enumerate() {
|
||||
let len = s.c.arclen(1e-6);
|
||||
// Guarded: kurbo subdivides without end on huge finite coordinates.
|
||||
let len = measured_arclen(&PathSeg::Cubic(s.c), 1e-6);
|
||||
let m = ((len / (tol * 0.5)).ceil() as usize).clamp(4, 256);
|
||||
sample(&s.c, m, &mut pts, k == 0);
|
||||
}
|
||||
@@ -454,7 +456,7 @@ fn seam_error(original: &SubPath, before: &SubPath, fit: &SubPath, tol: f64) ->
|
||||
let mut pts = Vec::new();
|
||||
for j in (0..sp.segment_count()).filter(|&j| !seam_only || is_seam(j)) {
|
||||
let c = sp.segment(j);
|
||||
let m = ((c.arclen(1e-6) / (tol.max(1e-6) * 0.5)).ceil() as usize).clamp(4, 256);
|
||||
let m = ((measured_arclen(&PathSeg::Cubic(c), 1e-6) / (tol.max(1e-6) * 0.5)).ceil() as usize).clamp(4, 256);
|
||||
sample(&c, m, &mut pts, true);
|
||||
}
|
||||
pts
|
||||
|
||||
Reference in New Issue
Block a user