From 3f1b236c0a1ec6b786bbb84cfb43c1e29743e7cf Mon Sep 17 00:00:00 2001 From: ramox81 <184937705+ramox81@users.noreply.github.com> Date: Fri, 25 Sep 2026 12:51:11 +0300 Subject: [PATCH] VPCLIP: chord direction and nested arc option prompts The chord direction step takes a typed angle and defaults to the last segment's direction on Enter; CEnter's Angle and Length prompts carry the direction switch hint as the reference words them. Co-Authored-By: Claude Opus 5.5 --- src/modules/layout/mview.rs | 55 ++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/src/modules/layout/mview.rs b/src/modules/layout/mview.rs index 99dffedef..e752d2574 100644 --- a/src/modules/layout/mview.rs +++ b/src/modules/layout/mview.rs @@ -211,25 +211,55 @@ impl MviewCommand { self.finish_polygon() } - fn arc_prompt(&self) -> Option<&'static str> { + /// Direction of the last segment, degrees: the chord direction default. + fn tangent_degrees(&self) -> f64 { + let t = self.polygon_last_tangent.map_or(DVec2::X, |t| t.as_dvec2()); + t.y.atan2(t.x).to_degrees().rem_euclid(360.0) + } + + /// VPCLIP chord direction (degrees) for the arc option being answered. + fn arc_chord(&mut self, degrees: f64) -> Option { + let a = self.last2()?; + let p = a + DVec2::from_angle(degrees.to_radians()); + let (e, bulge) = arc_for(self.arc_sub, a, p, self.polygon_last_tangent)?; + Some(self.push_arc(e, bulge)) + } + + fn chord_step(&self) -> bool { + matches!(self.arc_sub, Sub::ArcAngleRadiusDir { .. } | Sub::ArcRadiusAngleDir { .. }) + } + + fn arc_prompt(&self) -> Option { + if self.chord_step() { + let default = format!("{:.4}", self.tangent_degrees()); + let default = default.trim_end_matches('0').trim_end_matches('.'); + return Some(format!( + "Specify direction of chord for arc (hold Ctrl to switch direction) <{default}>:" + )); + } Some(match self.arc_sub { - Sub::ArcAngle | Sub::ArcCenterAngle { .. } | Sub::ArcRadiusAngle { .. } => "Specify included angle:", + Sub::ArcCenterAngle { .. } => "Specify included angle (hold Ctrl to switch direction):", + Sub::ArcAngle | Sub::ArcRadiusAngle { .. } => "Specify included angle:", Sub::ArcAngleEnd { .. } => "Specify endpoint of arc (hold Ctrl to switch direction) or [CEnter/Radius]:", Sub::ArcCenter | Sub::ArcAngleCenter { .. } => "Specify center point of arc:", Sub::ArcCenterEnd { .. } => "Specify endpoint of arc (hold Ctrl to switch direction) or [Angle/Length]:", - Sub::ArcCenterLength { .. } => "Specify length of chord:", + Sub::ArcCenterLength { .. } => "Specify length of chord (hold Ctrl to switch direction):", Sub::ArcDirection => "Specify the tangent direction for the start point of arc:", Sub::ArcDirectionEnd { .. } => "Specify endpoint of the arc (hold Ctrl to switch direction):", Sub::ArcRadius | Sub::ArcAngleRadius { .. } => "Specify radius of arc:", Sub::ArcRadiusEnd { .. } => "Specify endpoint of arc (hold Ctrl to switch direction) or [Angle]:", - Sub::ArcAngleRadiusDir { .. } | Sub::ArcRadiusAngleDir { .. } => "Specify direction of chord for arc:", Sub::ArcSecond => "Specify second point on arc:", Sub::ArcSecondEnd { .. } => "Specify end point of arc:", _ => return None, - }) + } + .to_string()) } fn clip_text(&mut self, upper: &str) -> Option { + if self.step == Step::Polygon && self.chord_step() { + let degrees = crate::entities::common::parse_typed_angle(upper)?.to_degrees(); + return self.arc_chord(degrees); + } if self.step == Step::Polygon && self.arc_sub != Sub::None { let next = match (self.arc_sub, upper) { (Sub::ArcAngleEnd { angle }, "CE" | "CENTER" | "CENTRE") => Sub::ArcAngleCenter { angle }, @@ -499,13 +529,17 @@ impl CadCommand for MviewCommand { } fn prompt(&self) -> String { + if self.clip.is_some() && self.step == Step::Polygon { + if let Some(prompt) = self.arc_prompt() { + return prompt; + } + } if self.clip.is_some() { return match self.step { Step::ClipSelect => "Select viewport to clip:", Step::ClipChoice => "Select clipping object or [Polygonal] :", Step::ClipLength => "Specify length of line:", Step::Polygon if self.polygon.is_empty() => "Specify start point:", - Step::Polygon if self.arc_prompt().is_some() => self.arc_prompt().unwrap_or_default(), Step::Polygon if self.polygon_mode == PolygonMode::Arc => { "Enter an arc boundary option\n[Angle/CEnter/CLose/Direction/Line/Radius/Second pt/Undo/Endpoint of arc] :" } @@ -716,6 +750,11 @@ impl CadCommand for MviewCommand { fn on_enter(&mut self) -> CmdResult { match self.step { + // The chord direction defaults to the last segment's direction. + Step::Polygon if self.chord_step() => { + let degrees = self.tangent_degrees(); + self.arc_chord(degrees).unwrap_or(CmdResult::NeedPoint) + } Step::ClipChoice => { self.step = Step::Polygon; CmdResult::NeedPoint @@ -771,7 +810,9 @@ impl CadCommand for MviewCommand { } fn input_kind(&self) -> InputKind { - if self.step == Step::ClipLength || (self.step == Step::Polygon && self.arc_sub.is_scalar()) { + if self.step == Step::ClipLength + || (self.step == Step::Polygon && (self.arc_sub.is_scalar() || self.chord_step())) + { InputKind::FreeText } else if self.step == Step::ChooseView { InputKind::FreeText