From 23d44cd9c88fc82fc54ba1a5e4ad0193b63fa5f1 Mon Sep 17 00:00:00 2001 From: aiongg Date: Sun, 25 Oct 2026 04:26:14 +0000 Subject: [PATCH] MEASUREGEOM Volume: the height can be given by two points, and Enter at the height prompt says a height is required --- crates/engine/src/cmd/inquiry.rs | 43 ++++++++++++++++------ crates/engine/tests/it/inquiry_keywords.rs | 8 ++++ 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/crates/engine/src/cmd/inquiry.rs b/crates/engine/src/cmd/inquiry.rs index 26f074a96..9962c3fd6 100644 --- a/crates/engine/src/cmd/inquiry.rs +++ b/crates/engine/src/cmd/inquiry.rs @@ -933,6 +933,8 @@ pub(super) struct AreaM { volume: bool, /// Areas measured in volume mode that still wait for their height, oldest first. pending: Vec, + /// The first point of a height given by two points. + height_from: Option, } impl AreaM { @@ -960,6 +962,19 @@ impl AreaM { AreaMode::Subtract => self.total - v, } } + /// Measure the oldest pending area's volume with height `h`. + fn height(&mut self, s: &mut Session, h: f64) -> Step { + match self.pending.first().map(|a| a * h.abs()) { + Some(v) if v.is_finite() && self.total_with(v).is_finite() => { + self.pending.remove(0); + self.volume_measured(s, v) + } + _ => { + s.echo("The volume is too large."); + Step::Continue + } + } + } /// Report a volume (and the running total in add/subtract mode); ends the command in single mode. fn volume_measured(&mut self, s: &mut Session, v: f64) -> Step { s.echo(volume_text(s, v)); @@ -1003,7 +1018,10 @@ impl Interactive for AreaM { } fn prompt(&self, _s: &Session) -> Prompt { if !self.pending.is_empty() { - return Prompt::new(format!("{}Specify height", self.mode_prefix()), Accept::NUMBER); + return match self.height_from { + Some(p) => Prompt::new("Specify second point", Accept::POINT).base(p), + None => Prompt::new(format!("{}Specify height", self.mode_prefix()), Accept::POINT_OR_NUMBER), + }; } if self.object { return Prompt::new(format!("{}Select objects", self.mode_prefix()), Accept::SELECT); @@ -1023,17 +1041,20 @@ impl Interactive for AreaM { } fn input(&mut self, s: &mut Session, i: Input) -> Result { if !self.pending.is_empty() { - if let Input::Text(t) = i { - match crate::units::parse_distance(&t).filter(|v| v.is_finite()) { - Some(h) => match self.pending.first().map(|a| a * h.abs()) { - Some(v) if v.is_finite() && self.total_with(v).is_finite() => { - self.pending.remove(0); - return Ok(self.volume_measured(s, v)); - } - _ => s.echo("The volume is too large."), - }, - None => s.echo("Requires a distance."), + // A height is typed, or given by two points (their distance). + match (i, self.height_from) { + (Input::Point(p), None) => self.height_from = Some(p), + (Input::Point(p), Some(from)) => { + self.height_from = None; + return Ok(self.height(s, p.dist(from))); } + (Input::Text(t), None) => match crate::units::parse_distance(&t).filter(|v| v.is_finite()) { + Some(h) => return Ok(self.height(s, h)), + None => s.echo("Requires a distance."), + }, + (Input::Enter, None) => s.echo("Requires a height."), + (Input::Enter, Some(_)) => s.echo("Requires a second point."), + _ => {} } return Ok(Step::Continue); } diff --git a/crates/engine/tests/it/inquiry_keywords.rs b/crates/engine/tests/it/inquiry_keywords.rs index 1a46bc5c9..5a2c4cb6e 100644 --- a/crates/engine/tests/it/inquiry_keywords.rs +++ b/crates/engine/tests/it/inquiry_keywords.rs @@ -229,6 +229,14 @@ fn measuregeom_volume_multiplies_an_area_by_a_height() { assert!(has(&log, "Requires a distance."), "{log:?}"); assert!(s.prompt_text().contains("Specify height"), "{}", s.prompt_text()); + // Enter is not a height; two points give the height as their distance. + let (mut s, log) = run(&["measuregeom", "v", "0,0", "4,0", "4,3", "", "", "1,1"]); + assert!(has(&log, "Requires a height."), "{log:?}"); + assert!(s.prompt_text().contains("Specify second point"), "{}", s.prompt_text()); + s.cmdline("7,9").unwrap(); + assert!(has(&s.log, "Volume = 60.0000"), "{:?}", s.log); + assert!(s.running.is_none(), "{}", s.prompt_text()); + // The JSON forms, by points and by handle. let mut s = Session::new(); let r = s.execute("measuregeom", &json!({"mode": "volume", "points": [[0, 0], [4, 0], [4, 3]], "height": 10})).unwrap();