//! Three-pick authoring shared by Linear, Polar and XY parameters. use crate::command::{CadCommand, CmdResult}; use crate::scene::{ block_distance_parameter::{self, Kind}, WireModel, }; use codec::{types::Vector3, Handle}; use glam::DVec3; pub struct DistanceParameterCommand { document_id: u64, definition: Handle, kind: Kind, base: Option, end: Option, } impl DistanceParameterCommand { pub(crate) fn new(document_id: u64, definition: Handle, kind: Kind) -> Self { Self { document_id, definition, kind, base: None, end: None, } } } impl CadCommand for DistanceParameterCommand { fn name(&self) -> &'static str { "BPARAMETER" } fn prompt(&self) -> String { let step = if self.base.is_none() { "Specify parameter base point:" } else if self.end.is_none() { "Specify parameter endpoint:" } else { "Specify parameter label location:" }; crate::tf!( "BPARAMETER {} {}", crate::t!(self.kind.name()), crate::t!(step) ) .into_owned() } fn on_point(&mut self, point: DVec3) -> CmdResult { if !point.is_finite() { return CmdResult::ReportError( crate::t!("Specify a finite parameter location.").into_owned(), ); } let Some(base) = self.base else { self.base = Some(point); return CmdResult::NeedPoint; }; let vector = |p: DVec3| Vector3::new(p.x, p.y, p.z); if let Some(error) = block_distance_parameter::points_error( self.kind, vector(base), vector(self.end.unwrap_or(point)), vector(point), ) { return CmdResult::ReportError(crate::t!(error).into_owned()); } let Some(end) = self.end else { self.end = Some(point); return CmdResult::NeedPoint; }; CmdResult::PlaceBlockDistanceParameter { document_id: self.document_id, definition: self.definition, kind: self.kind, base, end, label: point, } } fn on_preview_wires(&mut self, point: DVec3) -> Vec { let Some(base) = self.base.filter(|_| point.is_finite()) else { return vec![]; }; let end = self.end.unwrap_or(point); let mut lines = vec![[base, end]]; if self.kind == Kind::XY { lines = vec![ [base, DVec3::new(end.x, base.y, base.z)], [base, DVec3::new(base.x, end.y, base.z)], ]; } if self.end.is_some() { if self.kind == Kind::XY { let x = DVec3::new(base.x, point.y, base.z); let y = DVec3::new(point.x, base.y, base.z); lines.extend([ [base, x], [x, DVec3::new(end.x, point.y, base.z)], [base, y], [y, DVec3::new(point.x, end.y, base.z)], ]); } else { let d = end - base; let n = DVec3::new(-d.y, d.x, 0.0).normalize_or_zero(); let offset = n * (point - base).dot(n); lines = vec![ [base, base + offset], [base + offset, end + offset], [end + offset, end], ]; } } lines .into_iter() .map(|line| { WireModel::solid_f64( "preview_distance_parameter".into(), line.into_iter().map(|point| point.to_array()).collect(), WireModel::CYAN, false, ) }) .collect() } fn on_enter(&mut self) -> CmdResult { CmdResult::Cancel } }