DIMANGULAR: accept polyline segments (fixes #10) (#15)

Picking a side of a rectangle or a PLINE segment was rejected with
"Select a line or an arc." because only LINE and ARC entities were
accepted. The picked object is now resolved to the segment under the
cursor: straight polyline segments work like lines and arc segments
like arcs.
This commit is contained in:
Books 2026-10-11 03:57:13 +11:00 committed by GitHub
parent 698f2c8c36
commit 093c87d08a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 42 additions and 6 deletions

View File

@ -760,6 +760,19 @@ fn pick_at(s: &Session, p: Vec2) -> Option<Handle> {
crate::select::pick(s.doc().ok()?, &s.space(), p, ap)
}
/// The straight or curved piece of `h` picked at `p`: a line, an arc, or the polyline segment nearest `p`.
fn segment_at(s: &Session, h: Handle, p: Vec2) -> Option<Segment> {
match &s.doc().ok()?.entity(h)?.kind {
EntityKind::Line(l) => Some(Segment::Line(cadcraft_geom::Line::new(l.a.xy(), l.b.xy()))),
EntityKind::Arc(a) => Some(Segment::Arc { arc: cadcraft_geom::Arc::new(a.center.xy(), a.radius, a.start, a.end), ccw: true }),
EntityKind::LwPolyline(pl) => cadcraft_geom::Polyline { vertices: pl.vertices.clone(), closed: pl.closed }
.segments()
.into_iter()
.min_by(|x, y| x.closest(p).dist(p).total_cmp(&y.closest(p).dist(p))),
_ => None,
}
}
struct LinearM {
aligned: bool,
pts: Vec<Vec2>,
@ -1003,15 +1016,13 @@ impl Interactive for AngularM {
s.echo("*Invalid selection*");
return Ok(Step::Continue);
};
let kind = s.doc()?.entity(h).map(|e| e.kind.clone());
match kind {
Some(EntityKind::Arc(a)) if self.first.is_none() => {
let g = cadcraft_geom::Arc::new(a.center.xy(), a.radius, a.start, a.end);
match segment_at(s, h, p) {
Some(Segment::Arc { arc: g, .. }) if self.first.is_none() => {
self.arc = Some((g.center, g.start_point(), g.end_point()));
}
Some(EntityKind::Line(l)) => {
Some(Segment::Line(l)) => {
self.handles.push(h);
let seg = (l.a.xy(), l.b.xy());
let seg = (l.a, l.b);
if self.first.is_none() {
self.first = Some(seg);
} else {

View File

@ -143,6 +143,31 @@ fn angular_between_lines_follows_rotation() {
assert_eq!(cadcraft_render::dimension_in(s.doc().unwrap(), &dim(&s, d)).value, "45°");
}
#[test]
fn interactive_angular_picks_polyline_segments() {
// Rectangle sides are polyline segments, not lines (issue #10).
let mut s = Session::new();
s.cmdline("rectang 0,0 10,5").unwrap();
s.cmdline("dimangular").unwrap();
s.cmdline("5,0").unwrap();
s.cmdline("0,2").unwrap();
s.cmdline("2,2").unwrap();
assert!(s.running.is_none());
let d = s.last_dim.unwrap();
assert_eq!(cadcraft_render::dimension_in(s.doc().unwrap(), &dim(&s, d)).value, "90°");
// A polyline arc segment works like an arc.
s.cmdline("pline 20,0 30,0 a 30,10").unwrap();
s.cmdline("").unwrap();
s.cmdline("dimangular").unwrap();
let (cx, cy) = (30.0 + 5.0 * std::f64::consts::FRAC_1_SQRT_2, 5.0 - 5.0 * std::f64::consts::FRAC_1_SQRT_2);
s.cmdline(&format!("{cx},{cy}")).unwrap();
s.cmdline("40,5").unwrap();
assert!(s.running.is_none());
let d2 = s.last_dim.unwrap();
assert_ne!(d, d2);
assert_eq!(cadcraft_render::dimension_in(s.doc().unwrap(), &dim(&s, d2)).value, "180°");
}
#[test]
fn erase_disassociate_and_reassociate() {
let mut s = Session::new();