mirror of
https://github.com/storytold/cadcraft.git
synced 2026-10-24 10:56:51 -06:00
Offset elliptical arcs towards the picked side (#1475)
Found while testing crates/engine/src/cmd/modify.rs:584-597 (offset_kind, EntityKind::Ellipse branch) Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 5.5
parent
bf6d9fd46a
commit
1738d3805e
@@ -586,10 +586,14 @@ pub(crate) fn offset_kind(k: &EntityKind, dist: f64, side: Vec2) -> Option<Entit
|
||||
EntityKind::Ellipse(e) => {
|
||||
// Approximate with a polyline offset of the tessellation.
|
||||
let ge = cadcraft_geom::Ellipse { center: e.center.xy(), major: e.major.xy(), ratio: e.ratio, start: e.start, end: e.end };
|
||||
// Inside = on the centre side of the full ellipse, even for an open arc.
|
||||
let inside = {
|
||||
let mut pts = Vec::new();
|
||||
ge.tessellate(e.major.xy().len() * 1e-3, &mut pts);
|
||||
cadcraft_geom::point_in_polygon(&pts, side)
|
||||
let a = e.major.xy().len();
|
||||
let b = a * e.ratio.abs();
|
||||
let u = e.major.xy().normalized();
|
||||
let d = side - e.center.xy();
|
||||
let (x, y) = (d.dot(u) * b, d.dot(u.perp()) * a);
|
||||
x * x + y * y < (a * b) * (a * b)
|
||||
};
|
||||
// offset_points shifts along the left normal, which points into a counter-clockwise ellipse.
|
||||
let mut pts = Vec::new();
|
||||
|
||||
@@ -754,3 +754,18 @@ fn offset_polyline_arc_bulge_follows_joined_endpoints() {
|
||||
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);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn offset_elliptical_arc_follows_picked_side() {
|
||||
let max_x = |side: Value| {
|
||||
let mut s = Session::new();
|
||||
let e = h(&s.execute("ellipse", &json!({"center": [0, 0], "major": [10, 0], "ratio": 0.5, "start": 0, "end": 90})).unwrap());
|
||||
s.execute("offset", &json!({"handle": e, "distance": 1, "side": side})).unwrap();
|
||||
let p = poly(&last(&s));
|
||||
p.vertices.iter().map(|v| v.p.x).fold(f64::MIN, f64::max)
|
||||
};
|
||||
let centre = max_x(json!([0, 0]));
|
||||
assert!((centre - 9.0).abs() < 0.05, "centre side went outward: max x = {centre}");
|
||||
let outer = max_x(json!([20, 20]));
|
||||
assert!((outer - 11.0).abs() < 0.05, "outer side went inward: max x = {outer}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user