forked from 1b-agent/opencadstudio-upstream
feat(block-editor): wire Linear, Polar and XY parameter placement
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.
This commit is contained in:
1 parent
cdfb4ed632
commit
6dab5a7229
16 files changed
+1378
-26
No files matched your search
@@ -0,0 +1,129 @@
|
||||
//! 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
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use crate::modules::{CadModule, IconKind, ModuleEvent, RibbonGroup, RibbonItem,
|
||||
|
||||
pub mod visibility_parameter;
|
||||
pub mod point_parameter;
|
||||
pub mod distance_parameter;
|
||||
|
||||
pub struct BlockEditorModule;
|
||||
|
||||
|
||||
@@ -27,8 +27,10 @@ impl CadCommand for VisibilityParameterCommand {
|
||||
|
||||
fn prompt(&self) -> String {
|
||||
if self.choosing_type {
|
||||
crate::t!("BPARAMETER Enter parameter type [Point/Visibility] <Visibility>:")
|
||||
.into_owned()
|
||||
crate::t!(
|
||||
"BPARAMETER Enter parameter type [Point/Linear/Polar/XY/Visibility] <Visibility>:"
|
||||
)
|
||||
.into_owned()
|
||||
} else {
|
||||
crate::t!("BPARAMETER Specify visibility parameter location:").into_owned()
|
||||
}
|
||||
@@ -38,6 +40,9 @@ impl CadCommand for VisibilityParameterCommand {
|
||||
if self.choosing_type {
|
||||
vec![
|
||||
CmdOption::new(crate::t!("Point").as_ref(), "P"),
|
||||
CmdOption::new(crate::t!("Linear").as_ref(), "L"),
|
||||
CmdOption::new(crate::t!("Polar").as_ref(), "PO"),
|
||||
CmdOption::new(crate::t!("XY").as_ref(), "XY"),
|
||||
CmdOption::new(crate::t!("Visibility").as_ref(), "V"),
|
||||
]
|
||||
} else {
|
||||
@@ -60,16 +65,17 @@ impl CadCommand for VisibilityParameterCommand {
|
||||
.to_ascii_uppercase()
|
||||
.as_str()
|
||||
{
|
||||
"L" | "LINEAR" => CmdResult::Dispatch("BPARAMETER LINEAR".into()),
|
||||
"PO" | "POLAR" => CmdResult::Dispatch("BPARAMETER POLAR".into()),
|
||||
"XY" => CmdResult::Dispatch("BPARAMETER XY".into()),
|
||||
"P" | "POINT" => CmdResult::Dispatch("BPARAMETER POINT".into()),
|
||||
"" | "V" | "VISIBILITY" => {
|
||||
self.choosing_type = false;
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
_ => CmdResult::ReportError(
|
||||
crate::t!(
|
||||
"Only Point and Visibility parameter placement is currently supported."
|
||||
)
|
||||
.into_owned(),
|
||||
crate::t!("Supported parameter types: Point, Linear, Polar, XY, Visibility.")
|
||||
.into_owned(),
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user