forked from 1b-agent/opencadstudio-upstream
Implement associative center mark workflow
This commit is contained in:
1 parent
0ae6355c2c
commit
ff09fc7800
18 files changed
+936
-40
No files matched your search
@@ -8,22 +8,26 @@
|
||||
// `m = radius * 0.2`. Both lines are committed at once and the command ends.
|
||||
|
||||
use acadrust::types::Vector3;
|
||||
use acadrust::entities::{CenterMarkAssociation, CenterMarkSource};
|
||||
use acadrust::{EntityType, Handle, Line};
|
||||
use glam::DVec3;
|
||||
use crate::t;
|
||||
|
||||
use crate::command::{CadCommand, CmdResult};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::centerline::{
|
||||
center_measure_is_relative, resolve_center_measure, CenterLineSettings,
|
||||
};
|
||||
|
||||
// ── Ribbon definition ─────────────────────────────────────────────────────
|
||||
|
||||
#[allow(dead_code)] // ribbon definition ready for wiring; command works via the command line
|
||||
pub fn tool() -> ToolDef {
|
||||
ToolDef {
|
||||
id: "DIMCENTER",
|
||||
id: "CENTERMARK",
|
||||
label: "Center Mark",
|
||||
icon: IconKind::Svg(include_bytes!("../../../../assets/icons/line.svg")),
|
||||
event: ModuleEvent::Command("DIMCENTER".to_string()),
|
||||
event: ModuleEvent::Command("CENTERMARK".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +137,119 @@ impl CadCommand for DimCenterCommand {
|
||||
}
|
||||
}
|
||||
|
||||
/// Associative centre-mark command. Each accepted pick commits one smart mark
|
||||
/// and keeps the command active so further circular objects can be selected.
|
||||
pub struct CenterMarkCommand {
|
||||
picked: Option<EntityType>,
|
||||
settings: CenterLineSettings,
|
||||
}
|
||||
|
||||
impl CenterMarkCommand {
|
||||
pub(crate) fn new(settings: CenterLineSettings) -> Self {
|
||||
Self { picked: None, settings }
|
||||
}
|
||||
|
||||
fn build_mark(
|
||||
&self,
|
||||
source: CenterMarkSource,
|
||||
center: DVec3,
|
||||
radius: f64,
|
||||
x: DVec3,
|
||||
y: DVec3,
|
||||
) -> EntityType {
|
||||
let diameter = radius * 2.0;
|
||||
let association = CenterMarkAssociation {
|
||||
source,
|
||||
plane_origin: Vector3::new(center.x, center.y, center.z),
|
||||
plane_x: Vector3::new(x.x, x.y, x.z),
|
||||
plane_y: Vector3::new(y.x, y.y, y.z),
|
||||
center: Vector3::new(center.x, center.y, center.z),
|
||||
radius,
|
||||
cross_size: resolve_center_measure(&self.settings.cross_size, diameter, 0.1),
|
||||
cross_gap: resolve_center_measure(&self.settings.cross_gap, diameter, 0.05),
|
||||
cross_size_relative: center_measure_is_relative(&self.settings.cross_size),
|
||||
cross_gap_relative: center_measure_is_relative(&self.settings.cross_gap),
|
||||
extension_length: self.settings.extension,
|
||||
length_adjustments: [0.0; 4],
|
||||
overshoots: [0.0; 4],
|
||||
show_extensions: self.settings.mark_extensions,
|
||||
associated: true,
|
||||
};
|
||||
let mut line = Line::from_points(
|
||||
Vector3::new(center.x, center.y, center.z),
|
||||
Vector3::new(center.x, center.y, center.z),
|
||||
);
|
||||
crate::scene::centermark::update_carrier(&mut line, &association);
|
||||
EntityType::Line(line)
|
||||
}
|
||||
}
|
||||
|
||||
impl CadCommand for CenterMarkCommand {
|
||||
fn name(&self) -> &'static str { "CENTERMARK" }
|
||||
|
||||
fn prompt(&self) -> String {
|
||||
t!("CENTERMARK Select arc or circle <finish>:").into_owned()
|
||||
}
|
||||
|
||||
fn needs_entity_pick(&self) -> bool { true }
|
||||
fn inject_before_entity_pick(&self) -> bool { true }
|
||||
|
||||
fn inject_picked_entity(&mut self, entity: EntityType) {
|
||||
self.picked = Some(entity);
|
||||
}
|
||||
|
||||
fn on_entity_pick(&mut self, handle: Handle, point: DVec3) -> CmdResult {
|
||||
if handle.is_null() {
|
||||
return CmdResult::NeedPoint;
|
||||
}
|
||||
let Some((source, center, radius, x, y)) = self
|
||||
.picked
|
||||
.as_ref()
|
||||
.and_then(|entity| crate::scene::centermark::picked_mark_source(entity, handle, point))
|
||||
else {
|
||||
return CmdResult::NeedPoint;
|
||||
};
|
||||
CmdResult::CommitEntity(self.build_mark(source, center, radius, x, y))
|
||||
}
|
||||
|
||||
fn on_point(&mut self, _point: DVec3) -> CmdResult { CmdResult::NeedPoint }
|
||||
fn on_enter(&mut self) -> CmdResult { CmdResult::Cancel }
|
||||
fn on_escape(&mut self) -> CmdResult { CmdResult::Cancel }
|
||||
}
|
||||
|
||||
pub struct CenterMarkReassociateCommand {
|
||||
target: Handle,
|
||||
picked: Option<EntityType>,
|
||||
}
|
||||
|
||||
impl CenterMarkReassociateCommand {
|
||||
pub fn new(target: Handle) -> Self {
|
||||
Self { target, picked: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl CadCommand for CenterMarkReassociateCommand {
|
||||
fn name(&self) -> &'static str { "CENTERREASSOCIATE" }
|
||||
fn prompt(&self) -> String {
|
||||
t!("CENTERREASSOCIATE Select new arc or circle:").into_owned()
|
||||
}
|
||||
fn needs_entity_pick(&self) -> bool { true }
|
||||
fn inject_before_entity_pick(&self) -> bool { true }
|
||||
fn inject_picked_entity(&mut self, entity: EntityType) { self.picked = Some(entity); }
|
||||
fn on_entity_pick(&mut self, source: Handle, point: DVec3) -> CmdResult {
|
||||
let valid = self.picked.as_ref().and_then(|entity| {
|
||||
crate::scene::centermark::picked_mark_source(entity, source, point)
|
||||
}).is_some();
|
||||
if !valid {
|
||||
return CmdResult::NeedPoint;
|
||||
}
|
||||
CmdResult::ReassociateCenterMark { target: self.target, source, point }
|
||||
}
|
||||
fn on_point(&mut self, _point: DVec3) -> CmdResult { CmdResult::NeedPoint }
|
||||
fn on_enter(&mut self) -> CmdResult { CmdResult::Cancel }
|
||||
fn on_escape(&mut self) -> CmdResult { CmdResult::Cancel }
|
||||
}
|
||||
|
||||
// ── Autocomplete registry ─────────────────────────────────
|
||||
inventory::submit!(crate::command::CommandRegistration {
|
||||
names: &["DIMCENTER", "DCE", "CENTERMARK"]
|
||||
|
||||
@@ -63,6 +63,27 @@ pub fn explode_polyline_segments(entity: &EntityType) -> Vec<EntityType> {
|
||||
/// Returns an empty vec if the entity cannot be exploded.
|
||||
pub fn explode_entity(entity: &EntityType, document: &CadDocument) -> Vec<EntityType> {
|
||||
match entity {
|
||||
EntityType::Line(line) => {
|
||||
let Some(association) = acadrust::entities::CenterMarkAssociation::read(
|
||||
&line.common.extended_data,
|
||||
) else {
|
||||
return vec![];
|
||||
};
|
||||
crate::scene::centermark::mark_segments(&association)
|
||||
.into_iter()
|
||||
.map(|segment| {
|
||||
let mut common = line.common.clone();
|
||||
common.handle = Handle::NULL;
|
||||
acadrust::entities::CenterMarkAssociation::remove(&mut common.extended_data);
|
||||
EntityType::Line(LineEnt {
|
||||
common,
|
||||
start: Vector3::new(segment[0].x, segment[0].y, segment[0].z),
|
||||
end: Vector3::new(segment[1].x, segment[1].y, segment[1].z),
|
||||
..LineEnt::new()
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
EntityType::LwPolyline(p) => explode_lwpolyline(p),
|
||||
EntityType::Polyline2D(p) => explode_polyline2d(p),
|
||||
EntityType::Polyline(p) => explode_polyline(p),
|
||||
|
||||
Reference in new issue
Block a user