cad-editor/src/modules/annotate/aligned_dim.rs

320 lines
11 KiB
Rust
Raw Normal View History

// DIMALIGNED command — aligned dimension (measures true distance between two points).
use acadrust::entities::{Dimension, DimensionAligned};
use acadrust::types::Vector3;
use acadrust::EntityType;
use glam::DVec3;
use crate::command::{CadCommand, CmdResult, WorkingPlane};
use crate::modules::{IconKind, ModuleEvent, ToolDef};
use crate::scene::model::wire_model::WireModel;
2026-08-02 22:09:25 +03:00
use crate::t;
pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/dim_aligned.svg"));
pub fn tool() -> ToolDef {
ToolDef {
id: "DIMALIGNED",
label: "Aligned",
icon: ICON,
event: ModuleEvent::Command("DIMALIGNED".to_string()),
}
}
enum Step {
First,
Second(DVec3),
DimLine { p1: DVec3, p2: DVec3 },
}
pub struct AlignedDimensionCommand {
step: Step,
plane: WorkingPlane,
feat(commands): integrate standard CAD commands and fix behavior gaps Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
/// Optional text that replaces the measured value (None = measurement).
text_override: Option<String>,
/// True while the next typed line is captured as the text override.
awaiting_text: bool,
/// Explicit text rotation in radians (None = follow the UCS/style).
text_angle: Option<f64>,
/// True while the next typed value is captured as the text angle.
awaiting_angle: bool,
}
impl AlignedDimensionCommand {
pub fn new() -> Self {
feat(commands): integrate standard CAD commands and fix behavior gaps Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
Self {
step: Step::First,
plane: WorkingPlane::default(),
feat(commands): integrate standard CAD commands and fix behavior gaps Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
text_override: None,
awaiting_text: false,
text_angle: None,
awaiting_angle: false,
}
}
}
impl CadCommand for AlignedDimensionCommand {
fn set_working_plane(&mut self, plane: WorkingPlane) {
self.plane = plane;
}
2026-05-12 10:36:15 +03:00
fn name(&self) -> &'static str {
"DIMALIGNED"
}
fn prompt(&self) -> String {
feat(commands): integrate standard CAD commands and fix behavior gaps Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
if self.awaiting_text {
2026-08-02 22:09:25 +03:00
return t!("DIMALIGNED Enter dimension text (blank = measured value):").into_owned();
feat(commands): integrate standard CAD commands and fix behavior gaps Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
}
if self.awaiting_angle {
2026-08-02 22:09:25 +03:00
return t!("DIMALIGNED Specify text angle (degrees):").into_owned();
feat(commands): integrate standard CAD commands and fix behavior gaps Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
}
match self.step {
2026-08-02 22:09:25 +03:00
Step::First => t!("DIMALIGNED Specify first extension line origin:").into_owned(),
feat(commands): integrate standard CAD commands and fix behavior gaps Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
Step::Second(_) => {
2026-08-02 22:09:25 +03:00
t!("DIMALIGNED Specify second extension line origin [Text/Angle]:").into_owned()
feat(commands): integrate standard CAD commands and fix behavior gaps Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
}
Step::DimLine { .. } => {
2026-08-02 22:09:25 +03:00
t!("DIMALIGNED Specify dimension line location [Text/Angle]:").into_owned()
feat(commands): integrate standard CAD commands and fix behavior gaps Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
}
}
}
fn on_point(&mut self, pt: DVec3) -> CmdResult {
match self.step {
Step::First => {
self.step = Step::Second(pt);
CmdResult::NeedPoint
}
Step::Second(p1) => {
self.step = Step::DimLine { p1, p2: pt };
CmdResult::NeedPoint
}
Step::DimLine { p1, p2 } => {
let p1 = self.plane.to_local(p1);
let p2 = self.plane.to_local(p2);
let pt = self.plane.to_local(pt);
let mut dim = DimensionAligned::new(v3(p1), v3(p2));
// The dimension line runs through the cursor: store it as the
// definition point and let the renderer project it onto the
// line perpendicular (same as the preview and DIMLINEAR).
//
// The old path called `set_offset` with the straight-line
// p2→cursor *distance*, which `set_offset` then re-applies along
// the line perpendicular — placing the line at the wrong
// perpendicular distance and always on the +perp side, so it
// never matched the preview the user was dragging. (#150)
dim.definition_point = v3(pt);
dim.base.definition_point = v3(pt);
let (d1, d2) = dim_line_endpoints(p1, p2, pt);
dim.base.text_middle_point = v3((d1 + d2) * 0.5);
dim.base.insertion_point = dim.base.text_middle_point;
dim.base.actual_measurement = dim.measurement();
feat(commands): integrate standard CAD commands and fix behavior gaps Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
dim.base.user_text = self.text_override.clone();
// An explicit text angle overrides the default rotation.
if let Some(a) = self.text_angle {
dim.base.text_rotation = a;
}
CmdResult::CommitAndExit(self.plane.place_entity(EntityType::Dimension(
Dimension::Aligned(dim),
)))
}
}
}
2026-05-12 10:36:15 +03:00
fn on_enter(&mut self) -> CmdResult {
feat(commands): integrate standard CAD commands and fix behavior gaps Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
// A bare Enter while entering override text/angle accepts the default.
if self.awaiting_text {
self.awaiting_text = false;
return CmdResult::NeedPoint;
}
if self.awaiting_angle {
self.awaiting_angle = false;
return CmdResult::NeedPoint;
}
2026-05-12 10:36:15 +03:00
CmdResult::Cancel
}
feat(commands): integrate standard CAD commands and fix behavior gaps Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
fn wants_text_input(&self) -> bool {
true
}
fn point_step_accepts_keywords(&self) -> bool {
// While entering the override text or angle it is a value, not a point
// step.
!self.awaiting_text && !self.awaiting_angle
}
fn wants_text_with_spaces(&self) -> bool {
// The override text may contain spaces.
self.awaiting_text
}
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
if self.awaiting_text {
let t = text.trim();
// Blank (or the "<>" placeholder) keeps the measured value.
self.text_override = if t.is_empty() || t == "<>" {
None
} else {
Some(t.to_string())
};
self.awaiting_text = false;
return Some(CmdResult::NeedPoint);
}
if self.awaiting_angle {
let t = text.trim();
// Blank clears any explicit angle (follow the default again).
self.text_angle = if t.is_empty() {
None
} else {
feat(units): read back every form the drawing writes The readout learned to write lengths as 5'-6 1/2" and angles as N 45d0'0" E, but typed input was still a bare parse::<f64>() — a coordinate could be displayed and not entered. Give the formatters their inverses. parse_length takes feet and inches separated by a dash, a space, or nothing, with the closing quote optional, and whole-plus-fraction in any of those forms: 5', 60", 5'-9", 5'9-1/2, 9-1/2, 1/2. A leading minus is a sign; the one inside 5'-9" is a separator, since after feet there is nothing left to subtract from. parse_angle reads the mark that says which convention an angle is in — g for grads, r for radians, d/'/" for degrees-minutes-seconds, compass letters for a surveyor's bearing — and reads a bare number in whichever convention the drawing is set to. ANGBASE and ANGDIR now apply, but only where they mean something. Which way a thing points is measured from the drawing's zero and runs the way it says; how wide an arc opens is the same number whatever zero is counted from. format_direction and parse_direction are the pair for directions, and the polar readout and polar input both go through them, so the bearing shown is the bearing accepted. format_angle stays for sizes, where applying a base angle would corrupt the value. The command prompts follow the same rule, each classified rather than swept: OFFSET distance, FILLET radius, CHAMFER distances, ARRAY and MINSERT spacing, TRACE width, HELIX, and EXTRUDE height read lengths; the four dimension text-rotation prompts, ARRAY's total angle and INSERT's rotation read angles. MLINE's scale and INSERT's scale factor are left alone — a multiplier has no unit to be written in. INSERT read both through one parse; they are now separate. The typed variants also take a decimal comma, which a single-value prompt has no other use for. parse_length itself does not: inside a coordinate the comma separates the axes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 23:46:49 +03:00
crate::entities::common::parse_typed_angle(t)
feat(commands): integrate standard CAD commands and fix behavior gaps Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:27:35 +03:00
};
self.awaiting_angle = false;
return Some(CmdResult::NeedPoint);
}
match text.trim().to_uppercase().as_str() {
"T" | "TEXT" | "M" | "MTEXT" => {
self.awaiting_text = true;
Some(CmdResult::NeedPoint)
}
"A" | "ANGLE" => {
self.awaiting_angle = true;
Some(CmdResult::NeedPoint)
}
_ => None,
}
}
fn on_mouse_move(&mut self, pt: DVec3) -> Option<WireModel> {
let (p1, p2) = match self.step {
Step::First => return None,
Step::Second(p1) => (p1, pt),
Step::DimLine { p1, p2 } => {
let p1 = self.plane.to_local(p1);
let p2 = self.plane.to_local(p2);
let pt = self.plane.to_local(pt);
let mut preview = preview_aligned(p1, p2, pt);
preview.points = preview
.points
.iter()
.map(|point| {
if point[0].is_nan() {
*point
} else {
self.plane
.to_world(DVec3::new(
point[0] as f64,
point[1] as f64,
point[2] as f64,
))
.as_vec3()
.to_array()
}
})
.collect();
return Some(preview);
}
};
// Preview WireModel points are screen/GPU-side: downcast to f32.
let p1 = p1.as_vec3();
let p2 = p2.as_vec3();
Some(WireModel {
taper_widths: Vec::new(),
world_width: 0.0,
depth_override: None,
fill_is_3d: false,
fill_is_2d_solid: false,
render_instance: None,
fix(pick): hit-test lineweight width and thickness walls Selection tested a flat 8 px radius around each wire's centreline and nothing else, so two things the user can see were not pickable. A wire renders as a band `line_weight_px` wide, so pick now widens to that rendered half-width via `pick_tolerance_px`, mirroring the wire shader's `select(0.5, half_width, lwdisplay_enable)`. Behaviour is unchanged for every standard weight (the widest, 2.11 mm, renders 7.97 px half-width — just under the 8 px threshold); this keeps the two sides from drifting apart if the display boost in `lineweight_to_px` ever changes. Entities extruded by a DXF thickness draw their wall as four edges with nothing in between, so the interior was a hole the cursor fell through. WireModel gains `pick_tris`: triangles hit-testing treats as solid and the renderer never uploads. Kept apart from `fill_tris` because that channel reaches the GPU, and a wall that rendered shaded would change how every thickness drawing looks. Ranked below `fill_tris` — those are drawn, these are not, so where they overlap the drawn face is what the user means. Walls are dropped when a wire is projected into a floating viewport: `points` are reprojected and clipped into paper coords there, so cloned model-space triangles would hit-test at a model-scale offset. Extruded entities stay selectable by their edges, which do get projected. The wall loop runs on every hover that misses everything else, so it rejects on the wire's AABB first — an extruded circle is ~128 triangles and a drawing full of thickness would otherwise project every wall on each mouse move. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 14:58:55 +03:00
pick_tris: Vec::new(),
pick_tris_low: Vec::new(),
dash_from_start: false,
feat(mline): GPU-dash multiline elements with shared A-type alignment MLINE dashed elements were fully CPU-expanded (apply_along) — one wire per dash — to keep the parallel lines in phase. Move pure-dash elements onto the GPU dash shader and end-align every element to the multiline's centre-line so they share one interior phase. - wire_distances now accumulates arc-length from the double-single (high+low) points, so the dash phase stays precise at UTM coordinates. f32-high-only deltas quantised ~0.1 there and drifted the parallel lines apart — the original reason MLINE dashes were CPU-side. - New WireModel.dash_align_end carries a shared begin/end dash length. The shader uses it as align_end for every parallel element (the interior phase depends on align_end, not the wire's own length) while align_total stays the element's own length, so each still ends on a dash at its own endpoint. - MLINE tessellation derives that length once from the centre-line, routes pure dash/space/dot elements to the GPU pattern and text-bearing elements to apply_along. - apply_along gained an "A"-type mode (shared reference length): a solid begin/end dash and a phased interior, so its dashes — and embedded text — line up with the GPU-dashed sibling elements instead of tiling from start. Pure-dash MLINEs now cost one WireModel + pattern per element instead of N segments; single (non-MLINE) entities keep the from-start tiling unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:59:11 +03:00
dash_align_end: None,
text_verts: Vec::new(),
name: "dimaligned_preview".into(),
points: vec![[p1.x, p1.y, p1.z], [p2.x, p2.y, p2.z]],
points_low: Vec::new(),
color: WireModel::CYAN,
selected: false,
pattern_length: 0.0,
pattern: [0.0; 8],
line_weight_px: 1.0,
snap_pts: vec![],
tangent_geoms: vec![],
aci: 0,
key_vertices: vec![],
aabb: WireModel::UNBOUNDED_AABB,
plinegen: true,
fill_tris: vec![],
fill_tris_low: Vec::new(),
})
}
}
fn v3(p: DVec3) -> Vector3 {
Vector3::new(p.x, p.y, p.z)
}
/// Dimension-line endpoints: the baseline `p1`–`p2` shifted to pass through
/// the cursor's perpendicular projection. Uses the XY-plane perpendicular so
/// it matches the committed entity's renderer (and DIMLINEAR). The old
/// preview used an XZ-plane perpendicular, drawing the offset in the wrong
/// spatial direction. (#150)
fn dim_line_endpoints(p1: DVec3, p2: DVec3, dim_pt: DVec3) -> (DVec3, DVec3) {
let axis = (p2 - p1).normalize_or_zero();
let perp = DVec3::new(-axis.y, axis.x, 0.0);
let offset = (dim_pt - p1).dot(perp);
(p1 + perp * offset, p2 + perp * offset)
}
fn preview_aligned(p1: DVec3, p2: DVec3, dim_pt: DVec3) -> WireModel {
// Show ext lines + dim line.
let (d1, d2) = dim_line_endpoints(p1, p2, dim_pt);
// Preview WireModel points are screen/GPU-side: downcast to f32.
let p1 = p1.as_vec3();
let p2 = p2.as_vec3();
let d1 = d1.as_vec3();
let d2 = d2.as_vec3();
WireModel {
taper_widths: Vec::new(),
world_width: 0.0,
depth_override: None,
fill_is_3d: false,
fill_is_2d_solid: false,
render_instance: None,
fix(pick): hit-test lineweight width and thickness walls Selection tested a flat 8 px radius around each wire's centreline and nothing else, so two things the user can see were not pickable. A wire renders as a band `line_weight_px` wide, so pick now widens to that rendered half-width via `pick_tolerance_px`, mirroring the wire shader's `select(0.5, half_width, lwdisplay_enable)`. Behaviour is unchanged for every standard weight (the widest, 2.11 mm, renders 7.97 px half-width — just under the 8 px threshold); this keeps the two sides from drifting apart if the display boost in `lineweight_to_px` ever changes. Entities extruded by a DXF thickness draw their wall as four edges with nothing in between, so the interior was a hole the cursor fell through. WireModel gains `pick_tris`: triangles hit-testing treats as solid and the renderer never uploads. Kept apart from `fill_tris` because that channel reaches the GPU, and a wall that rendered shaded would change how every thickness drawing looks. Ranked below `fill_tris` — those are drawn, these are not, so where they overlap the drawn face is what the user means. Walls are dropped when a wire is projected into a floating viewport: `points` are reprojected and clipped into paper coords there, so cloned model-space triangles would hit-test at a model-scale offset. Extruded entities stay selectable by their edges, which do get projected. The wall loop runs on every hover that misses everything else, so it rejects on the wire's AABB first — an extruded circle is ~128 triangles and a drawing full of thickness would otherwise project every wall on each mouse move. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 14:58:55 +03:00
pick_tris: Vec::new(),
pick_tris_low: Vec::new(),
dash_from_start: false,
feat(mline): GPU-dash multiline elements with shared A-type alignment MLINE dashed elements were fully CPU-expanded (apply_along) — one wire per dash — to keep the parallel lines in phase. Move pure-dash elements onto the GPU dash shader and end-align every element to the multiline's centre-line so they share one interior phase. - wire_distances now accumulates arc-length from the double-single (high+low) points, so the dash phase stays precise at UTM coordinates. f32-high-only deltas quantised ~0.1 there and drifted the parallel lines apart — the original reason MLINE dashes were CPU-side. - New WireModel.dash_align_end carries a shared begin/end dash length. The shader uses it as align_end for every parallel element (the interior phase depends on align_end, not the wire's own length) while align_total stays the element's own length, so each still ends on a dash at its own endpoint. - MLINE tessellation derives that length once from the centre-line, routes pure dash/space/dot elements to the GPU pattern and text-bearing elements to apply_along. - apply_along gained an "A"-type mode (shared reference length): a solid begin/end dash and a phased interior, so its dashes — and embedded text — line up with the GPU-dashed sibling elements instead of tiling from start. Pure-dash MLINEs now cost one WireModel + pattern per element instead of N segments; single (non-MLINE) entities keep the from-start tiling unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:59:11 +03:00
dash_align_end: None,
text_verts: Vec::new(),
name: "dimaligned_preview".into(),
points: vec![
2026-05-12 10:36:15 +03:00
[p1.x, p1.y, p1.z],
[d1.x, d1.y, d1.z],
[f32::NAN, 0.0, 0.0],
2026-05-12 10:36:15 +03:00
[p2.x, p2.y, p2.z],
[d2.x, d2.y, d2.z],
[f32::NAN, 0.0, 0.0],
2026-05-12 10:36:15 +03:00
[d1.x, d1.y, d1.z],
[d2.x, d2.y, d2.z],
],
points_low: Vec::new(),
color: WireModel::CYAN,
selected: false,
pattern_length: 0.0,
pattern: [0.0; 8],
line_weight_px: 1.0,
snap_pts: vec![],
tangent_geoms: vec![],
aci: 0,
2026-05-12 10:36:15 +03:00
key_vertices: vec![],
aabb: WireModel::UNBOUNDED_AABB,
plinegen: true,
fill_tris: vec![],
fill_tris_low: Vec::new(),
}
}
// ── Autocomplete registry ─────────────────────────────────
inventory::submit!(crate::command::CommandRegistration { names: &["DIMALIGNED"] }); // AlignedDimensionCommand