2D prism route: the same letters cut again are one exact boolean (#1644)
Thanks @phanoob.
This commit is contained in:
1 parent
3087363c44
commit
64b0b674d2
3 files changed
+76
-8
No files matched your search
@@ -1300,10 +1300,15 @@ fn exact_loop(lp: &Loop2, tags: &[Tag], sources: &[Seg2], near: f64) -> (Vec<Seg
|
||||
};
|
||||
let (t0, t1) = (at(seg.start()), at(last.end()));
|
||||
if (t1 - t0).abs() < 1e-9 {
|
||||
// A sliver of the curve: its arcs as they are.
|
||||
for m in k..=j {
|
||||
let q = (first + m) % n;
|
||||
pieces.push(Piece::Plain(*lp.segs.get(q).unwrap_or(seg), tag(q)));
|
||||
// A sliver of the curve: its arcs as they are, or, shorter than the tolerance (where
|
||||
// a curve lies on another, as when the same letters are cut again), nothing: its
|
||||
// neighbours meet where it was, and as an edge it would have no length.
|
||||
let length: f64 = (k..=j).filter_map(|m| lp.segs.get((first + m) % n)).map(Seg2::length).sum();
|
||||
if length > near {
|
||||
for m in k..=j {
|
||||
let q = (first + m) % n;
|
||||
pieces.push(Piece::Plain(*lp.segs.get(q).unwrap_or(seg), tag(q)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let t = Tag { end: tag((first + j) % n).end, ..tag(i) };
|
||||
@@ -1313,6 +1318,9 @@ fn exact_loop(lp: &Loop2, tags: &[Tag], sources: &[Seg2], near: f64) -> (Vec<Seg
|
||||
}
|
||||
// Each joint at an exact curve: both sides end at the same point, the exact crossing where
|
||||
// the curve is cut, its own end point where it ends.
|
||||
if pieces.is_empty() {
|
||||
return plain();
|
||||
}
|
||||
let m = pieces.len();
|
||||
let inner = |t: f64| t > 1e-9 && t < 1.0 - 1e-9;
|
||||
for i in 0..m {
|
||||
@@ -1690,6 +1698,11 @@ fn split_seg(seg: &Seg2, pts: &[Vec2], tol: f64) -> Option<Vec<Seg2>> {
|
||||
{
|
||||
return None;
|
||||
}
|
||||
// A point within `tol` of an end is that end (the sewing welds them into one): a cut
|
||||
// there would leave a piece with no length.
|
||||
if p.dist(seg.start()) < tol || p.dist(seg.end()) < tol {
|
||||
return None;
|
||||
}
|
||||
let t = seg.closest_param(*p);
|
||||
(t > 1e-9 && t < 1.0 - 1e-9 && seg.point_at(t).dist(*p) < tol).then_some(t)
|
||||
})
|
||||
@@ -1951,13 +1964,38 @@ fn sew_connected_sections(
|
||||
};
|
||||
let at = |u: Vec2, z: f64| plane.to_world(u) + d * z;
|
||||
let welded = |u: Vec2, z: f64| at(weld(&ends, &grid, u).unwrap_or(u), z);
|
||||
// One edge between two ends, whichever way a wall or a cap reads the curve there: a piece of
|
||||
// a font's curve so short that one section reads it as an arc within the tolerance, where
|
||||
// another has the curve itself (the same letters cut again), is one edge. The first reading
|
||||
// stands for all of them.
|
||||
let readings: std::cell::RefCell<Vec<(Vec3, Vec3, Vec3, EdgeSpec)>> = std::cell::RefCell::new(Vec::new());
|
||||
let same_edge = |spec: EdgeSpec, a: Vec3, b: Vec3, mid: Vec3| -> EdgeSpec {
|
||||
let mut known = readings.borrow_mut();
|
||||
for (ka, kb, km, k) in known.iter() {
|
||||
if km.dist(mid) <= tol * 10.0 {
|
||||
if *ka == a && *kb == b {
|
||||
return k.clone();
|
||||
}
|
||||
if *ka == b && *kb == a {
|
||||
return k.reversed();
|
||||
}
|
||||
}
|
||||
}
|
||||
known.push((a, b, mid, spec.clone()));
|
||||
spec
|
||||
};
|
||||
let edge = |sg: &Seg2, z: f64| -> Option<EdgeSpec> {
|
||||
Some(match sg {
|
||||
Seg2::Line { .. } => EdgeSpec::Line { a: welded(sg.start(), z), b: welded(sg.end(), z) },
|
||||
Seg2::Arc { .. } => EdgeSpec::Arc { a: welded(sg.start(), z), b: welded(sg.end(), z), mid: at(sg.point_at(0.5), z) },
|
||||
Seg2::Arc { .. } => {
|
||||
let (a, b, mid) = (welded(sg.start(), z), welded(sg.end(), z), at(sg.point_at(0.5), z));
|
||||
same_edge(EdgeSpec::Arc { a, b, mid }, a, b, mid)
|
||||
}
|
||||
_ => {
|
||||
let [p0, p1, p2, p3] = cubic_of(sg)?;
|
||||
EdgeSpec::Chain { ctrl: same_chain([welded(p0, z), at(p1, z), at(p2, z), welded(p3, z)]).to_vec().into() }
|
||||
let c = same_chain([welded(p0, z), at(p1, z), at(p2, z), welded(p3, z)]);
|
||||
let mid = (c[0] + (c[1] + c[2]) * 3.0 + c[3]) * 0.125;
|
||||
same_edge(EdgeSpec::Chain { ctrl: c.to_vec().into() }, c[0], c[3], mid)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user