forked from 1b-agent/opencadstudio-upstream
fix(annotate): align annotation ribbon workflows
This commit is contained in:
1 parent
fc1788df65
commit
6505b27818
26 files changed
+1921
-345
No files matched your search
@@ -1,13 +1,10 @@
|
||||
// DIMJOGLINE command — add a jog (zigzag) symbol to a linear or aligned dimension.
|
||||
//
|
||||
// Workflow:
|
||||
// 1. Pick the dimension
|
||||
// 2. Click the position on the dimension line where the jog should appear
|
||||
// DIMJOGLINE — add or remove a jog on a linear/aligned dimension.
|
||||
|
||||
use acadrust::Handle;
|
||||
use glam::DVec3;
|
||||
use acadrust::entities::Dimension;
|
||||
use acadrust::{EntityType, Handle};
|
||||
use glam::{DVec3, Vec3};
|
||||
|
||||
use crate::command::{CadCommand, CmdResult};
|
||||
use crate::command::{CadCommand, CmdOption, CmdResult, InputKind};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
use crate::t;
|
||||
@@ -30,12 +27,76 @@ enum Step {
|
||||
|
||||
pub struct DimJogLineCommand {
|
||||
step: Step,
|
||||
remove: bool,
|
||||
picked_entity: Option<EntityType>,
|
||||
dimension: Option<Dimension>,
|
||||
}
|
||||
|
||||
impl DimJogLineCommand {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
step: Step::PickDim,
|
||||
remove: false,
|
||||
picked_entity: None,
|
||||
dimension: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn result(handle: Handle, point: Option<DVec3>) -> CmdResult {
|
||||
use acadrust::entities::XLine;
|
||||
let mut marker = XLine::default();
|
||||
marker.common.layer = match point {
|
||||
Some(point) => format!(
|
||||
"__DIMJOG__{}|{:.15},{:.15},{:.15}",
|
||||
handle.value(), point.x, point.y, point.z
|
||||
),
|
||||
None => format!("__DIMJOG_REMOVE__{}", handle.value()),
|
||||
};
|
||||
CmdResult::ReplaceEntity(handle, vec![EntityType::XLine(marker)])
|
||||
}
|
||||
|
||||
fn default_position(dimension: &Dimension) -> Option<DVec3> {
|
||||
let (first, second, definition, axis) = match dimension {
|
||||
Dimension::Linear(value) => (
|
||||
value.first_point,
|
||||
value.second_point,
|
||||
value.definition_point,
|
||||
DVec3::new(value.rotation.cos(), value.rotation.sin(), 0.0),
|
||||
),
|
||||
Dimension::Aligned(value) => {
|
||||
let first = DVec3::new(value.first_point.x, value.first_point.y, value.first_point.z);
|
||||
let second = DVec3::new(value.second_point.x, value.second_point.y, value.second_point.z);
|
||||
(
|
||||
value.first_point,
|
||||
value.second_point,
|
||||
value.definition_point,
|
||||
(second - first).try_normalize().unwrap_or(DVec3::X),
|
||||
)
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
let first = DVec3::new(first.x, first.y, first.z);
|
||||
let second = DVec3::new(second.x, second.y, second.z);
|
||||
let definition = DVec3::new(definition.x, definition.y, definition.z);
|
||||
let axis = axis.try_normalize().unwrap_or(DVec3::X);
|
||||
let perpendicular = DVec3::new(-axis.y, axis.x, 0.0);
|
||||
let offset = definition.dot(perpendicular);
|
||||
let first_on_line = first + perpendicular * (offset - first.dot(perpendicular));
|
||||
let second_on_line = second + perpendicular * (offset - second.dot(perpendicular));
|
||||
let midpoint = (first_on_line + second_on_line) * 0.5;
|
||||
|
||||
let text = dimension.base().text_middle_point;
|
||||
let text = DVec3::new(text.x, text.y, text.z);
|
||||
let line = second_on_line - first_on_line;
|
||||
let length_squared = line.length_squared();
|
||||
if length_squared <= 1.0e-18 {
|
||||
return Some(midpoint);
|
||||
}
|
||||
let parameter = (text - first_on_line).dot(line) / length_squared;
|
||||
if text.is_finite() && (0.0..=1.0).contains(¶meter) {
|
||||
Some((first_on_line + text) * 0.5)
|
||||
} else {
|
||||
Some(midpoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,90 +107,129 @@ impl CadCommand for DimJogLineCommand {
|
||||
}
|
||||
|
||||
fn prompt(&self) -> String {
|
||||
match &self.step {
|
||||
Step::PickDim => t!("DIMJOGLINE Select linear or aligned dimension:").into_owned(),
|
||||
Step::PickJogPos { .. } => t!("DIMJOGLINE Specify jog location:").into_owned(),
|
||||
match self.step {
|
||||
Step::PickDim if self.remove => {
|
||||
t!("DIMJOGLINE Select dimension to remove jog:").into_owned()
|
||||
}
|
||||
Step::PickDim => {
|
||||
t!("DIMJOGLINE Select dimension to add jog or [Remove]:").into_owned()
|
||||
}
|
||||
Step::PickJogPos { .. } => {
|
||||
t!("DIMJOGLINE Specify jog location (or press Enter):").into_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn options(&self) -> Vec<CmdOption> {
|
||||
if matches!(self.step, Step::PickDim) && !self.remove {
|
||||
vec![CmdOption::new("Remove", "REMOVE")]
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn input_kind(&self) -> InputKind {
|
||||
InputKind::Point
|
||||
}
|
||||
|
||||
fn point_step_accepts_keywords(&self) -> bool {
|
||||
matches!(self.step, Step::PickDim) && !self.remove
|
||||
}
|
||||
|
||||
fn needs_entity_pick(&self) -> bool {
|
||||
matches!(self.step, Step::PickDim)
|
||||
}
|
||||
|
||||
fn on_entity_pick(&mut self, handle: Handle, _pt: DVec3) -> CmdResult {
|
||||
fn inject_before_entity_pick(&self) -> bool {
|
||||
matches!(self.step, Step::PickDim)
|
||||
}
|
||||
|
||||
fn inject_picked_entity(&mut self, entity: EntityType) {
|
||||
self.picked_entity = Some(entity);
|
||||
}
|
||||
|
||||
fn on_entity_pick(&mut self, handle: Handle, _point: DVec3) -> CmdResult {
|
||||
let Some(EntityType::Dimension(dimension @ (Dimension::Linear(_) | Dimension::Aligned(_)))) =
|
||||
self.picked_entity.take()
|
||||
else {
|
||||
return CmdResult::ReportError(
|
||||
t!("DIMJOGLINE: select a linear or aligned dimension.").into_owned(),
|
||||
);
|
||||
};
|
||||
if handle.is_null() {
|
||||
return CmdResult::NeedPoint;
|
||||
}
|
||||
if self.remove {
|
||||
return Self::result(handle, None);
|
||||
}
|
||||
self.dimension = Some(dimension);
|
||||
self.step = Step::PickJogPos { handle };
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
|
||||
fn on_point(&mut self, pt: DVec3) -> CmdResult {
|
||||
if let Step::PickJogPos { handle } = &self.step {
|
||||
let h = *handle;
|
||||
// Emit sentinel for commands.rs to store the jog position
|
||||
use acadrust::entities::XLine;
|
||||
let mut xl = XLine::default();
|
||||
xl.common.layer = format!("__DIMJOG__{},{:.6},{:.6}", h.value(), pt.x, pt.z);
|
||||
return CmdResult::ReplaceEntity(h, vec![acadrust::EntityType::XLine(xl)]);
|
||||
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
|
||||
if matches!(self.step, Step::PickDim)
|
||||
&& matches!(text.trim().to_ascii_uppercase().as_str(), "R" | "REMOVE")
|
||||
{
|
||||
self.remove = true;
|
||||
Some(CmdResult::NeedPoint)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn on_point(&mut self, point: DVec3) -> CmdResult {
|
||||
match self.step {
|
||||
Step::PickJogPos { handle } => Self::result(handle, Some(point)),
|
||||
Step::PickDim => CmdResult::NeedPoint,
|
||||
}
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
|
||||
fn on_enter(&mut self) -> CmdResult {
|
||||
CmdResult::Cancel
|
||||
match (&self.step, &self.dimension) {
|
||||
(Step::PickJogPos { handle }, Some(dimension)) => Self::default_position(dimension)
|
||||
.map(|point| Self::result(*handle, Some(point)))
|
||||
.unwrap_or(CmdResult::Cancel),
|
||||
_ => CmdResult::Cancel,
|
||||
}
|
||||
}
|
||||
|
||||
fn on_mouse_move(&mut self, pt: DVec3) -> Option<WireModel> { let pt = pt.as_vec3();
|
||||
fn on_mouse_move(&mut self, point: DVec3) -> Option<WireModel> {
|
||||
if !matches!(self.step, Step::PickJogPos { .. }) {
|
||||
return None;
|
||||
}
|
||||
let d = 0.3_f32;
|
||||
Some(WireModel {
|
||||
bg_adapt: None,
|
||||
point_marker: None,
|
||||
taper_widths: Vec::new(),
|
||||
pattern_stations: Vec::new(),
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
render_instance: None,
|
||||
pick_tris: Vec::new(),
|
||||
pick_tris_low: Vec::new(),
|
||||
dash_from_start: false,
|
||||
dash_align_end: None,
|
||||
text_verts: Vec::new(),
|
||||
name: "dimjog_preview".into(),
|
||||
// Jog zigzag in the XY drawing plane (Z is elevation, ~0). The old
|
||||
// marker varied Z, so in the top-down view it collapsed to a flat
|
||||
// line instead of a zigzag. (#150)
|
||||
points: vec![
|
||||
[pt.x - d, pt.y, pt.z],
|
||||
[pt.x - d * 0.3, pt.y + d, pt.z],
|
||||
[pt.x + d * 0.3, pt.y - d, pt.z],
|
||||
[pt.x + d, pt.y, pt.z],
|
||||
],
|
||||
points_low: Vec::new(),
|
||||
color: WireModel::CYAN,
|
||||
selected: false,
|
||||
pattern_length: 0.0,
|
||||
pattern: [0.0; 8],
|
||||
line_weight_px: 1.2,
|
||||
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(),
|
||||
})
|
||||
let axis = self
|
||||
.dimension
|
||||
.as_ref()
|
||||
.and_then(|dimension| match dimension {
|
||||
Dimension::Linear(value) => {
|
||||
Some(Vec3::new(value.rotation.cos() as f32, value.rotation.sin() as f32, 0.0))
|
||||
}
|
||||
Dimension::Aligned(value) => Some(Vec3::new(
|
||||
(value.second_point.x - value.first_point.x) as f32,
|
||||
(value.second_point.y - value.first_point.y) as f32,
|
||||
0.0,
|
||||
)),
|
||||
_ => None,
|
||||
})
|
||||
.and_then(Vec3::try_normalize)
|
||||
.unwrap_or(Vec3::X);
|
||||
let perpendicular = Vec3::new(-axis.y, axis.x, 0.0);
|
||||
let center = point.as_vec3();
|
||||
let size = 0.3;
|
||||
let points = vec![
|
||||
center - axis * size,
|
||||
center - axis * size * 0.25 + perpendicular * size,
|
||||
center + axis * size * 0.25 - perpendicular * size,
|
||||
center + axis * size,
|
||||
];
|
||||
let mut preview = WireModel::default();
|
||||
preview.name = "dimjog_preview".into();
|
||||
preview.points = points.into_iter().map(|point| point.to_array()).collect();
|
||||
preview.color = WireModel::CYAN;
|
||||
preview.line_weight_px = 1.2;
|
||||
Some(preview)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ── Autocomplete registry ─────────────────────────────────
|
||||
inventory::submit!(crate::command::CommandRegistration { names: &["DIMJOGLINE"] }); // DimJogLineCommand
|
||||
inventory::submit!(crate::command::CommandRegistration { names: &["DIMJOGLINE"] });
|
||||
Reference in new issue
Block a user