collective

Browse / github.com/storytold/cadcraft / patch

PLINE: Undo returns to the last segment's mode, and PLINEWID is the width

PLINE: Undo returns to the last segment's mode, and PLINEWID is the width ## What was wrong I checked PLINE against AutoCAD 2024 as a black box: 76 typed inputs (every arc option, widths, Close, Length, Undo, PLINEWID) run in `accoreconsole` and read back with `entget` and GETVAR. On `main`, 72 match; with this PR, all 76 do. 1. **Undo after an arc segment stayed in arc mode.** In AutoCAD, `_U` returns to the mode of the segment that is now last. After `… point _A point _U`, the next prompt is line mode's "Specify next point or [Arc/Close/Halfwidth/Length/Undo/Width]", so `_L` is **Length**. In CADCraft, `_L` was arc mode's **Line**, and the next point became a pl

Status
open
Score
0.00
Adopters
0 other operators
Author
2ez4gcx (imported from pull request #2205, open)
Base
d864a08b013353143086bd8bb568c26cb6256796
Size
+52 −0 in 2 files
Review
pending
Shared
2026-10-28
Id
40b15c54f53a9158f70b87f8

How it went

No other operator has reported using it yet.

Diff

raw · crates/engine/src/cmd/draw/line_pline.rs crates/engine/src/tests.rs

diff --git a/crates/engine/src/cmd/draw/line_pline.rs b/crates/engine/src/cmd/draw/line_pline.rs--- a/crates/engine/src/cmd/draw/line_pline.rs+++ b/crates/engine/src/cmd/draw/line_pline.rs@@ -256,6 +256,12 @@ impl Interactive for PlineM {     fn name(&self) -> &'static str {         "PLINE"     }+    /// Segments start at PLINEWID, the width the last Width or Halfwidth answer left.+    fn begin(&mut self, s: &mut Session) -> Result<Step> {+        let w = s.doc()?.header.f64("PLINEWID", 0.0);+        (self.start_w, self.end_w) = if w.is_finite() && w > 0.0 { (w, w) } else { (0.0, 0.0) };+        Ok(Step::Continue)+    }     fn prompt(&self, s: &Session) -> Prompt {         if self.asking_width > 0 {             let unit = if self.half { "half-width" } else { "width" };@@ -302,6 +308,11 @@ impl Interactive for PlineM {                 self.end_w = self.start_w;             }             self.asking_width = if self.asking_width == 1 { 2 } else { 0 };+            if self.asking_width == 0 {+                // The ending width becomes PLINEWID, the next polyline's width (AutoCAD:+                // Halfwidth 0.5 0.5 leaves PLINEWID 1).+                s.doc_mut()?.header.set_f64("PLINEWID", self.end_w);+            }             return Ok(Step::Continue);         }         if let (Some(a), Some(st)) = (self.ask, self.verts.last().map(|v| v.p)) {@@ -365,6 +376,10 @@ impl Interactive for PlineM {                         l.bulge = 0.0;                         (l.start_width, l.end_width) = (0.0, 0.0);                     }+                    // Back to the mode of the segment now last (AutoCAD: `_A` point `_U` returns+                    // to "Specify next point", where `_L` is Length, not arc mode's Line).+                    let n = self.verts.len();+                    self.arc_mode = n >= 2 && self.verts.get(n - 2).is_some_and(|v| v.bulge != 0.0);                     self.sync(s, false)?;                     Ok(Step::Continue)                 }diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs--- a/crates/engine/src/tests.rs+++ b/crates/engine/src/tests.rs@@ -1226,6 +1226,43 @@ fn pline_width_answers_taper_the_next_segment() {     assert_eq!(widths(&p), (0.0, vec![(0.0, 0.0), (0.0, 0.0)])); } +/// PLINE against what AutoCAD 2024 stores for the same typed input (black-box: synthetic input+/// in accoreconsole, read back with `entget` and GETVAR).+#[test]+fn pline_undo_mode_and_plinewid_match_autocad() {+    // Undo after an arc segment returns to line mode, where `_L` is Length (a point gives the+    // length, along the last segment).+    let p = typed_pline(+        "pline -0.702422643378533,-28.46727901968281 -27.912058384977463,-34.74188138168937 -22.546524604415925,32.44142803067136 _U \+         25.831317263304115,13.510616645626207 _A -33.2372517304228,12.083585785350365 _U _L -22.546524604415925,32.44142803067136",+    );+    let want = [+        (-0.7024226433785329, -28.4672790196828),+        (-27.91205838497746, -34.74188138168937),+        (25.83131726330411, 13.5106166456262),+        (64.48701958199356, 48.21692560701169),+    ];+    assert_eq!(p.vertices.len(), want.len(), "{p:?}");+    for (v, (x, y)) in p.vertices.iter().zip(want) {+        assert!(v.p.near(Vec2::new(x, y), 1e-9 * x.abs().max(y.abs())) && v.bulge == 0.0, "{p:?}");+    }+    // PLINEWID is the width a new polyline starts with…+    let mut s = Session::new();+    s.cmdline("(setvar \"PLINEWID\" 0.75)").unwrap();+    s.cmdline("pline -21.06802233135781,9.943678105070298 -29.261665218975015,-28.460093326613574 7.898763272534772,6.73634194079888").unwrap();+    s.cmdline("").unwrap();+    assert!(matches!(&s.doc().unwrap().model.last().unwrap().kind, EntityKind::LwPolyline(p) if p.const_width == 0.75));+    // …and the ending width of the last Width or Halfwidth answer (half-width 0.5: PLINEWID 1).+    let mut s = Session::new();+    s.cmdline(+        "pline -9.151085154682761,12.9438035725412 _W 0.0934460985004879 1.547654372298795 19.161590651864245,38.23079339857958 \+         26.720225103092986,-9.028145532375504 _H 0.5 0.5 -24.7035288980598,-14.309723714209586",+    )+    .unwrap();+    s.cmdline("").unwrap();+    assert_eq!(s.doc().unwrap().header.f64("PLINEWID", 0.0), 1.0);+}+ #[test] fn press_and_drag_selection_window() {     let mut s = Session::new();