forked from 1b-agent/opencadstudio-upstream
feat(dimension): styled placement previews for creation commands
Show the styled dimension and its value while placing a dimension, using the same builder the command commits with. Each creation command (DIMLINEAR, DIMALIGNED, DIMANGULAR, DIMRADIUS, DIMDIAMETER, DIMARC, DIMJOGGED, DIMORDINATE, DIMCONTINUE, DIMBASELINE, QDIM) reports the dimensions it would commit at the current stage through `CadCommand::dimension_preview`. The application applies the current creation style, or the base dimension's style for DIMCONTINUEMODE=1, and the same viewport measurement scale as commit, then tessellates the transient entity through the normal dimension renderer. While the second definition point is being acquired, a hovered model snap supplies a provisional viewport scale; once both points are fixed, hovering another viewport does not change the value. Angular dimensions never receive length compensation. Degenerate geometry, an invalid scale, or conflicting viewports fall back to the plain rubber-band preview so no misleading value is shown.
This commit is contained in:
1 parent
ca0ee37d26
commit
acbbb23297
17 files changed
+724
-138
No files matched your search
@@ -6,7 +6,8 @@ use acadrust::EntityType;
|
||||
use glam::DVec3;
|
||||
|
||||
use crate::command::{
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, InputKind, WorkingPlane,
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, DimensionPreview, InputKind,
|
||||
WorkingPlane,
|
||||
};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
@@ -61,6 +62,29 @@ impl AlignedDimensionCommand {
|
||||
mtext_override: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_dimension(&self, first: DVec3, second: DVec3, point: DVec3) -> EntityType {
|
||||
let first = self.plane.to_local(first);
|
||||
let second = self.plane.to_local(second);
|
||||
let point = self.plane.to_local(point);
|
||||
let mut dim = DimensionAligned::new(v3(first), v3(second));
|
||||
// The placement point is stored so commit matches the preview.
|
||||
dim.definition_point = v3(point);
|
||||
dim.base.definition_point = v3(point);
|
||||
let (d1, d2) = dim_line_endpoints(first, second, point);
|
||||
dim.base.text_middle_point = v3((d1 + d2) * 0.5);
|
||||
dim.base.insertion_point = dim.base.text_middle_point;
|
||||
dim.base.actual_measurement = dim.measurement();
|
||||
crate::entities::dimension::set_dimension_text_override(
|
||||
&mut dim.base,
|
||||
self.text_override.clone(),
|
||||
);
|
||||
// An explicit text angle overrides the default rotation.
|
||||
if let Some(angle) = self.text_angle {
|
||||
dim.base.text_rotation = angle;
|
||||
}
|
||||
self.plane.place_entity(EntityType::Dimension(Dimension::Aligned(dim)))
|
||||
}
|
||||
}
|
||||
|
||||
impl CadCommand for AlignedDimensionCommand {
|
||||
@@ -115,27 +139,8 @@ impl CadCommand for AlignedDimensionCommand {
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
Step::DimLine { p1, p2 } => {
|
||||
let p1 = self.plane.to_local(p1);
|
||||
let p2 = self.plane.to_local(p2);
|
||||
let pt = self.plane.to_local(pt);
|
||||
let mut dim = DimensionAligned::new(v3(p1), v3(p2));
|
||||
// Store the cursor position so commit matches the preview.
|
||||
dim.definition_point = v3(pt);
|
||||
dim.base.definition_point = v3(pt);
|
||||
let (d1, d2) = dim_line_endpoints(p1, p2, pt);
|
||||
dim.base.text_middle_point = v3((d1 + d2) * 0.5);
|
||||
dim.base.insertion_point = dim.base.text_middle_point;
|
||||
dim.base.actual_measurement = dim.measurement();
|
||||
crate::entities::dimension::set_dimension_text_override(
|
||||
&mut dim.base,
|
||||
self.text_override.clone(),
|
||||
);
|
||||
// An explicit text angle overrides the default rotation.
|
||||
if let Some(a) = self.text_angle {
|
||||
dim.base.text_rotation = a;
|
||||
}
|
||||
CmdResult::CommitDimension {
|
||||
entity: self.plane.place_entity(EntityType::Dimension(Dimension::Aligned(dim))),
|
||||
entity: self.build_dimension(p1, p2, pt),
|
||||
association: DimensionAssociationInput::Infer(self.source_handle),
|
||||
preserve_base_style: false,
|
||||
continue_command: false,
|
||||
@@ -351,6 +356,23 @@ impl CadCommand for AlignedDimensionCommand {
|
||||
fill_tris_low: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn dimension_preview(&self, cursor: DVec3) -> Option<Vec<DimensionPreview>> {
|
||||
if self.selecting_object {
|
||||
return None;
|
||||
}
|
||||
let (first, second) = match self.step {
|
||||
Step::First => return None,
|
||||
Step::Second(first) => (first, cursor),
|
||||
Step::DimLine { p1, p2 } => (p1, p2),
|
||||
};
|
||||
if first.distance_squared(second) <= 1e-24 {
|
||||
return Some(Vec::new());
|
||||
}
|
||||
Some(vec![DimensionPreview::current_style(
|
||||
self.build_dimension(first, second, cursor),
|
||||
)])
|
||||
}
|
||||
}
|
||||
|
||||
fn v3(p: DVec3) -> Vector3 {
|
||||
|
||||
@@ -7,8 +7,8 @@ use cadkernel::geom2d::{
|
||||
};
|
||||
|
||||
use crate::command::{
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput,
|
||||
DimensionAssociationSource, InputKind, WorkingPlane,
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, DimensionAssociationSource,
|
||||
DimensionPreview, InputKind, WorkingPlane,
|
||||
};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
@@ -807,6 +807,32 @@ impl CadCommand for AngularDimensionCommand {
|
||||
};
|
||||
Some(preview_wire(points))
|
||||
}
|
||||
|
||||
fn dimension_preview(&self, cursor: DVec3) -> Option<Vec<DimensionPreview>> {
|
||||
if self.selecting_object {
|
||||
return None;
|
||||
}
|
||||
let result = match self.step {
|
||||
Step::ArcPoint3 {
|
||||
vertex,
|
||||
first,
|
||||
second,
|
||||
} => self.finish_three_point(vertex, first, second, cursor),
|
||||
Step::ArcPoint2 {
|
||||
first_start,
|
||||
first_end,
|
||||
second_start,
|
||||
second_end,
|
||||
} => self.finish_two_line(first_start, first_end, second_start, second_end, cursor),
|
||||
_ => return None,
|
||||
};
|
||||
match result {
|
||||
CmdResult::CommitDimension { entity, .. } => {
|
||||
Some(vec![DimensionPreview::current_style(entity)])
|
||||
}
|
||||
_ => Some(Vec::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn picked_curve(entity: &EntityType, click: DVec3) -> Option<PickedCurve> {
|
||||
|
||||
@@ -5,8 +5,8 @@ use cadkernel::geom2d::tessellate::{arc, DEFAULT_SEGMENTS_PER_RADIAN};
|
||||
use glam::DVec3;
|
||||
|
||||
use crate::command::{
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput,
|
||||
DimensionAssociationSource, InputKind, WorkingPlane,
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, DimensionAssociationSource,
|
||||
DimensionPreview, InputKind, WorkingPlane,
|
||||
};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::dimension_assoc::{
|
||||
@@ -516,6 +516,18 @@ impl CadCommand for ArcLengthDimensionCommand {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn dimension_preview(&self, cursor: DVec3) -> Option<Vec<DimensionPreview>> {
|
||||
let Step::DimLine(selection) = self.step else {
|
||||
return None;
|
||||
};
|
||||
match self.commit_dimension(selection, cursor) {
|
||||
CmdResult::CommitDimension { entity, .. } => {
|
||||
Some(vec![DimensionPreview::current_style(entity)])
|
||||
}
|
||||
_ => Some(Vec::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn positive_sweep(start: f64, end: f64) -> f64 {
|
||||
|
||||
@@ -4,7 +4,8 @@ use acadrust::EntityType;
|
||||
use glam::{DVec3, Vec3};
|
||||
|
||||
use crate::command::{
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, InputKind, WorkingPlane,
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, DimensionPreview, InputKind,
|
||||
WorkingPlane,
|
||||
};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
@@ -55,6 +56,35 @@ impl DiameterDimensionCommand {
|
||||
Step::DimLine(source) => dvec(source.point_at_angle(source.start_angle)),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_dimension(
|
||||
&self,
|
||||
source: crate::scene::dimension_assoc::RadialSourceGeometry,
|
||||
world: DVec3,
|
||||
) -> EntityType {
|
||||
let plane = WorkingPlane::new(
|
||||
DVec3::from_array(source.plane.origin),
|
||||
DVec3::from_array(source.plane.x_axis),
|
||||
DVec3::from_array(source.plane.y_axis),
|
||||
);
|
||||
let chord = plane.to_local(dvec(source.chord_at(world.to_array())));
|
||||
let far_chord = plane.to_local(dvec(source.opposite_chord_at(world.to_array())));
|
||||
let point = plane.to_local(world);
|
||||
let mut dim = DimensionDiameter::new(v3(chord), v3(far_chord));
|
||||
dim.base.text_middle_point = v3(point);
|
||||
dim.base.insertion_point = v3(point);
|
||||
dim.base.text_user_positioned = true;
|
||||
dim.leader_length = chord.distance(point);
|
||||
dim.base.actual_measurement = dim.measurement();
|
||||
crate::entities::dimension::set_dimension_text_override(
|
||||
&mut dim.base,
|
||||
self.text_override.clone(),
|
||||
);
|
||||
if let Some(angle) = self.text_angle {
|
||||
dim.base.text_rotation = angle;
|
||||
}
|
||||
plane.place_entity(EntityType::Dimension(Dimension::Diameter(dim)))
|
||||
}
|
||||
}
|
||||
|
||||
impl CadCommand for DiameterDimensionCommand {
|
||||
@@ -88,30 +118,8 @@ impl CadCommand for DiameterDimensionCommand {
|
||||
match self.step {
|
||||
Step::SelectObject => CmdResult::NeedPoint,
|
||||
Step::DimLine(source) => {
|
||||
let source_plane = WorkingPlane::new(
|
||||
DVec3::from_array(source.plane.origin),
|
||||
DVec3::from_array(source.plane.x_axis),
|
||||
DVec3::from_array(source.plane.y_axis),
|
||||
);
|
||||
let chord = source_plane.to_local(dvec(source.chord_at(pt.to_array())));
|
||||
let far_chord = source_plane.to_local(dvec(source.opposite_chord_at(pt.to_array())));
|
||||
let pt = source_plane.to_local(pt);
|
||||
let mut dim = DimensionDiameter::new(v3(chord), v3(far_chord));
|
||||
dim.base.text_middle_point = v3(pt);
|
||||
dim.base.insertion_point = v3(pt);
|
||||
dim.base.text_user_positioned = true;
|
||||
dim.leader_length = chord.distance(pt);
|
||||
dim.base.actual_measurement = dim.measurement();
|
||||
crate::entities::dimension::set_dimension_text_override(
|
||||
&mut dim.base,
|
||||
self.text_override.clone(),
|
||||
);
|
||||
if let Some(a) = self.text_angle {
|
||||
dim.base.text_rotation = a;
|
||||
}
|
||||
CmdResult::CommitDimension {
|
||||
entity: source_plane
|
||||
.place_entity(EntityType::Dimension(Dimension::Diameter(dim))),
|
||||
entity: self.build_dimension(source, pt),
|
||||
association: DimensionAssociationInput::Infer(self.source_handle),
|
||||
preserve_base_style: false,
|
||||
continue_command: false,
|
||||
@@ -278,6 +286,13 @@ impl CadCommand for DiameterDimensionCommand {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn dimension_preview(&self, cursor: DVec3) -> Option<Vec<DimensionPreview>> {
|
||||
let Step::DimLine(source) = self.step else {
|
||||
return None;
|
||||
};
|
||||
Some(vec![DimensionPreview::current_style(self.build_dimension(source, cursor))])
|
||||
}
|
||||
}
|
||||
|
||||
fn v3(p: DVec3) -> Vector3 {
|
||||
|
||||
@@ -13,7 +13,9 @@ use cadkernel::geom2d::{
|
||||
use cadkernel::space::Plane;
|
||||
use glam::DVec3;
|
||||
|
||||
use crate::command::{CadCommand, CmdOption, CmdResult, DimensionAssociationInput};
|
||||
use crate::command::{
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, DimensionPreview,
|
||||
};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
|
||||
@@ -482,6 +484,16 @@ impl CadCommand for DimBaselineCommand {
|
||||
self.build_dimension(point)
|
||||
.map(|dimension| preview_for_dimension(&dimension))
|
||||
}
|
||||
|
||||
fn dimension_preview(&self, cursor: DVec3) -> Option<Vec<DimensionPreview>> {
|
||||
self.build_dimension(cursor)
|
||||
.map(|dimension| {
|
||||
vec![DimensionPreview {
|
||||
entity: EntityType::Dimension(dimension),
|
||||
preserve_base_style: self.preserve_base_style,
|
||||
}]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn linear_base(
|
||||
|
||||
@@ -11,7 +11,9 @@ use cadkernel::geom2d::{
|
||||
use cadkernel::space::Plane;
|
||||
use glam::DVec3;
|
||||
|
||||
use crate::command::{CadCommand, CmdOption, CmdResult, DimensionAssociationInput};
|
||||
use crate::command::{
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, DimensionPreview,
|
||||
};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
|
||||
@@ -423,6 +425,16 @@ impl CadCommand for DimContinueCommand {
|
||||
self.build_dimension(point)
|
||||
.map(|dimension| preview_for_dimension(&dimension))
|
||||
}
|
||||
|
||||
fn dimension_preview(&self, cursor: DVec3) -> Option<Vec<DimensionPreview>> {
|
||||
self.build_dimension(cursor)
|
||||
.map(|dimension| {
|
||||
vec![DimensionPreview {
|
||||
entity: EntityType::Dimension(dimension),
|
||||
preserve_base_style: self.preserve_base_style,
|
||||
}]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn build_linear(
|
||||
|
||||
@@ -5,7 +5,7 @@ use glam::{DVec3, Vec3};
|
||||
|
||||
use crate::command::{
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, DimensionAssociationSource,
|
||||
InputKind, WorkingPlane,
|
||||
DimensionPreview, InputKind, WorkingPlane,
|
||||
};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::creation_style::DimensionCreationDefaults;
|
||||
@@ -390,6 +390,35 @@ impl CadCommand for JoggedRadiusDimensionCommand {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn dimension_preview(&self, cursor: DVec3) -> Option<Vec<DimensionPreview>> {
|
||||
let result = match self.step {
|
||||
Step::DimLine {
|
||||
source,
|
||||
override_center,
|
||||
} => {
|
||||
// The jog is not chosen yet; preview it midway along the
|
||||
// dimension line so the styled value is visible while the
|
||||
// text position is placed.
|
||||
let chord = dvec(source.chord_at(cursor.to_array()));
|
||||
let jog = (override_center + chord) * 0.5;
|
||||
self.commit_dimension(source, override_center, chord, cursor, jog)
|
||||
}
|
||||
Step::Jog {
|
||||
source,
|
||||
override_center,
|
||||
chord,
|
||||
text_position,
|
||||
} => self.commit_dimension(source, override_center, chord, text_position, cursor),
|
||||
_ => return None,
|
||||
};
|
||||
match result {
|
||||
CmdResult::CommitDimension { entity, .. } => {
|
||||
Some(vec![DimensionPreview::current_style(entity)])
|
||||
}
|
||||
_ => Some(Vec::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn source_plane(source: RadialSourceGeometry) -> WorkingPlane {
|
||||
|
||||
@@ -6,7 +6,8 @@ use cadkernel::geom2d::{
|
||||
};
|
||||
|
||||
use crate::command::{
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, InputKind, WorkingPlane,
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, DimensionPreview, InputKind,
|
||||
WorkingPlane,
|
||||
};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
@@ -107,6 +108,29 @@ impl LinearDimensionCommand {
|
||||
mtext_override: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_dimension(&self, first: DVec3, second: DVec3, point: DVec3) -> EntityType {
|
||||
let first = self.plane.to_local(first);
|
||||
let second = self.plane.to_local(second);
|
||||
let point = self.plane.to_local(point);
|
||||
let mut dim = DimensionLinear::new(v3(first), v3(second));
|
||||
let axis = self.axis_mode.axis(first, second, point);
|
||||
dim.rotation = axis.y.atan2(axis.x);
|
||||
dim.set_offset(dimension_line_offset(second, point, axis));
|
||||
dim.base.definition_point = dim.definition_point;
|
||||
dim.base.text_middle_point = v3(linear_text_pos(first, second, point, axis));
|
||||
dim.base.insertion_point = dim.base.text_middle_point;
|
||||
dim.base.actual_measurement = dim.measurement();
|
||||
crate::entities::dimension::set_dimension_text_override(
|
||||
&mut dim.base,
|
||||
self.text_override.clone(),
|
||||
);
|
||||
// An explicit text angle overrides the UCS-derived rotation.
|
||||
if let Some(angle) = self.text_angle {
|
||||
dim.base.text_rotation = angle;
|
||||
}
|
||||
self.plane.place_entity(EntityType::Dimension(Dimension::Linear(dim)))
|
||||
}
|
||||
}
|
||||
|
||||
impl CadCommand for LinearDimensionCommand {
|
||||
@@ -164,28 +188,7 @@ impl CadCommand for LinearDimensionCommand {
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
Step::DimensionLine { first, second } => {
|
||||
let first = self.plane.to_local(first);
|
||||
let second = self.plane.to_local(second);
|
||||
let pt = self.plane.to_local(pt);
|
||||
let mut dim = DimensionLinear::new(v3(first), v3(second));
|
||||
let axis = self.axis_mode.axis(first, second, pt);
|
||||
dim.rotation = axis.y.atan2(axis.x);
|
||||
dim.set_offset(dimension_line_offset(second, pt, axis));
|
||||
dim.base.definition_point = dim.definition_point;
|
||||
dim.base.text_middle_point = v3(linear_text_pos(first, second, pt, axis));
|
||||
dim.base.insertion_point = dim.base.text_middle_point;
|
||||
dim.base.actual_measurement = dim.measurement();
|
||||
crate::entities::dimension::set_dimension_text_override(
|
||||
&mut dim.base,
|
||||
self.text_override.clone(),
|
||||
);
|
||||
// An explicit text angle overrides the UCS-derived rotation.
|
||||
if let Some(a) = self.text_angle {
|
||||
dim.base.text_rotation = a;
|
||||
}
|
||||
let entity = self.plane.place_entity(EntityType::Dimension(
|
||||
Dimension::Linear(dim),
|
||||
));
|
||||
let entity = self.build_dimension(first, second, pt);
|
||||
CmdResult::CommitDimension {
|
||||
entity,
|
||||
association: DimensionAssociationInput::Infer(self.source_handle),
|
||||
@@ -386,6 +389,23 @@ impl CadCommand for LinearDimensionCommand {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn dimension_preview(&self, cursor: DVec3) -> Option<Vec<DimensionPreview>> {
|
||||
if self.selecting_object {
|
||||
return None;
|
||||
}
|
||||
let (first, second) = match self.step {
|
||||
Step::FirstPoint => return None,
|
||||
Step::SecondPoint(first) => (first, cursor),
|
||||
Step::DimensionLine { first, second } => (first, second),
|
||||
};
|
||||
if first.distance_squared(second) <= 1e-24 {
|
||||
return Some(Vec::new());
|
||||
}
|
||||
Some(vec![DimensionPreview::current_style(
|
||||
self.build_dimension(first, second, cursor),
|
||||
)])
|
||||
}
|
||||
}
|
||||
|
||||
fn v3(pt: DVec3) -> Vector3 {
|
||||
|
||||
@@ -4,7 +4,8 @@ use acadrust::EntityType;
|
||||
use glam::{DVec3, Vec3};
|
||||
|
||||
use crate::command::{
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, InputKind, WorkingPlane,
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, DimensionPreview, InputKind,
|
||||
WorkingPlane,
|
||||
};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
@@ -60,6 +61,26 @@ impl OrdinateDimCommand {
|
||||
Step::LeaderEndpoint { feature } => feature,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_dimension(&self, feature: DVec3, point: DVec3) -> EntityType {
|
||||
let feature = self.plane.to_local(feature);
|
||||
let point = self.plane.to_local(point);
|
||||
let is_x = match self.datum_mode {
|
||||
DatumMode::Automatic => is_x_type(feature, point),
|
||||
DatumMode::X => true,
|
||||
DatumMode::Y => false,
|
||||
};
|
||||
let mut dim = DimensionOrdinate::new(v3(feature), v3(point), is_x);
|
||||
crate::entities::dimension::set_dimension_text_override(
|
||||
&mut dim.base,
|
||||
self.text_override.clone(),
|
||||
);
|
||||
if let Some(angle) = self.text_angle {
|
||||
dim.base.text_rotation = angle;
|
||||
}
|
||||
dim.refresh_measurement();
|
||||
self.plane.place_entity(EntityType::Dimension(Dimension::Ordinate(dim)))
|
||||
}
|
||||
}
|
||||
|
||||
impl CadCommand for OrdinateDimCommand {
|
||||
@@ -95,26 +116,8 @@ impl CadCommand for OrdinateDimCommand {
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
Step::LeaderEndpoint { feature } => {
|
||||
let feature = self.plane.to_local(feature);
|
||||
let pt = self.plane.to_local(pt);
|
||||
let is_x = match self.datum_mode {
|
||||
DatumMode::Automatic => is_x_type(feature, pt),
|
||||
DatumMode::X => true,
|
||||
DatumMode::Y => false,
|
||||
};
|
||||
let mut dim = DimensionOrdinate::new(v3(feature), v3(pt), is_x);
|
||||
crate::entities::dimension::set_dimension_text_override(
|
||||
&mut dim.base,
|
||||
self.text_override.clone(),
|
||||
);
|
||||
if let Some(angle) = self.text_angle {
|
||||
dim.base.text_rotation = angle;
|
||||
}
|
||||
dim.refresh_measurement();
|
||||
CmdResult::CommitDimension {
|
||||
entity: self.plane.place_entity(EntityType::Dimension(
|
||||
Dimension::Ordinate(dim),
|
||||
)),
|
||||
entity: self.build_dimension(feature, pt),
|
||||
association: DimensionAssociationInput::Infer(None),
|
||||
preserve_base_style: false,
|
||||
continue_command: false,
|
||||
@@ -258,6 +261,13 @@ impl CadCommand for OrdinateDimCommand {
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
|
||||
fn dimension_preview(&self, cursor: DVec3) -> Option<Vec<DimensionPreview>> {
|
||||
let Step::LeaderEndpoint { feature } = self.step else {
|
||||
return None;
|
||||
};
|
||||
Some(vec![DimensionPreview::current_style(self.build_dimension(feature, cursor))])
|
||||
}
|
||||
}
|
||||
|
||||
fn v3(p: DVec3) -> Vector3 {
|
||||
|
||||
@@ -8,7 +8,7 @@ use glam::DVec3;
|
||||
|
||||
use crate::command::{
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, DimensionAssociationSource,
|
||||
EntityTransform, SelectionEntity, WorkingPlane,
|
||||
DimensionPreview, EntityTransform, SelectionEntity, WorkingPlane,
|
||||
};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
@@ -364,6 +364,15 @@ impl CadCommand for QdimCommand {
|
||||
}
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn dimension_preview(&self, cursor: DVec3) -> Option<Vec<DimensionPreview>> {
|
||||
(self.step == Step::Place).then(|| {
|
||||
self.build_dimensions(cursor)
|
||||
.into_iter()
|
||||
.map(|(entity, _)| DimensionPreview::current_style(entity))
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn v3(point: DVec3) -> Vector3 { Vector3::new(point.x, point.y, point.z) }
|
||||
|
||||
@@ -3,7 +3,8 @@ use acadrust::types::{Handle, Vector3};
|
||||
use acadrust::EntityType;
|
||||
|
||||
use crate::command::{
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, InputKind, WorkingPlane,
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, DimensionPreview, InputKind,
|
||||
WorkingPlane,
|
||||
};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
@@ -55,6 +56,36 @@ impl RadiusDimensionCommand {
|
||||
Step::DimLine(source) => dvec(source.point_at_angle(source.start_angle)),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_dimension(
|
||||
&self,
|
||||
source: crate::scene::dimension_assoc::RadialSourceGeometry,
|
||||
world: DVec3,
|
||||
) -> EntityType {
|
||||
let plane = WorkingPlane::new(
|
||||
DVec3::from_array(source.plane.origin),
|
||||
DVec3::from_array(source.plane.x_axis),
|
||||
DVec3::from_array(source.plane.y_axis),
|
||||
);
|
||||
let center = plane.to_local(dvec(source.center_world()));
|
||||
let chord = plane.to_local(dvec(source.chord_at(world.to_array())));
|
||||
let point = plane.to_local(world);
|
||||
let mut dim = DimensionRadius::new(v3(center), v3(chord));
|
||||
dim.base.definition_point = v3(chord);
|
||||
dim.base.text_middle_point = v3(point);
|
||||
dim.base.insertion_point = v3(point);
|
||||
dim.base.text_user_positioned = true;
|
||||
dim.leader_length = chord.distance(point);
|
||||
dim.base.actual_measurement = dim.measurement();
|
||||
crate::entities::dimension::set_dimension_text_override(
|
||||
&mut dim.base,
|
||||
self.text_override.clone(),
|
||||
);
|
||||
if let Some(angle) = self.text_angle {
|
||||
dim.base.text_rotation = angle;
|
||||
}
|
||||
plane.place_entity(EntityType::Dimension(Dimension::Radius(dim)))
|
||||
}
|
||||
}
|
||||
|
||||
impl CadCommand for RadiusDimensionCommand {
|
||||
@@ -84,32 +115,8 @@ impl CadCommand for RadiusDimensionCommand {
|
||||
match self.step {
|
||||
Step::SelectObject => CmdResult::NeedPoint,
|
||||
Step::DimLine(source) => {
|
||||
let source_plane = WorkingPlane::new(
|
||||
DVec3::from_array(source.plane.origin),
|
||||
DVec3::from_array(source.plane.x_axis),
|
||||
DVec3::from_array(source.plane.y_axis),
|
||||
);
|
||||
let center_world = dvec(source.center_world());
|
||||
let point_world = dvec(source.chord_at(pt.to_array()));
|
||||
let center = source_plane.to_local(center_world);
|
||||
let point = source_plane.to_local(point_world);
|
||||
let pt = source_plane.to_local(pt);
|
||||
let mut dim = DimensionRadius::new(v3(center), v3(point));
|
||||
dim.base.definition_point = v3(point);
|
||||
dim.base.text_middle_point = v3(pt);
|
||||
dim.base.insertion_point = v3(pt);
|
||||
dim.base.text_user_positioned = true;
|
||||
dim.leader_length = point.distance(pt);
|
||||
dim.base.actual_measurement = dim.measurement();
|
||||
crate::entities::dimension::set_dimension_text_override(
|
||||
&mut dim.base,
|
||||
self.text_override.clone(),
|
||||
);
|
||||
if let Some(a) = self.text_angle {
|
||||
dim.base.text_rotation = a;
|
||||
}
|
||||
CmdResult::CommitDimension {
|
||||
entity: source_plane.place_entity(EntityType::Dimension(Dimension::Radius(dim))),
|
||||
entity: self.build_dimension(source, pt),
|
||||
association: DimensionAssociationInput::Infer(self.source_handle),
|
||||
preserve_base_style: false,
|
||||
continue_command: false,
|
||||
@@ -284,6 +291,13 @@ impl CadCommand for RadiusDimensionCommand {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn dimension_preview(&self, cursor: DVec3) -> Option<Vec<DimensionPreview>> {
|
||||
let Step::DimLine(source) = self.step else {
|
||||
return None;
|
||||
};
|
||||
Some(vec![DimensionPreview::current_style(self.build_dimension(source, cursor))])
|
||||
}
|
||||
}
|
||||
|
||||
fn v3(pt: DVec3) -> Vector3 {
|
||||
|
||||
Reference in new issue
Block a user