fix(dimension): complete ordinate workflow

This commit is contained in:
Hakan Seven committed 2026-08-25 21:36:04 +03:00
commit 968ee3fda4
29 files changed
+504 -112

No files matched your search

+214 -24
View File
@@ -158,6 +158,23 @@ fn properties(dim: &Dimension) -> Vec<PropSection> {
}],
}];
}
if let Dimension::Ordinate(d) = dim {
return vec![PropSection {
title: t!("Misc").into_owned(),
props: vec![
Property {
label: t!("Dimension style").into_owned(),
field: "style_name",
value: PropValue::PlainText(d.base.style_name.clone()),
},
edit_angle(
t!("Rotation").as_ref(),
"ordinate_rotation",
-d.base.horizontal_direction.to_degrees(),
),
],
}];
}
let mut props = base_props(dim.base());
match dim {
Dimension::Aligned(d) => {
@@ -385,6 +402,40 @@ fn assign_deg(value: &str, target: &mut f64) -> bool {
}
fn apply_geom_prop(dim: &mut Dimension, field: &str, value: &str) {
let ordinate_auto_text = match dim {
Dimension::Ordinate(ordinate) if !ordinate.base.text_user_positioned => {
Some(dimension_text_pos_f64(dim, None, 2.5, 1.0))
}
_ => None,
};
if let Dimension::Ordinate(ordinate) = dim {
match field {
"ordinate_rotation" => {
if let Some(angle) = parse_f64(value) {
ordinate.base.horizontal_direction = -angle.to_radians();
ordinate.refresh_measurement();
}
return;
}
"text_x" | "text_y" => {
let old_text = ordinate_auto_text.unwrap_or(ordinate.base.text_middle_point);
let mut new_text = old_text;
let changed = if field == "text_x" {
assign_f64(value, &mut new_text.x)
} else {
assign_f64(value, &mut new_text.y)
};
if changed {
let delta = new_text - old_text;
ordinate.leader_endpoint = ordinate.leader_endpoint + delta;
ordinate.base.text_middle_point = new_text;
ordinate.base.text_user_positioned = true;
}
return;
}
_ => {}
}
}
if apply_base_prop(dim.base_mut(), field, value) {
return;
}
@@ -743,6 +794,42 @@ fn apply_large_radial_fields(d: &mut DimensionLargeRadial, field: &str, value: &
}
fn apply_transform(dim: &mut Dimension, t: &EntityTransform) {
if matches!(dim, Dimension::Ordinate(_)) {
match t {
EntityTransform::Translate(delta) => dim.translate(Vector3::new(
delta.x, delta.y, delta.z,
)),
EntityTransform::Rotate {
center,
axis,
angle_rad,
} => crate::scene::view::transform::apply_standard_transform(
dim,
*center,
*axis,
*angle_rad,
),
EntityTransform::Scale { center, factor } => {
crate::scene::view::transform::apply_standard_scale(dim, *center, *factor)
}
EntityTransform::Mirror {
p1,
p2,
working_normal,
} => acadrust::Entity::apply_transform(
dim,
&crate::scene::view::transform::reflection_about_working_line(
*p1,
*p2,
*working_normal,
),
),
EntityTransform::Affine(transform) => {
acadrust::Entity::apply_transform(dim, transform)
}
}
return;
}
match t {
EntityTransform::Translate(d) => dim.translate(acadrust::types::Vector3::new(
d.x as f64, d.y as f64, d.z as f64,
@@ -1242,10 +1329,9 @@ impl Grippable for Dimension {
center_grip(4, text),
],
Dimension::Ordinate(d) => vec![
square_grip(0, dv3(&d.definition_point)),
center_grip(1, dv3(&d.feature_location)),
center_grip(2, dv3(&d.leader_endpoint)),
center_grip(3, text),
square_grip(0, dv3(&d.feature_location)),
center_grip(1, dv3(&d.leader_endpoint)),
center_grip(2, text),
],
Dimension::Arc(d) => {
let mut grips = vec![
@@ -1276,13 +1362,26 @@ impl Grippable for Dimension {
fn apply_grip(&mut self, grip_id: usize, apply: GripApply) {
if matches!(self, Dimension::Ordinate(_)) && grip_id == 2 {
let old_text = dimension_text_pos_f64(self, None, 2.5, 1.0);
let mut new_text = old_text;
apply_to_v3(&mut new_text, &apply);
let delta = new_text - old_text;
if let Dimension::Ordinate(d) = self {
d.leader_endpoint = d.leader_endpoint + delta;
d.base.text_middle_point = new_text;
d.base.text_user_positioned = true;
d.refresh_measurement();
}
return;
}
// Last grip always moves the text.
let text_grip = match self {
Dimension::Linear(_) | Dimension::Aligned(_) => 3,
Dimension::Radius(_) | Dimension::Diameter(_) => 2,
Dimension::Angular2Ln(_) => 5,
Dimension::Angular3Pt(_) => 4,
Dimension::Ordinate(_) => 3,
Dimension::Ordinate(_) => 2,
Dimension::Arc(d) => if d.has_leader { 6 } else { 4 },
Dimension::LargeRadial(_) => 4,
};
@@ -1357,9 +1456,15 @@ impl Grippable for Dimension {
_ => {}
},
Dimension::Ordinate(d) => match grip_id {
0 => apply_to_v3(&mut d.definition_point, &apply),
1 => apply_to_v3(&mut d.feature_location, &apply),
2 => apply_to_v3(&mut d.leader_endpoint, &apply),
0 => apply_to_v3(&mut d.feature_location, &apply),
1 => {
let old = d.leader_endpoint;
apply_to_v3(&mut d.leader_endpoint, &apply);
if d.base.text_user_positioned {
d.base.text_middle_point =
d.base.text_middle_point + (d.leader_endpoint - old);
}
}
_ => {}
},
Dimension::Arc(d) => match grip_id {
@@ -1396,7 +1501,7 @@ impl Grippable for Dimension {
Dimension::Radius(_) | Dimension::Diameter(_) => (1, 2),
Dimension::Angular2Ln(_) => (4, 5),
Dimension::Angular3Pt(_) => (3, 4),
Dimension::Ordinate(_) => (0, 3),
Dimension::Ordinate(_) => (1, 2),
Dimension::Arc(d) => (3, if d.has_leader { 6 } else { 4 }),
Dimension::LargeRadial(_) => (3, 4),
};
@@ -1435,6 +1540,11 @@ impl Grippable for Dimension {
action: GripMenuAction::Center,
},
]
} else if matches!(self, Dimension::Ordinate(_)) {
vec![GripMenuItem {
label: "Stretch",
action: GripMenuAction::Stretch,
}]
} else if grip_id == dim_line_grip {
vec![
GripMenuItem {
@@ -1465,7 +1575,7 @@ impl Grippable for Dimension {
Dimension::Radius(_) | Dimension::Diameter(_) => (1, 2),
Dimension::Angular2Ln(_) => (4, 5),
Dimension::Angular3Pt(_) => (3, 4),
Dimension::Ordinate(_) => (0, 3),
Dimension::Ordinate(_) => (1, 2),
Dimension::Arc(d) => (3, if d.has_leader { 6 } else { 4 }),
Dimension::LargeRadial(_) => (3, 4),
};
@@ -1513,7 +1623,7 @@ impl Grippable for Dimension {
Dimension::Radius(_) | Dimension::Diameter(_) => 2,
Dimension::Angular2Ln(_) => 5,
Dimension::Angular3Pt(_) => 4,
Dimension::Ordinate(_) => 3,
Dimension::Ordinate(_) => 2,
Dimension::Arc(d) => if d.has_leader { 6 } else { 4 },
Dimension::LargeRadial(_) => 4,
};
@@ -2410,7 +2520,6 @@ pub fn style_sections(
],
},
];
if matches!(dimension, Dimension::Radius(_) | Dimension::Diameter(_)) {
let dimcen = real(ov::DIMCEN, s.dimcen);
let center_type = if dimcen > 1e-12 {
@@ -2561,6 +2670,52 @@ pub fn style_sections(
}
}
if matches!(dimension, Dimension::Ordinate(_)) {
for section in &mut sections {
section.props.retain(|property| match section.title.as_str() {
title if title == t!("Lines & Arrows").as_ref() => matches!(
property.field,
"dim_arrow_size"
| "dim_ext_line_lineweight"
| "dim_ext_linetype_1"
| "dim_ext_line_1"
| "dim_ext_line_fixed"
| "dim_ext_line_fixed_length"
| "dim_ext_line_color"
| "dim_ext_line_offset"
),
title if title == t!("Text").as_ref() => !matches!(
property.field,
"dim_text_outside_align" | "dim_text_pos_hor" | "dim_text_inside_align"
),
title if title == t!("Fit").as_ref() => matches!(
property.field,
"dim_text_movement" | "dim_scale_overall"
),
_ => true,
});
}
let dim_scale = if s.dimscale > 1e-6 { s.dimscale } else { 1.0 };
let text_position = dimension_text_pos_f64(
dimension,
Some(s),
real(ov::DIMTXT, s.dimtxt) * dim_scale,
dim_scale,
);
for section in &mut sections {
for property in &mut section.props {
match property.field {
"text_x" => {
property.value = PropValue::EditText(format!("{:.4}", text_position.x));
}
"text_y" => {
property.value = PropValue::EditText(format!("{:.4}", text_position.y));
}
_ => {}
}
}
}
}
sections
}
@@ -3996,16 +4151,23 @@ fn dimension_geometry(
);
}
Dimension::Ordinate(d) => {
add_segment(
&mut g.dim_lines,
lv(d.feature_location),
lv(d.definition_point),
);
add_segment(
&mut g.dim_lines,
lv(d.definition_point),
lv(d.leader_endpoint),
);
if !suppress.ext1 {
let fixed_length = params
.dimfxlon
.then_some(params.dimfxl.max(0.0) as f64);
let points = d.leader_polyline(
(params.arrow_len * 2.0) as f64,
params.dimexo as f64,
fixed_length,
);
for pair in points.windows(2) {
let start = lv(pair[0]);
let end = lv(pair[1]);
if (end - start).length_squared() > 1e-12 {
add_segment(&mut g.ext_lines, start, end);
}
}
}
}
Dimension::Arc(d) => {
append_angular_dimension(
@@ -4702,7 +4864,6 @@ fn dimension_snap_pts(dim: &Dimension) -> Vec<(glam::DVec3, SnapHint)> {
node(d.definition_point),
],
Dimension::Ordinate(d) => vec![
node(d.definition_point),
node(d.feature_location),
node(d.leader_endpoint),
],
@@ -4912,6 +5073,8 @@ fn dimension_text_rotation(dim: &Dimension, style: Option<&DimStyle>) -> f64 {
let outside = dimension_text_is_outside(dim, style);
if base.text_rotation.abs() > 1e-9 {
base.text_rotation
} else if matches!(dim, Dimension::Ordinate(_)) {
dimension_text_natural_rotation(dim)
} else if base.horizontal_direction.abs() > 1e-9 {
base.horizontal_direction
} else if (outside && dimtoh) || (!outside && dimtih) {
@@ -5047,6 +5210,14 @@ fn dimension_text_natural_rotation(dim: &Dimension) -> f64 {
.atan2(d.definition_point.x - d.angle_vertex.x),
Dimension::Diameter(d) => (d.definition_point.y - d.angle_vertex.y)
.atan2(d.definition_point.x - d.angle_vertex.x),
Dimension::Ordinate(d) => {
let axis_rotation = -d.base.horizontal_direction;
if d.is_ordinate_type_x {
axis_rotation + std::f64::consts::FRAC_PI_2
} else {
axis_rotation
}
}
_ => 0.0,
};
// Clamp to (-π/2, π/2] so text never appears upside-down.
@@ -5887,12 +6058,31 @@ fn dimension_text_pos_f64(
dimtad,
)
}
Dimension::Ordinate(d) => {
let (x_axis, y_axis) = d.local_axes();
let text_axis = if d.is_ordinate_type_x { y_axis } else { x_axis };
let perpendicular = if d.is_ordinate_type_x { x_axis } else { y_axis };
let delta = d.leader_endpoint - d.feature_location;
let direction_sign = if delta.dot(&text_axis) < 0.0 { -1.0 } else { 1.0 };
let perpendicular_sign = if delta.dot(&perpendicular) < 0.0 {
-1.0
} else {
1.0
};
let vertical = match dimtad {
0 => dimtvp * text_height,
4 => -perp_off,
_ => perp_off,
};
d.leader_endpoint
+ text_axis * (direction_sign * (text_w * 0.5 + dimgap))
+ perpendicular * (perpendicular_sign * vertical)
}
_ => {
// Auto-placed text follows the style offset.
let mid = match dim {
Dimension::Angular2Ln(d) => d.dimension_arc,
Dimension::Angular3Pt(d) => d.definition_point,
Dimension::Ordinate(d) => d.leader_endpoint,
Dimension::Arc(d) => d.definition_point,
Dimension::LargeRadial(d) => d.jog_point,
_ => base.text_middle_point,