Merge pull request #1320 from ghost/styled-dimension-preview

This commit is contained in:
Hakan Seven committed 2026-09-17 07:11:10 +03:00
commit 79bc800728
23 files changed
+724 -138

No files matched your search

+43 -21
View File
@@ -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,
@@ -363,6 +368,23 @@ impl CadCommand for AlignedDimensionCommand {
ref_point: None,
})
}
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 {
+28 -2
View File
@@ -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> {
+14 -2
View File
@@ -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 {
+39 -24
View File
@@ -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 -1
View File
@@ -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(
+13 -1
View File
@@ -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(
+30 -1
View File
@@ -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 {
+43 -23
View File
@@ -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),
@@ -402,6 +405,23 @@ impl CadCommand for LinearDimensionCommand {
ref_point: None,
})
}
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 {
+30 -20
View File
@@ -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 {
+10 -1
View File
@@ -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) }
+40 -26
View File
@@ -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 {