Complete angular dimension layout and fitting

This commit is contained in:
ramox81 2026-08-25 12:23:29 +03:00
commit 6bbef80a26

View file

@ -1095,6 +1095,14 @@ fn dimension_line_grip_position(dim: &Dimension) -> Option<DVec3> {
}
fn above_dimension_text_position(dim: &Dimension) -> Option<DVec3> {
if let Some((vertex, start, end, radius)) = angular_dimension_frame(dim) {
let angle = (start + end) * 0.5;
let direction = DVec3::new(angle.cos() as f64, angle.sin() as f64, 0.0);
return Some(
DVec3::new(vertex.x as f64, vertex.y as f64, vertex.z as f64)
+ direction * (radius as f64 + 1.0),
);
}
let center = dimension_line_grip_position(dim)?;
let (ax, ay) = match dim {
Dimension::Linear(d) => (d.rotation.cos(), d.rotation.sin()),
@ -2524,7 +2532,7 @@ use acadrust::{CadDocument, EntityType, Handle};
use crate::scene::convert::tess_util::aci_to_rgba;
use crate::scene::convert::tessellate::{
add_polyline, add_segment, append_arrow, arrow_from_block_with_deferred_hatch,
add_segment, append_arrow, arrow_from_block_with_deferred_hatch,
normalized_or, ArrowKind, DimGeom,
};
use crate::scene::model::wire_model::{SnapHint, WireModel};
@ -4056,6 +4064,43 @@ fn two_line_angle_frame(
Some((vertex, start, end))
}
fn angular_dimension_frame(dim: &Dimension) -> Option<(Vec3, f32, f32, f32)> {
let (vertex, start, end, arc_point) = match dim {
Dimension::Angular2Ln(value) => {
let first_start = vec3_local(value.first_point);
let first_end = vec3_local(value.second_point);
let second_start = vec3_local(value.angle_vertex);
let second_end = vec3_local(value.definition_point);
let stored_arc = if value.dimension_arc.length_squared() > 1.0e-18 {
value.dimension_arc
} else {
value.base.definition_point
};
let arc_point = vec3_local(stored_arc);
let (vertex, start, end) = two_line_angle_frame(
first_start,
first_end,
second_start,
second_end,
arc_point,
)?;
(vertex, start, end, arc_point)
}
Dimension::Angular3Pt(value) => {
let vertex = vec3_local(value.angle_vertex);
let first = vec3_local(value.first_point);
let second = vec3_local(value.second_point);
let arc_point = vec3_local(value.definition_point);
let (vertex, start, end) =
two_line_angle_frame(vertex, first, vertex, second, arc_point)?;
(vertex, start, end, arc_point)
}
_ => return None,
};
let radius = vertex.distance(arc_point);
(radius > 1.0e-6).then_some((vertex, start, end, radius))
}
fn append_angular_dimension(
g: &mut DimGeom,
vertex: Vec3,
@ -4121,11 +4166,22 @@ fn append_angular_dimension(
delta = end - start;
}
let arc_extension = if params.ticks && radius > 1.0e-6 {
params.dimdle / radius
let arc_length = radius * delta.abs();
let arrows_outside = if params.ticks || params.arrow_len <= 1.0e-6 {
false
} else if arc_length < params.arrow_len * 2.0 {
true
} else if arc_length < params.text_width + params.arrow_len * 2.0 {
match params.dimatfit {
0 | 1 => true,
2 => false,
_ => params.text_width <= arc_length,
}
} else {
0.0
false
};
let draw_inside_line = !arrows_outside || params.dimtofl;
let arc_extension = if params.ticks { params.dimdle / radius } else { 0.0 };
let direction = delta.signum();
let draw_start = start - direction * arc_extension;
let draw_delta = delta + direction * arc_extension * 2.0;
@ -4133,34 +4189,119 @@ fn append_angular_dimension(
let mut arc_pts = Vec::with_capacity((steps + 1) as usize);
for i in 0..=steps {
let t = i as f32 / steps as f32;
let a = draw_start + draw_delta * t;
arc_pts.push(vertex + Vec3::new(a.cos() * radius, a.sin() * radius, 0.0));
let angle = draw_start + draw_delta * t;
arc_pts.push(vertex + Vec3::new(angle.cos() * radius, angle.sin() * radius, 0.0));
}
if draw_inside_line {
for index in 0..steps as usize {
let t = (index as f32 + 0.5) / steps as f32;
if (t < 0.5 && suppress.dim1) || (t >= 0.5 && suppress.dim2) {
continue;
}
let a = arc_pts[index];
let b = arc_pts[index + 1];
let hidden_by_text = params.text_break.is_some_and(|(center, half_width, half_height)| {
let angle = draw_start + draw_delta * t;
let radial = Vec3::new(angle.cos(), angle.sin(), 0.0);
let tangent = Vec3::new(-angle.sin(), angle.cos(), 0.0);
let offset = center - (a + b) * 0.5;
offset.dot(tangent).abs() <= half_width
&& offset.dot(radial).abs() <= half_height
});
if !hidden_by_text {
add_segment(&mut g.dim_lines, a, b);
}
let midpoint = arc_pts.len() / 2;
if !suppress.dim1 && midpoint > 0 {
add_polyline(&mut g.dim_lines, &arc_pts[..=midpoint]);
}
if !suppress.dim2 && midpoint + 1 < arc_pts.len() {
add_polyline(&mut g.dim_lines, &arc_pts[midpoint..]);
}
if arc_pts.len() >= 2 {
if arrows_outside && !params.dimsoxd {
let stub_angle = (params.arrow_len * 2.0 / radius).min(std::f32::consts::FRAC_PI_2);
if !suppress.dim1 {
append_sampled_arc(
&mut g.dim_lines,
vertex,
radius,
start - direction * stub_angle,
start,
);
}
if !suppress.dim2 {
append_sampled_arc(
&mut g.dim_lines,
vertex,
radius,
end,
end + direction * stub_angle,
);
}
}
if let Some((text_center, half_width, _)) = params.text_break {
let text_angle = (text_center.y - vertex.y).atan2(text_center.x - vertex.x);
let into = (text_angle - start).rem_euclid(std::f32::consts::TAU);
if into > delta.abs() + 1.0e-6 {
let back_to_start = (start - text_angle).rem_euclid(std::f32::consts::TAU);
let forward_from_end = (text_angle - end).rem_euclid(std::f32::consts::TAU);
let text_gap = (half_width / radius).min(std::f32::consts::FRAC_PI_2);
if back_to_start <= forward_from_end && !suppress.dim1 {
append_sampled_arc(
&mut g.dim_lines,
vertex,
radius,
text_angle + text_gap,
start,
);
} else if !suppress.dim2 {
append_sampled_arc(
&mut g.dim_lines,
vertex,
radius,
end,
text_angle - text_gap,
);
}
}
}
let start_tangent = Vec3::new(-start.sin(), start.cos(), 0.0) * direction;
let end_tangent = Vec3::new(-end.sin(), end.cos(), 0.0) * direction;
let draw_arrows = !arrows_outside || !params.dimsoxd;
if draw_arrows && !suppress.dim1 {
append_arrow(
g,
arc_pts[0],
normalized_or(arc_pts[1] - arc_pts[0], Vec3::X),
arc_start,
if arrows_outside { -start_tangent } else { start_tangent },
arrow1,
);
let n = arc_pts.len();
}
if draw_arrows && !suppress.dim2 {
append_arrow(
g,
arc_pts[n - 1],
normalized_or(arc_pts[n - 2] - arc_pts[n - 1], Vec3::X),
arc_end,
if arrows_outside { end_tangent } else { -end_tangent },
arrow2,
);
}
}
fn append_sampled_arc(
lines: &mut Vec<[f32; 3]>,
vertex: Vec3,
radius: f32,
start: f32,
end: f32,
) {
let steps = angular_arc_steps(end - start);
let mut previous = vertex + Vec3::new(start.cos() * radius, start.sin() * radius, 0.0);
for index in 1..=steps {
let t = index as f32 / steps as f32;
let angle = start + (end - start) * t;
let next = vertex + Vec3::new(angle.cos() * radius, angle.sin() * radius, 0.0);
add_segment(lines, previous, next);
previous = next;
}
}
fn angular_arc_steps(sweep: f32) -> u32 {
((sweep.abs() / std::f32::consts::PI * 90.0).ceil() as u32).clamp(8, 720)
}
@ -4422,6 +4563,32 @@ fn dimension_text_is_outside(dim: &Dimension, style: Option<&DimStyle>) -> bool
let Some(style) = style else {
return false;
};
if let Some((vertex, start, end, radius)) = angular_dimension_frame(dim) {
if dim.base().text_user_positioned {
let text = vec3_local(dim.base().text_middle_point);
let angle = (text.y - vertex.y).atan2(text.x - vertex.x);
return (angle - start).rem_euclid(std::f32::consts::TAU)
> end - start + 1.0e-6;
}
if style.dimtix {
return false;
}
let scale = if style.dimscale > 1e-9 { style.dimscale } else { 1.0 };
let height = style.dimtxt * scale;
let gap = style.dimgap.abs() * scale;
let text_width = dimension_text_value(dim, Some(style))
.map(|value| value.chars().count() as f64 * height * 0.6 + gap * 2.0)
.unwrap_or(0.0);
let arrow = style.dimasz * scale;
let span = radius as f64 * (end - start).abs() as f64;
let insufficient = text_width + arrow * 2.0 > span;
return insufficient
&& match style.dimatfit {
0 | 2 => true,
1 | 3 => text_width > span,
_ => text_width > span,
};
}
let (first, second, axis) = match dim {
Dimension::Linear(d) => (
d.first_point,
@ -4472,6 +4639,11 @@ fn dimension_text_natural_rotation(dim: &Dimension) -> f64 {
let dy = d.second_point.y - d.first_point.y;
dy.atan2(dx)
}
Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_) => angular_dimension_frame(dim)
.map(|(_, start, end, _)| {
((start + end) * 0.5 + std::f32::consts::FRAC_PI_2) as f64
})
.unwrap_or(0.0),
_ => 0.0,
};
// Clamp to (-π/2, π/2] so text never appears upside-down.
@ -5245,6 +5417,32 @@ fn dimension_text_pos_f64(
dimtad,
)
}
Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_) => {
let Some((vertex, start, end, radius)) = angular_dimension_frame(dim) else {
return base.text_middle_point;
};
let span = radius as f64 * (end - start).abs() as f64;
let insufficient = text_w + arrow * 2.0 > span;
let move_outside = !dimtix
&& insufficient
&& match dimatfit {
0 | 2 => true,
1 | 3 => text_w > span,
_ => text_w > span,
};
let angle = if move_outside {
end as f64 + (text_w * 0.5 + dimgap + arrow) / (radius as f64).max(1.0e-12)
} else {
((start + end) * 0.5) as f64
};
let radial_offset = if dimtad == 4 { -perp_off } else { perp_off };
let text_radius = (radius as f64 + radial_offset).max(0.0);
Vector3::new(
vertex.x as f64 + angle.cos() * text_radius,
vertex.y as f64 + angle.sin() * text_radius,
vertex.z as f64,
)
}
_ => {
// Non-linear (radius / diameter / angular / ordinate): lift the
// natural mid point straight up by the style offset. A user-dragged