forked from 1b-agent/opencadstudio-upstream
Enable the three existing palette rows and BPARAMETER choices. Pick a base, endpoint and label location to create the appropriate native parameter, one end grip and its location expressions in the shared authoring graph. Render editor dimensions and labels, preserve them when reframing the block, and include them in editor extents. Reuse local undo/redo, save/discard and native DWG/DXF persistence. Reject incomplete or invalid placement without changing document data or history. This milestone implements parameter placement. Action association/evaluation, parameter property editing, alternate grip counts and parameter sets remain separate work. Validation: focused placement and palette interaction checks; Block Editor and dock regressions; native append and DWG/DXF round trips in all 17 research fixtures, preserving existing graph data and source files; app-view renders.
130 lines
3.9 KiB
Rust
130 lines
3.9 KiB
Rust
//! 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<DVec3>,
|
|
end: Option<DVec3>,
|
|
}
|
|
|
|
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<WireModel> {
|
|
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
|
|
}
|
|
}
|