fix(dimension): harden jogged radius workflow

This commit is contained in:
Hakan Seven committed 2026-08-27 08:09:02 +03:00
commit bc750c6d76
71 files changed
+5834 -860

No files matched your search

+201 -2
View File
@@ -16,6 +16,19 @@ use crate::command::DimensionAssociationSource;
use super::{ChangeKind, Scene};
pub(crate) const POLYLINE_ARC_CENTER_MARKER: i32 = -4;
const POLYLINE_ARC_POINT_MARKER_BASE: i32 = -5;
pub(crate) const ARC_DIMENSION_POINT_MARKER: i32 = -1;
pub(crate) fn polyline_arc_point_marker(segment: i32) -> i32 {
POLYLINE_ARC_POINT_MARKER_BASE - segment.max(0)
}
fn polyline_arc_segment_from_point_marker(marker: i32) -> Option<i32> {
(marker <= POLYLINE_ARC_POINT_MARKER_BASE)
.then_some(POLYLINE_ARC_POINT_MARKER_BASE - marker)
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct RadialSourceGeometry {
pub plane: Plane,
@@ -329,7 +342,21 @@ fn source_marker(entity: &EntityType, point: Vector3) -> Option<i32> {
fn resolve_reference(scene: &Scene, reference: &AssocDimensionReference) -> Option<Vector3> {
let source = *reference.xrefs.first()?;
let entity = scene.document.get_entity(source)?;
if reference.main_gs_marker == -4 {
if reference.main_gs_marker == ARC_DIMENSION_POINT_MARKER {
let radial = radial_source_for_marker(entity, 0)?;
let sweep = positive_sweep(radial.start_angle, radial.end_angle);
let angle = radial.start_angle + sweep * reference.osnap_distance.clamp(0.0, 1.0);
return Some(radial.point_at_angle(angle));
}
if let Some(segment) =
polyline_arc_segment_from_point_marker(reference.main_gs_marker)
{
let radial = radial_source_for_marker(entity, segment)?;
let sweep = positive_sweep(radial.start_angle, radial.end_angle);
let angle = radial.start_angle + sweep * reference.osnap_distance.clamp(0.0, 1.0);
return Some(radial.point_at_angle(angle));
}
if reference.main_gs_marker == POLYLINE_ARC_CENTER_MARKER {
let segment = reference.osnap_distance.round().max(0.0) as usize;
return polyline_arc_center(entity, segment);
}
@@ -422,10 +449,82 @@ fn dimension_reference_points(dimension: &Dimension) -> Vec<Vector3> {
angular.definition_point,
],
Dimension::Ordinate(ordinate) => vec![ordinate.feature_location],
Dimension::Arc(arc) => vec![
arc.center_point,
arc.first_extension_point,
arc.second_extension_point,
],
_ => Vec::new(),
}
}
fn positive_sweep(start: f64, end: f64) -> f64 {
let raw = end - start;
let mut sweep = raw.rem_euclid(TAU);
if sweep <= 1.0e-12 && raw.abs() > 1.0e-12 {
sweep = TAU;
}
sweep
}
fn signed_angle_delta(value: f64) -> f64 {
(value + std::f64::consts::PI).rem_euclid(TAU) - std::f64::consts::PI
}
fn angle_about_plane(
plane: Plane,
center: Vector3,
point: Vector3,
) -> f64 {
let delta = [
point.x - center.x,
point.y - center.y,
point.z - center.z,
];
let dot = |axis: [f64; 3]| {
delta[0] * axis[0] + delta[1] * axis[1] + delta[2] * axis[2]
};
dot(plane.y_axis).atan2(dot(plane.x_axis))
}
fn point_on_radial_circle(
radial: RadialSourceGeometry,
radius: f64,
angle: f64,
) -> Vector3 {
vector3(radial.plane.point_at([
radial.center[0] + radius * angle.cos(),
radial.center[1] + radius * angle.sin(),
]))
}
fn plane_from_normal(origin: Vector3, normal: Vector3) -> Plane {
let (x_axis, y_axis) = crate::scene::view::transform::ocs_axes((
normal.x, normal.y, normal.z,
));
Plane::from_axes(
[origin.x, origin.y, origin.z],
[x_axis.0, x_axis.1, x_axis.2],
[y_axis.0, y_axis.1, y_axis.2],
)
}
fn remap_plane_offset(
old_plane: Plane,
new_plane: Plane,
old_origin: Vector3,
old_point: Vector3,
new_origin: Vector3,
) -> Vector3 {
let old_origin = old_plane.project(dpoint(old_origin)).unwrap_or([0.0; 2]);
let old_point = old_plane.project(dpoint(old_point)).unwrap_or(old_origin);
let new_origin_uv = new_plane.project(dpoint(new_origin)).unwrap_or([0.0; 2]);
vector3(new_plane.point_at([
new_origin_uv[0] + old_point[0] - old_origin[0],
new_origin_uv[1] + old_point[1] - old_origin[1],
]))
}
pub(crate) fn dimension_is_associative(
document: &acadrust::CadDocument,
dimension: Handle,
@@ -807,6 +906,18 @@ impl Scene {
let radial = radial_source_for_marker(entity, reference.main_gs_marker)?;
Some((radial, reference.osnap_distance))
});
let arc_source = association.references[0].first().and_then(|reference| {
let source = *reference.xrefs.first()?;
let entity = self.document.get_entity(source)?;
let segment = match reference.main_gs_marker {
-3 => 0,
POLYLINE_ARC_CENTER_MARKER => {
reference.osnap_distance.round().max(0.0) as i32
}
_ => return None,
};
radial_source_for_marker(entity, segment)
});
if radial_source.is_none() && resolved.iter().all(Option::is_none) {
continue;
}
@@ -936,7 +1047,95 @@ impl Scene {
}
ordinate.refresh_measurement();
}
_ => continue,
Dimension::Arc(arc) => {
let Some(radial) = arc_source else {
continue;
};
let center = resolved[0].unwrap_or_else(|| radial.center_world());
let Some(first) = resolved[1] else {
continue;
};
let Some(second) = resolved[2] else {
continue;
};
let old_center = arc.center_point;
let old_definition = arc.definition_point;
let old_plane = plane_from_normal(old_center, arc.base.normal);
let old_source_radius = old_center.distance(&arc.first_extension_point);
let old_dim_radius = old_center.distance(&old_definition);
let radial_offset = old_dim_radius - old_source_radius;
let old_mid = arc.arc_start_parameter
+ positive_sweep(
arc.arc_start_parameter,
arc.arc_end_parameter,
) * 0.5;
let old_definition_angle =
angle_about_plane(old_plane, old_center, old_definition);
let definition_angle_offset =
signed_angle_delta(old_definition_angle - old_mid);
let start = radial.angle_at(dpoint(first));
let end_at = radial.angle_at(dpoint(second));
let sweep = positive_sweep(start, end_at);
let end = start + sweep;
let new_radius = center.distance(&first);
if !new_radius.is_finite() || new_radius <= 1.0e-12 {
continue;
}
let dim_radius = (new_radius + radial_offset).max(1.0e-9);
let middle = start + sweep * 0.5;
let definition = point_on_radial_circle(
radial,
dim_radius,
middle + definition_angle_offset,
);
let text_middle = remap_plane_offset(
old_plane,
radial.plane,
old_definition,
arc.base.text_middle_point,
definition,
);
let insertion = remap_plane_offset(
old_plane,
radial.plane,
old_definition,
arc.base.insertion_point,
definition,
);
let second_leader = remap_plane_offset(
old_plane,
radial.plane,
old_definition,
arc.second_leader_point,
definition,
);
arc.center_point = center;
arc.first_extension_point = first;
arc.second_extension_point = second;
arc.arc_start_parameter = start;
arc.arc_end_parameter = end;
arc.definition_point = definition;
arc.base.definition_point = definition;
if let Some(normal) = radial.plane.normal() {
arc.base.normal = vector3(normal);
}
if arc.base.text_user_positioned {
arc.base.text_middle_point = text_middle;
arc.base.insertion_point = insertion;
} else {
arc.base.text_middle_point = definition;
arc.base.insertion_point = definition;
}
if arc.has_leader {
arc.first_leader_point =
point_on_radial_circle(radial, dim_radius, middle);
arc.second_leader_point = second_leader;
}
arc.base.actual_measurement = arc.measurement();
}
}
dimension.base_mut().actual_measurement = dimension.measurement();
refreshed.push((association.dimension, ChangeKind::Modified));