mirror of
https://github.com/storytold/cadcraft.git
synced 2026-11-01 23:06:50 -06:00
This commit is contained in:
@@ -427,7 +427,7 @@ fn run_texts(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
mod count;
|
||||
|
||||
#[derive(Default)]
|
||||
struct DistM {
|
||||
pub(super) struct DistM {
|
||||
first: Option<Vec2>,
|
||||
first_source: Option<crate::snap::ViewportPoint>,
|
||||
/// Multiple points: the points so far, the first included.
|
||||
@@ -662,7 +662,7 @@ enum AreaMode {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct AreaM {
|
||||
pub(super) struct AreaM {
|
||||
pts: Vec<Vec2>,
|
||||
mode: AreaMode,
|
||||
total: f64,
|
||||
|
||||
@@ -26,7 +26,10 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
.noundo()
|
||||
.interactive(|_| Ok(Box::<PickM>::default())),
|
||||
CommandSpec::new("find", "Find...", run_find).menu(&["Edit", "Find..."]).params("{find, replace?, matchCase?: bool, wholeWord?: bool}"),
|
||||
CommandSpec::new("measuregeom", "Measure Geometry", run_measuregeom).params("{mode: distance|radius|angle|area, ...}").noundo(),
|
||||
CommandSpec::new("measuregeom", "Measure Geometry", run_measuregeom)
|
||||
.params("{mode: distance|radius|angle|area, ...}")
|
||||
.noundo()
|
||||
.interactive(|_| Ok(Box::<MeasureM>::default())),
|
||||
CommandSpec::new("radius.measure", "Radius", run_radius).menu(&["Tools", "Inquiry", "Radius"]).params("{handle}").noundo(),
|
||||
CommandSpec::new("angle.measure", "Angle", run_angle).menu(&["Tools", "Inquiry", "Angle"]).params("{vertex, p1, p2} | {h1, h2}").noundo(),
|
||||
]
|
||||
@@ -319,6 +322,61 @@ fn run_measuregeom(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
}
|
||||
}
|
||||
|
||||
/// MEASUREGEOM typed or picked: choose what to measure, then continue as DIST, AREA or a radius pick.
|
||||
#[derive(Default)]
|
||||
struct MeasureM {
|
||||
inner: Option<Box<dyn Interactive>>,
|
||||
/// Waiting for the arc or circle of the Radius option.
|
||||
radius: bool,
|
||||
}
|
||||
|
||||
impl Interactive for MeasureM {
|
||||
fn name(&self) -> &'static str {
|
||||
"MEASUREGEOM"
|
||||
}
|
||||
fn prompt(&self, s: &Session) -> Prompt {
|
||||
match &self.inner {
|
||||
Some(m) => m.prompt(s),
|
||||
None if self.radius => Prompt::new("Select arc or circle", Accept::POINT),
|
||||
None => Prompt::new("Enter an option", Accept { point: false, number: false, text: false, select: false, enter: true })
|
||||
.kw(&["Distance", "Radius", "ARea"])
|
||||
.default("Distance"),
|
||||
}
|
||||
}
|
||||
fn input(&mut self, s: &mut Session, i: Input) -> Result<Step> {
|
||||
if let Some(m) = &mut self.inner {
|
||||
return m.input(s, i);
|
||||
}
|
||||
if self.radius {
|
||||
let Input::Point(p) = i else { return Ok(Step::Done) };
|
||||
let Some(h) = super::curves::pick_at(s, p) else { return Ok(Step::Continue) };
|
||||
match run_radius(s, &json!({ "handle": h.0 })) {
|
||||
Ok(r) => {
|
||||
for l in r["message"].as_str().unwrap_or_default().lines() {
|
||||
s.echo(l.to_string());
|
||||
}
|
||||
return Ok(Step::Done);
|
||||
}
|
||||
Err(_) => s.echo("Select an arc or circle."),
|
||||
}
|
||||
return Ok(Step::Continue);
|
||||
}
|
||||
match i {
|
||||
Input::Enter => self.inner = Some(Box::new(super::inquiry::DistM::default())),
|
||||
Input::Keyword(k) => match k.as_str() {
|
||||
"Radius" => self.radius = true,
|
||||
"ARea" => self.inner = Some(Box::new(super::inquiry::AreaM::default())),
|
||||
_ => self.inner = Some(Box::new(super::inquiry::DistM::default())),
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
Ok(Step::Continue)
|
||||
}
|
||||
fn preview(&self, s: &Session, cursor: Vec2) -> Vec<EntityKind> {
|
||||
self.inner.as_ref().map(|m| m.preview(s, cursor)).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -66,3 +66,17 @@ fn area_of_an_open_elliptical_arc_is_refused_and_a_full_ellipse_is_measured() {
|
||||
assert!(has(&log, "no area"), "{log:?}");
|
||||
assert!(!has(&log, "Area = "), "{log:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn measuregeom_typed_asks_for_the_option_then_the_points() {
|
||||
// Distance is the default option (#1103: typed, it used to fail asking for `p1`).
|
||||
let (s, log) = run(&["measuregeom", "", "0,0", "3,4"]);
|
||||
assert!(has(&log, "Distance = 5.0000"), "{log:?}");
|
||||
assert!(s.running.is_none(), "{}", s.prompt_text());
|
||||
|
||||
let (_, log) = run(&["circle 0,0 2", "measuregeom", "r", "2,0"]);
|
||||
assert!(has(&log, "Radius = 2.0000"), "{log:?}");
|
||||
|
||||
let (_, log) = run(&["measuregeom", "ar", "0,0", "4,0", "4,3", ""]);
|
||||
assert!(has(&log, "Area = 6.0000"), "{log:?}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user