Co-authored-by: Brandon Thomas <echelon@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
64b7825d08
commit
4257674dfa
|
|
@ -682,20 +682,40 @@ pub(crate) fn offset_polyline(pl: &Polyline, d: f64) -> Option<Vec<PolyVertex>>
|
|||
return None;
|
||||
}
|
||||
let n = segs.len();
|
||||
let mut verts: Vec<PolyVertex> = Vec::new();
|
||||
// Where each offset segment starts after joining it to the previous one.
|
||||
let mut starts: Vec<Vec2> = Vec::with_capacity(n);
|
||||
for i in 0..n {
|
||||
let s = segs.get(i)?;
|
||||
let start = if i == 0 && !pl.closed {
|
||||
starts.push(if i == 0 && !pl.closed {
|
||||
s.start()
|
||||
} else {
|
||||
let prev = segs.get((i + n - 1) % n)?;
|
||||
join_point(prev, s).unwrap_or(s.start())
|
||||
});
|
||||
}
|
||||
let mut verts: Vec<PolyVertex> = Vec::new();
|
||||
for i in 0..n {
|
||||
let s = segs.get(i)?;
|
||||
let start = *starts.get(i)?;
|
||||
let end = if i + 1 < n {
|
||||
*starts.get(i + 1)?
|
||||
} else if pl.closed {
|
||||
*starts.first()?
|
||||
} else {
|
||||
s.end()
|
||||
};
|
||||
let bulge = match s {
|
||||
Segment::Line(_) => 0.0,
|
||||
Segment::Arc { arc, ccw } => {
|
||||
let sw = arc.sweep();
|
||||
cadcraft_geom::arc_to_bulge(if *ccw { sw } else { -sw })
|
||||
// The joined endpoints may have moved along the circle: take the sweep between them.
|
||||
let sweep = if start.near(end, 1e-9) {
|
||||
arc.sweep()
|
||||
} else if *ccw {
|
||||
ccw_sweep(arc.center.angle_to(start), arc.center.angle_to(end))
|
||||
} else {
|
||||
ccw_sweep(arc.center.angle_to(end), arc.center.angle_to(start))
|
||||
};
|
||||
cadcraft_geom::arc_to_bulge(if *ccw { sweep } else { -sweep })
|
||||
}
|
||||
};
|
||||
verts.push(PolyVertex { p: start, bulge, start_width: 0.0, end_width: 0.0 });
|
||||
|
|
@ -703,7 +723,6 @@ pub(crate) fn offset_polyline(pl: &Polyline, d: f64) -> Option<Vec<PolyVertex>>
|
|||
if !pl.closed {
|
||||
verts.push(PolyVertex::new(segs.last()?.end()));
|
||||
}
|
||||
// Recompute arc bulges where endpoints moved (approximation: keep sweep sign).
|
||||
Some(verts)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -707,3 +707,17 @@ fn pedit_preselected_line_asks_to_convert() {
|
|||
assert!(s.running.is_none());
|
||||
assert!(matches!(kind(&s, &m), EntityKind::Line(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn offset_polyline_arc_bulge_follows_joined_endpoints() {
|
||||
let mut s = Session::new();
|
||||
// A diagonal line into a CCW semicircle centred on (10, 5); offsetting inward moves the arc start.
|
||||
let pl = pline(&mut s, json!([[0, -5], {"p": [10, 0], "bulge": 1}, [10, 10]]), false);
|
||||
s.execute("offset", &json!({"handle": pl, "distance": 1, "side": [12, 5]})).unwrap();
|
||||
let p = poly(&last(&s));
|
||||
let (a, b) = (p.vertices[1], p.vertices[2]);
|
||||
let (arc, ccw) = cadcraft_geom::bulge_to_arc(a.p, b.p, a.bulge).unwrap();
|
||||
assert!(ccw);
|
||||
assert!(near(arc.center, 10.0, 5.0), "arc centre drifted to {:?}", arc.center);
|
||||
assert!((arc.radius - 4.0).abs() < 1e-6, "radius {}", arc.radius);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue