forked from 1b-agent/opencadstudio-upstream
Merge pull request #1447 from ramox81:codex/diameter-constraint-parity
#1447 branched from the same commit as #1443 and rewrote the radial dimensional constraint a second time, so the two designs had to be reconciled rather than stacked. #1447's is the one kept: it covers DCRADIUS and DCDIAMETER through one command, places the dimension by the direction the location was picked in rather than storing a text point, and names the parameters `radN` / `diaN`. #1443's radial command result, its entity builder call and its follow-up code are gone; its own independent work stays — the ribbon's small-button grid and tool descriptions, the magnitude reading of a negative radius, and the centre anchor a parameter edit resizes a circle about. The DIMCONSTRAINT default follows #1443: running DCRADIUS or DCDIAMETER directly leaves it alone, and the Dispatch arm sets it when DIMCONSTRAINT is what asked for the command. The second commit's radial drawing — the dimension line broken around the text, the elbowed leader, the centre-mark and arrowhead rules — applied to every radius and diameter dimension, not just a constraint's, and three layout-parity tests said the old layout was the measured one. It is now scoped to a dimensional constraint's own dimension, as #1443 scoped its version, and ordinary radial dimensions draw as they did. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
commit
889a19c362
9 files changed
+706
-415
No files matched your search
@@ -87,6 +87,25 @@ impl DiameterDimensionCommand {
|
||||
}
|
||||
}
|
||||
|
||||
/// A diameter dimension for a dimensional constraint: the dimension line
|
||||
/// runs through the centre towards `location`, and the style places the
|
||||
/// text.
|
||||
pub(crate) fn diameter_constraint_entity(
|
||||
center: DVec3,
|
||||
radius: f64,
|
||||
location: DVec3,
|
||||
text: Option<String>,
|
||||
) -> Option<EntityType> {
|
||||
let direction = super::radius_dim::radial_direction(center, location)?;
|
||||
let chord = center + direction * radius;
|
||||
let far_chord = center - direction * radius;
|
||||
let mut dim = DimensionDiameter::new(v3(chord), v3(far_chord));
|
||||
dim.leader_length = chord.distance(location).max(radius * 0.5);
|
||||
dim.base.actual_measurement = dim.measurement();
|
||||
crate::entities::dimension::set_dimension_text_override(&mut dim.base, text);
|
||||
Some(EntityType::Dimension(Dimension::Diameter(dim)))
|
||||
}
|
||||
|
||||
impl CadCommand for DiameterDimensionCommand {
|
||||
fn set_working_plane(&mut self, _plane: WorkingPlane) {
|
||||
}
|
||||
|
||||
@@ -96,6 +96,31 @@ pub(crate) fn radial_dimension_entity(
|
||||
plane.place_entity(EntityType::Dimension(Dimension::Radius(dim)))
|
||||
}
|
||||
|
||||
/// A radius dimension for a dimensional constraint: the leader leaves the
|
||||
/// centre towards `location`, and the style places the text.
|
||||
pub(crate) fn radius_constraint_entity(
|
||||
center: DVec3,
|
||||
radius: f64,
|
||||
location: DVec3,
|
||||
text: Option<String>,
|
||||
) -> Option<EntityType> {
|
||||
let direction = radial_direction(center, location)?;
|
||||
let chord = center + direction * radius;
|
||||
let mut dim = DimensionRadius::new(v3(center), v3(chord));
|
||||
dim.base.definition_point = v3(chord);
|
||||
dim.leader_length = chord.distance(location).max(radius * 0.5);
|
||||
dim.base.actual_measurement = dim.measurement();
|
||||
crate::entities::dimension::set_dimension_text_override(&mut dim.base, text);
|
||||
Some(EntityType::Dimension(Dimension::Radius(dim)))
|
||||
}
|
||||
|
||||
/// The unit direction a radial constraint's dimension points in, from the
|
||||
/// centre to where its dimension line was picked.
|
||||
pub(crate) fn radial_direction(center: DVec3, location: DVec3) -> Option<DVec3> {
|
||||
let delta = location - center;
|
||||
(delta.length() > 1.0e-9).then(|| delta.normalize())
|
||||
}
|
||||
|
||||
impl CadCommand for RadiusDimensionCommand {
|
||||
fn set_working_plane(&mut self, _plane: WorkingPlane) {
|
||||
}
|
||||
|
||||
@@ -16,8 +16,10 @@ pub enum DimConstraintAxis {
|
||||
Aligned,
|
||||
/// The angle between two lines, or at a vertex between two points.
|
||||
Angular,
|
||||
/// The radius of a circle or arc.
|
||||
/// A circle's or arc's radius.
|
||||
Radius,
|
||||
/// A circle's or arc's diameter.
|
||||
Diameter,
|
||||
}
|
||||
|
||||
/// A picked line (a line entity or one polyline segment) an Aligned
|
||||
@@ -108,15 +110,15 @@ enum Step {
|
||||
sector: u8,
|
||||
measured: f64,
|
||||
},
|
||||
/// Radius: `Select arc or circle:`
|
||||
RadialSelect,
|
||||
/// `Specify dimension line location:` of a radius.
|
||||
RadialLocation { circle: ParametricRef, radius: f64 },
|
||||
/// `Enter value or name and value <rad1=30>:`
|
||||
/// Radius/Diameter: `Select arc or circle:`
|
||||
RadialObject,
|
||||
/// `Specify dimension line location:` of a radius or diameter.
|
||||
RadialLocation { target: RadialTarget },
|
||||
/// `Enter value or name and value <dia1=50>:`
|
||||
RadialValue {
|
||||
circle: ParametricRef,
|
||||
radius: f64,
|
||||
target: RadialTarget,
|
||||
location: DVec3,
|
||||
measured: f64,
|
||||
},
|
||||
/// `Enter value or name and value <d1=100>:`
|
||||
Value {
|
||||
@@ -147,6 +149,14 @@ enum AngularData {
|
||||
},
|
||||
}
|
||||
|
||||
/// The circle or arc a Radius/Diameter constraint measures.
|
||||
#[derive(Clone, Copy)]
|
||||
struct RadialTarget {
|
||||
circle: ParametricRef,
|
||||
center: DVec3,
|
||||
radius: f64,
|
||||
}
|
||||
|
||||
/// The reference's Linear/Horizontal/Vertical/Aligned dimensional constraint:
|
||||
/// two constraint points (or one object's ends), a dimension line location,
|
||||
/// then the parameter name and expression the dynamic dimension carries.
|
||||
@@ -167,15 +177,13 @@ impl DimConstraintCommand {
|
||||
"The object or point is already selected. Select a different object or constraint point.";
|
||||
pub const INVALID_LINE: &'static str = "Invalid selection for Aligned. Select a line segment, polyline segment, text, MText, major or minor axis of ellipse or elliptical arc.";
|
||||
pub const PARALLEL_LINES: &'static str = "Lines are parallel.";
|
||||
pub const INVALID_RADIAL: &'static str =
|
||||
"Invalid selection for Radial. Select a circle or arc.";
|
||||
|
||||
pub fn new(axis: DimConstraintAxis, default_name: String) -> Self {
|
||||
Self {
|
||||
axis,
|
||||
step: match axis {
|
||||
DimConstraintAxis::Angular => Step::AngularFirst,
|
||||
DimConstraintAxis::Radius => Step::RadialSelect,
|
||||
DimConstraintAxis::Radius | DimConstraintAxis::Diameter => Step::RadialObject,
|
||||
_ => Step::First,
|
||||
},
|
||||
picked_entity: None,
|
||||
@@ -318,25 +326,6 @@ impl DimConstraintCommand {
|
||||
})
|
||||
}
|
||||
|
||||
fn build_radial(&self, name: String, expression: String) -> Option<CmdResult> {
|
||||
let Step::RadialValue {
|
||||
circle, location, ..
|
||||
} = self.step
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
if expression.trim().is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(CmdResult::AddRadialConstraint {
|
||||
circle,
|
||||
location,
|
||||
renamed: name != self.default_name,
|
||||
name,
|
||||
expression,
|
||||
})
|
||||
}
|
||||
|
||||
fn command_name(&self) -> &'static str {
|
||||
match self.axis {
|
||||
DimConstraintAxis::Linear => "DCLINEAR",
|
||||
@@ -345,6 +334,7 @@ impl DimConstraintCommand {
|
||||
DimConstraintAxis::Aligned => "DCALIGNED",
|
||||
DimConstraintAxis::Angular => "DCANGULAR",
|
||||
DimConstraintAxis::Radius => "DCRADIUS",
|
||||
DimConstraintAxis::Diameter => "DCDIAMETER",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,10 +345,47 @@ impl DimConstraintCommand {
|
||||
DimConstraintAxis::Vertical => "Vertical",
|
||||
DimConstraintAxis::Aligned => "Aligned",
|
||||
DimConstraintAxis::Angular => "Angular",
|
||||
DimConstraintAxis::Radius => "Radial",
|
||||
DimConstraintAxis::Radius => "Radius",
|
||||
DimConstraintAxis::Diameter => "Diameter",
|
||||
}
|
||||
}
|
||||
|
||||
/// The circle or arc a radial pick landed on, with its centre and radius.
|
||||
fn radial_target(entity: &EntityType, handle: Handle) -> Option<RadialTarget> {
|
||||
let (center, radius) = match entity {
|
||||
EntityType::Circle(circle) => (circle.center, circle.radius),
|
||||
EntityType::Arc(arc) => (arc.center, arc.radius),
|
||||
_ => return None,
|
||||
};
|
||||
(radius > 1.0e-12).then_some(RadialTarget {
|
||||
circle: ParametricRef::whole(handle),
|
||||
center: DVec3::new(center.x, center.y, center.z),
|
||||
radius,
|
||||
})
|
||||
}
|
||||
|
||||
fn build_radial(&self, name: String, expression: String) -> Option<CmdResult> {
|
||||
let Step::RadialValue {
|
||||
target, location, ..
|
||||
} = self.step
|
||||
else {
|
||||
return None;
|
||||
};
|
||||
if expression.trim().is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(CmdResult::AddRadialConstraint {
|
||||
circle: target.circle,
|
||||
center: target.center,
|
||||
radius: target.radius,
|
||||
location,
|
||||
diameter: self.axis == DimConstraintAxis::Diameter,
|
||||
renamed: name != self.default_name,
|
||||
name,
|
||||
expression,
|
||||
})
|
||||
}
|
||||
|
||||
fn report(message: &str) -> CmdResult {
|
||||
CmdResult::ReportError(message.to_string())
|
||||
}
|
||||
@@ -509,8 +536,11 @@ impl DimConstraintCommand {
|
||||
}
|
||||
DimConstraintAxis::Horizontal => (ConstraintKind::DistanceX, DVec3::X),
|
||||
DimConstraintAxis::Vertical => (ConstraintKind::DistanceY, DVec3::Y),
|
||||
// Angular and Radius never measure here; their own steps decide.
|
||||
DimConstraintAxis::Aligned | DimConstraintAxis::Angular | DimConstraintAxis::Radius => (
|
||||
// Angular never measures here; its own steps decide the sector.
|
||||
DimConstraintAxis::Aligned
|
||||
| DimConstraintAxis::Angular
|
||||
| DimConstraintAxis::Radius
|
||||
| DimConstraintAxis::Diameter => (
|
||||
ConstraintKind::Distance,
|
||||
(second - first).normalize_or(DVec3::X),
|
||||
),
|
||||
@@ -560,9 +590,10 @@ impl DimConstraintCommand {
|
||||
DimConstraintAxis::Linear => "Linear constraint",
|
||||
DimConstraintAxis::Horizontal => "Horizontal distance constraint",
|
||||
DimConstraintAxis::Vertical => "Vertical distance constraint",
|
||||
DimConstraintAxis::Aligned | DimConstraintAxis::Angular | DimConstraintAxis::Radius => {
|
||||
"Aligned constraint"
|
||||
}
|
||||
DimConstraintAxis::Aligned
|
||||
| DimConstraintAxis::Angular
|
||||
| DimConstraintAxis::Radius
|
||||
| DimConstraintAxis::Diameter => "Aligned constraint",
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -604,17 +635,22 @@ impl CadCommand for DimConstraintCommand {
|
||||
Step::AngularPoint2 { .. } => {
|
||||
format!("{name} Specify second angle constraint point:")
|
||||
}
|
||||
Step::RadialSelect => format!("{name} Select arc or circle:"),
|
||||
Step::AngularLocation { .. } | Step::Location { .. } | Step::RadialLocation { .. } => {
|
||||
Step::RadialObject => format!("{name} Select arc or circle:"),
|
||||
Step::AngularLocation { .. }
|
||||
| Step::Location { .. }
|
||||
| Step::RadialLocation { .. } => {
|
||||
format!("{name} Specify dimension line location:")
|
||||
}
|
||||
Step::AngularValue { measured, .. } | Step::RadialValue { radius: measured, .. } => {
|
||||
format!(
|
||||
"{name} Enter value or name and value <{}={}>:",
|
||||
self.default_name,
|
||||
measured_expression(measured)
|
||||
)
|
||||
}
|
||||
Step::RadialValue { measured, .. } => format!(
|
||||
"{name} Enter value or name and value <{}={}>:",
|
||||
self.default_name,
|
||||
measured_expression(measured)
|
||||
),
|
||||
Step::AngularValue { measured, .. } => format!(
|
||||
"{name} Enter value or name and value <{}={}>:",
|
||||
self.default_name,
|
||||
measured_expression(measured)
|
||||
),
|
||||
Step::Value { measured, .. } => format!(
|
||||
"{name} Enter value or name and value <{}={}>:",
|
||||
self.default_name,
|
||||
@@ -717,7 +753,7 @@ impl CadCommand for DimConstraintCommand {
|
||||
| Step::AngularVertex
|
||||
| Step::AngularPoint1 { .. }
|
||||
| Step::AngularPoint2 { .. }
|
||||
| Step::RadialSelect
|
||||
| Step::RadialObject
|
||||
)
|
||||
}
|
||||
|
||||
@@ -909,27 +945,30 @@ impl CadCommand for DimConstraintCommand {
|
||||
whole_curve: false,
|
||||
})
|
||||
}
|
||||
Step::RadialSelect => {
|
||||
Step::RadialObject => {
|
||||
if handle.is_null() {
|
||||
return Self::report(Self::NO_OBJECT);
|
||||
}
|
||||
let Some(entity) = self.picked_entity.take() else {
|
||||
return CmdResult::NeedPoint;
|
||||
};
|
||||
let radius = match &entity {
|
||||
EntityType::Circle(circle) => circle.radius,
|
||||
EntityType::Arc(arc) => arc.radius,
|
||||
_ => return Self::report(Self::INVALID_RADIAL),
|
||||
let Some(target) = Self::radial_target(&entity, handle) else {
|
||||
return Self::report(&format!(
|
||||
"Invalid selection for {}. Select a circle or arc.",
|
||||
self.noun()
|
||||
));
|
||||
};
|
||||
self.step = Step::RadialLocation {
|
||||
circle: ParametricRef::whole(handle),
|
||||
radius,
|
||||
let measured = if self.axis == DimConstraintAxis::Diameter {
|
||||
target.radius * 2.0
|
||||
} else {
|
||||
target.radius
|
||||
};
|
||||
// The reference reports the radius before asking where the
|
||||
// dimension goes.
|
||||
self.step = Step::RadialLocation { target };
|
||||
// The measured size is reported before the location, as the
|
||||
// reference prints it, with trailing zeros suppressed.
|
||||
CmdResult::ReportMeasurement(format!(
|
||||
"Dimension text = {}",
|
||||
measured_expression(radius)
|
||||
measured_expression(measured)
|
||||
))
|
||||
}
|
||||
Step::Location { .. }
|
||||
@@ -1065,16 +1104,7 @@ impl CadCommand for DimConstraintCommand {
|
||||
| Step::TwoLinesFirst
|
||||
| Step::TwoLinesSecond { .. }
|
||||
| Step::AngularFirst
|
||||
| Step::AngularSecond { .. }
|
||||
| Step::RadialSelect => Self::report(Self::NO_OBJECT),
|
||||
Step::RadialLocation { circle, radius } => {
|
||||
self.step = Step::RadialValue {
|
||||
circle,
|
||||
radius,
|
||||
location: point,
|
||||
};
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
| Step::AngularSecond { .. } => Self::report(Self::NO_OBJECT),
|
||||
Step::AngularLocation { data } => {
|
||||
let frame = match data {
|
||||
AngularData::Lines { first, second } => Self::angle_frame(
|
||||
@@ -1126,6 +1156,20 @@ impl CadCommand for DimConstraintCommand {
|
||||
};
|
||||
CmdResult::ReportMeasurement(format!("Dimension text = {measured:.4}"))
|
||||
}
|
||||
Step::RadialObject => Self::report(Self::NO_OBJECT),
|
||||
Step::RadialLocation { target } => {
|
||||
let measured = if self.axis == DimConstraintAxis::Diameter {
|
||||
target.radius * 2.0
|
||||
} else {
|
||||
target.radius
|
||||
};
|
||||
self.step = Step::RadialValue {
|
||||
target,
|
||||
location: point,
|
||||
measured,
|
||||
};
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
Step::TwoLinesParallel { .. }
|
||||
| Step::Value { .. }
|
||||
| Step::AngularValue { .. }
|
||||
@@ -1147,9 +1191,6 @@ impl CadCommand for DimConstraintCommand {
|
||||
Step::AngularValue { measured, .. } => self
|
||||
.build_angular(self.default_name.clone(), measured_expression(measured))
|
||||
.unwrap_or(CmdResult::Cancel),
|
||||
Step::RadialValue { radius, .. } => self
|
||||
.build_radial(self.default_name.clone(), measured_expression(radius))
|
||||
.unwrap_or(CmdResult::Cancel),
|
||||
Step::PointLinePoint => {
|
||||
self.step = Step::LineFirst;
|
||||
CmdResult::NeedPoint
|
||||
@@ -1157,6 +1198,9 @@ impl CadCommand for DimConstraintCommand {
|
||||
Step::Value { measured, .. } => self
|
||||
.build(self.default_name.clone(), measured_expression(measured))
|
||||
.unwrap_or(CmdResult::Cancel),
|
||||
Step::RadialValue { measured, .. } => self
|
||||
.build_radial(self.default_name.clone(), measured_expression(measured))
|
||||
.unwrap_or(CmdResult::Cancel),
|
||||
_ => CmdResult::Cancel,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user