Complete angular dimension layout and fitting
This commit is contained in:
parent
24b344b2b2
commit
6bbef80a26
1 changed files with 215 additions and 17 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue