DCDIAMETER/DCRADIUS: the reference flow with a real radial dimension

The commands ask for the circle or arc themselves, report the measured
size, take a dimension line location and then the value or name and
value, creating a radius or diameter dimension as the constraint's
dynamic dimension with a radN/diaN parameter, refusing a second radial
constraint on the same object and any non-positive value.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
ramox81andClaude Opus 5 committed 2026-09-22 15:21:11 +03:00
1 parent 64c020293a
commit 19204d1b2c
8 files changed
+531 -24

No files matched your search

+132 -2
View File
@@ -363,6 +363,19 @@ pub(crate) fn next_dimensional_parameter_name(
.unwrap_or_else(|| "d1".to_string())
}
/// The first free `rad1`/`dia1`, `rad2`/`dia2`, … name a new radius or
/// diameter constraint takes.
pub(crate) fn next_radial_parameter_name(
table: &super::named_parameters::ParameterTable,
diameter: bool,
) -> String {
let prefix = if diameter { "dia" } else { "rad" };
(1..)
.map(|n| format!("{prefix}{n}"))
.find(|name| !table.contains(name))
.unwrap_or_else(|| format!("{prefix}1"))
}
/// The first free `ang1`, `ang2`, … name a new angular constraint takes.
pub(crate) fn next_angular_parameter_name(
table: &super::named_parameters::ParameterTable,
@@ -601,6 +614,99 @@ fn angular_follow_points(
}
}
/// A radial constraint's circle or arc: its centre and radius now.
fn radial_geometry(
document: &acadrust::CadDocument,
constraint: &ParametricConstraint,
) -> Option<(glam::DVec3, f64)> {
let reference = constraint.refs.first()?;
let (center, radius) = match document.get_entity(reference.entity)? {
acadrust::EntityType::Circle(circle) => (circle.center, circle.radius),
acadrust::EntityType::Arc(arc) => (arc.center, arc.radius),
_ => return None,
};
Some((glam::DVec3::new(center.x, center.y, center.z), radius))
}
/// Rebuilds a dynamic radial dimension on its circle's current centre and
/// radius, keeping the direction its dimension line was placed in; true
/// when anything moved.
fn dynamic_dimension_follow_radial(
dimension: &mut acadrust::entities::Dimension,
center: glam::DVec3,
radius: f64,
) -> bool {
use acadrust::entities::Dimension;
let to_dvec = |p: Vector3| glam::DVec3::new(p.x, p.y, p.z);
let same = |a: Vector3, b: Vector3| (a - b).length_squared() < 1.0e-16;
let text = dimension.base().user_text.clone();
let (rebuilt, leader) = match &*dimension {
Dimension::Radius(d) => {
let direction = to_dvec(d.definition_point) - to_dvec(d.angle_vertex);
let direction = direction
.try_normalize()
.unwrap_or(glam::DVec3::X);
(
crate::modules::annotate::radius_dim::radius_constraint_entity(
center,
radius,
center + direction * radius.max(1.0e-9),
text,
),
d.leader_length,
)
}
Dimension::Diameter(d) => {
let direction = to_dvec(d.angle_vertex) - to_dvec(d.definition_point);
let direction = direction
.try_normalize()
.unwrap_or(glam::DVec3::X);
(
crate::modules::annotate::diameter_dim::diameter_constraint_entity(
center,
radius,
center + direction * radius.max(1.0e-9),
text,
),
d.leader_length,
)
}
_ => return false,
};
let Some(acadrust::EntityType::Dimension(mut rebuilt)) = rebuilt else {
return false;
};
let unchanged = match (&*dimension, &rebuilt) {
(Dimension::Radius(old), Dimension::Radius(new)) => {
same(old.angle_vertex, new.angle_vertex)
&& same(old.definition_point, new.definition_point)
}
(Dimension::Diameter(old), Dimension::Diameter(new)) => {
same(old.angle_vertex, new.angle_vertex)
&& same(old.definition_point, new.definition_point)
}
_ => false,
};
if unchanged {
return false;
}
match &mut rebuilt {
Dimension::Radius(new) => new.leader_length = leader,
Dimension::Diameter(new) => new.leader_length = leader,
_ => {}
}
let base = dimension.base();
let target = rebuilt.base_mut();
target.common = base.common.clone();
target.style_name = base.style_name.clone();
target.text_rotation = base.text_rotation;
target.attachment_point = base.attachment_point;
target.line_spacing_style = base.line_spacing_style;
target.line_spacing_factor = base.line_spacing_factor;
*dimension = rebuilt;
true
}
/// Rebuilds a dynamic angular dimension on its sides' current positions,
/// keeping its arc point; true when anything moved.
fn dynamic_dimension_follow_angle(
@@ -1983,6 +2089,7 @@ impl super::Scene {
String,
Option<(Vector3, Vector3)>,
Option<Vec<Vector3>>,
Option<(glam::DVec3, f64)>,
)> = Vec::new();
// A reference (driven) constraint's parameter follows the geometry.
let mut followed: Vec<(String, f64)> = Vec::new();
@@ -2010,6 +2117,20 @@ impl super::Scene {
constraint.kind,
ConstraintKind::Angle | ConstraintKind::Angle3Point
);
let radial = matches!(
constraint.kind,
ConstraintKind::Radius | ConstraintKind::Diameter
);
let radial_now = radial
.then(|| radial_geometry(&self.document, constraint))
.flatten();
let radial_measured = radial_now.map(|(_, radius)| {
if constraint.kind == ConstraintKind::Diameter {
radius * 2.0
} else {
radius
}
});
let measured = points.filter(|_| !angular).map(|(first, second)| {
let delta = second - first;
let axis = match self.document.get_entity(*dimension) {
@@ -2027,6 +2148,7 @@ impl super::Scene {
_ => delta.length(),
}
});
let measured = radial_measured.or(measured);
let (name, value, source) = match &constraint.driving_param {
Some(DrivingValue::Named(name)) => {
let value = match (reference, measured) {
@@ -2068,8 +2190,11 @@ impl super::Scene {
annotational,
decimals,
),
points,
// A radial dimension follows its own circle, not a pair
// of constraint points.
points.filter(|_| !radial),
angle_points,
radial_now,
));
}
}
@@ -2079,7 +2204,7 @@ impl super::Scene {
let _ = self.named_parameters.set(&name, &source);
}
}
for (handle, text, points, angle_points) in updates {
for (handle, text, points, angle_points, radial) in updates {
let Some(acadrust::EntityType::Dimension(mut dimension)) =
self.document.get_entity(handle).cloned()
else {
@@ -2096,6 +2221,11 @@ impl super::Scene {
changed = true;
}
}
if let Some((center, radius)) = radial {
if dynamic_dimension_follow_radial(&mut dimension, center, radius) {
changed = true;
}
}
if dimension.base().user_text.as_deref() != Some(text.as_str()) {
crate::entities::dimension::set_dimension_text_override(
dimension.base_mut(),