Merge pull request #886 from ramox81/codex/complete-jogged-radius-dimension
Complete jogged radius dimension workflow
This commit is contained in:
commit
ba91095bcf
11 changed files with 747 additions and 85 deletions
|
|
@ -1864,6 +1864,12 @@ annotate =
|
|||
.dimjogged-created-a-jogged-radius-dimension = DIMJOGGED: created a jogged radius dimension.
|
||||
.dimjogged-invalid-radius = DIMJOGGED: invalid radius.
|
||||
.dimjogged-select-an-arc-or-circle-first = DIMJOGGED: select an arc or circle first.
|
||||
.dimjogged-enter-dimension-text-blank-measured = DIMJOGGED Enter dimension text (blank = measured value):
|
||||
.dimjogged-select-arc-circle-or-polyline-arc = DIMJOGGED Select arc, circle, or polyline arc:
|
||||
.dimjogged-specify-center-location-override = DIMJOGGED Specify center location override:
|
||||
.dimjogged-specify-dimension-line-location-text = DIMJOGGED Specify dimension line location [Mtext/Text/Angle]:
|
||||
.dimjogged-specify-jog-location = DIMJOGGED Specify jog location:
|
||||
.dimjogged-specify-text-angle-degrees = DIMJOGGED Specify text angle (degrees):
|
||||
.dimjogline-select-linear-or-aligned-dimension = DIMJOGLINE Select linear or aligned dimension:
|
||||
.dimjogline-specify-jog-location = DIMJOGLINE Specify jog location:
|
||||
.dimlinear-enter-dimension-text-blank-measured = DIMLINEAR Enter dimension text (blank = measured value):
|
||||
|
|
@ -2667,6 +2673,7 @@ properties =
|
|||
.island-detection-style = Island detection style
|
||||
.italic = Italic
|
||||
.jog-angle = Jog Angle
|
||||
.jogged-radius = Jogged Radius
|
||||
.jog-x = Jog X
|
||||
.jog-y = Jog Y
|
||||
.jog-z = Jog Z
|
||||
|
|
|
|||
|
|
@ -1844,6 +1844,12 @@ annotate =
|
|||
.dimjogged-created-a-jogged-radius-dimension = DIMJOGGED: kırıklı yarıçap ölçüsü oluşturuldu.
|
||||
.dimjogged-invalid-radius = DIMJOGGED: yarıçap geçersiz.
|
||||
.dimjogged-select-an-arc-or-circle-first = DIMJOGGED: önce bir yay veya daire seçin.
|
||||
.dimjogged-enter-dimension-text-blank-measured = DIMJOGGED Ölçü metnini girin (boş = ölçülen değer):
|
||||
.dimjogged-select-arc-circle-or-polyline-arc = DIMJOGGED Yay, daire veya çoklu çizgi yayı seçin:
|
||||
.dimjogged-specify-center-location-override = DIMJOGGED Geçersiz kılınmış merkez konumunu belirtin:
|
||||
.dimjogged-specify-dimension-line-location-text = DIMJOGGED Ölçü çizgisinin konumunu belirtin [Çok satırlı metin/Metin/Açı]:
|
||||
.dimjogged-specify-jog-location = DIMJOGGED Kırılma konumunu belirtin:
|
||||
.dimjogged-specify-text-angle-degrees = DIMJOGGED Metin açısını belirtin (derece):
|
||||
.dimjogline-select-linear-or-aligned-dimension = DIMJOGLINE Doğrusal veya hizalı ölçüyü seçin:
|
||||
.dimjogline-specify-jog-location = DIMJOGLINE Kırılma konumunu belirtin:
|
||||
.dimlinear-enter-dimension-text-blank-measured = DIMLINEAR Ölçü metnini girin (boş = ölçülen değer):
|
||||
|
|
@ -2606,6 +2612,7 @@ properties =
|
|||
.island-detection-style = Ada algılama stili
|
||||
.italic = İtalik
|
||||
.jog-angle = Kırılma Açısı
|
||||
.jogged-radius = Kırıklı Yarıçap
|
||||
.jog-x = Kırılma X
|
||||
.jog-y = Kırılma Y
|
||||
.jog-z = Kırılma Z
|
||||
|
|
|
|||
|
|
@ -48,6 +48,17 @@ impl OpenCADStudio {
|
|||
self.tabs[i].active_cmd = Some(Box::new(new_cmd));
|
||||
}
|
||||
|
||||
"DIMJOGGED" | "DIMJOG" => {
|
||||
use crate::modules::annotate::jogged_radius_dim::JoggedRadiusDimensionCommand;
|
||||
let defaults = crate::scene::creation_style::current_dimension_defaults(
|
||||
&self.tabs[i].scene.document,
|
||||
);
|
||||
let multiplier = self.tabs[i].scene.creation_annotation_multiplier();
|
||||
let new_cmd = JoggedRadiusDimensionCommand::new(defaults, multiplier);
|
||||
self.command_line.push_info(&new_cmd.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(new_cmd));
|
||||
}
|
||||
|
||||
"DIMANGULAR" => {
|
||||
use crate::modules::annotate::angular_dim::AngularDimensionCommand;
|
||||
let new_cmd = AngularDimensionCommand::new();
|
||||
|
|
@ -1293,49 +1304,6 @@ impl OpenCADStudio {
|
|||
self.tabs[i].active_cmd = Some(Box::new(new_cmd));
|
||||
}
|
||||
|
||||
// DIMJOGGED <DJO> — create a jogged radius dimension on the selected
|
||||
// arc/circle: a standard radius dim carrying an OCS_JOGGED XData marker
|
||||
// that the geometry generator renders with a foreshortened zig-zag.
|
||||
"DIMJOGGED" | "DIMJOG" => {
|
||||
use acadrust::entities::{Dimension, DimensionRadius};
|
||||
use acadrust::types::Vector3;
|
||||
use acadrust::xdata::{ExtendedDataRecord, XDataValue};
|
||||
let found =
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.selected_entities()
|
||||
.iter()
|
||||
.find_map(|(_, e)| match e {
|
||||
acadrust::EntityType::Arc(a) => Some((a.center, a.radius)),
|
||||
acadrust::EntityType::Circle(c) => Some((c.center, c.radius)),
|
||||
_ => None,
|
||||
});
|
||||
let Some((center, radius)) = found else {
|
||||
self.command_line
|
||||
.push_error(crate::t!("DIMJOGGED: select an arc or circle first.").as_ref());
|
||||
return None;
|
||||
};
|
||||
if radius <= 0.0 {
|
||||
self.command_line.push_error(crate::t!("DIMJOGGED: invalid radius.").as_ref());
|
||||
return None;
|
||||
}
|
||||
let k = std::f64::consts::FRAC_1_SQRT_2;
|
||||
let arc_point =
|
||||
Vector3::new(center.x + radius * k, center.y + radius * k, center.z);
|
||||
let mut dim = DimensionRadius::new(center, arc_point);
|
||||
dim.base.common.layer = self.tabs[i].active_layer.clone();
|
||||
let mut rec = ExtendedDataRecord::new("OCS_JOGGED");
|
||||
rec.add_value(XDataValue::String("1".to_string()));
|
||||
dim.base.common.extended_data.add_record(rec);
|
||||
self.push_undo_snapshot(i, "DIMJOGGED");
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.add_entity(acadrust::EntityType::Dimension(Dimension::Radius(dim)));
|
||||
self.tabs[i].dirty = true;
|
||||
self.command_line
|
||||
.push_output(crate::t!("DIMJOGGED: created a jogged radius dimension.").as_ref());
|
||||
}
|
||||
|
||||
// ARCTEXT <text> — lay the text out as one Text entity per character
|
||||
// along the selected arc, each rotated to follow the tangent.
|
||||
"ARCTEXT" => {
|
||||
|
|
|
|||
|
|
@ -1031,15 +1031,13 @@ impl OpenCADStudio {
|
|||
if !dim_style_names.is_empty() {
|
||||
// Current style is already shown as text in the geom section;
|
||||
// replace/upgrade it to a Choice if we have a list.
|
||||
if let Some(geom) = sections.last_mut() {
|
||||
// Replace the style name with a choice.
|
||||
if let Some(prop) =
|
||||
geom.props.iter_mut().find(|p| p.field == "style_name")
|
||||
if let Some(prop) = sections
|
||||
.iter_mut()
|
||||
.flat_map(|section| section.props.iter_mut())
|
||||
.find(|property| property.field == "style_name")
|
||||
{
|
||||
let current = match &prop.value {
|
||||
crate::scene::model::object::PropValue::PlainText(s) => {
|
||||
s.clone()
|
||||
}
|
||||
crate::scene::model::object::PropValue::PlainText(s) => s.clone(),
|
||||
_ => String::new(),
|
||||
};
|
||||
prop.value = crate::scene::model::object::PropValue::Choice {
|
||||
|
|
@ -1048,7 +1046,6 @@ impl OpenCADStudio {
|
|||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Append the resolved dimension style's groups
|
||||
// (Lines & Arrows, Text, Fit, Units, Tolerances).
|
||||
|
|
@ -1066,6 +1063,16 @@ impl OpenCADStudio {
|
|||
&self.tabs[i].scene.document,
|
||||
));
|
||||
|
||||
if matches!(d, acadrust::entities::Dimension::LargeRadial(_)) {
|
||||
if let Some(index) = sections
|
||||
.iter()
|
||||
.position(|section| section.title == t!("Misc").as_ref())
|
||||
{
|
||||
let misc = sections.remove(index);
|
||||
sections.push(misc);
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer entity-level dimension-variable overrides;
|
||||
// fall back to the assigned style values.
|
||||
use crate::entities::dim_override as dov;
|
||||
|
|
|
|||
|
|
@ -108,6 +108,52 @@ fn properties(dim: &Dimension) -> Vec<PropSection> {
|
|||
],
|
||||
}];
|
||||
}
|
||||
if let Dimension::LargeRadial(d) = dim {
|
||||
return vec![PropSection {
|
||||
title: t!("Misc").into_owned(),
|
||||
props: vec![
|
||||
Property {
|
||||
label: t!("Dimension style").into_owned(),
|
||||
field: "style_name",
|
||||
value: PropValue::PlainText(d.base.style_name.clone()),
|
||||
},
|
||||
edit(t!("Center X").as_ref(), "definition_x", d.definition_point.x),
|
||||
edit(t!("Center Y").as_ref(), "definition_y", d.definition_point.y),
|
||||
edit(t!("Center Z").as_ref(), "definition_z", d.definition_point.z),
|
||||
edit(t!("Chord X").as_ref(), "chord_x", d.chord_point.x),
|
||||
edit(t!("Chord Y").as_ref(), "chord_y", d.chord_point.y),
|
||||
edit(t!("Chord Z").as_ref(), "chord_z", d.chord_point.z),
|
||||
edit(
|
||||
t!("Override Center X").as_ref(),
|
||||
"override_x",
|
||||
d.override_center.x,
|
||||
),
|
||||
edit(
|
||||
t!("Override Center Y").as_ref(),
|
||||
"override_y",
|
||||
d.override_center.y,
|
||||
),
|
||||
edit(
|
||||
t!("Override Center Z").as_ref(),
|
||||
"override_z",
|
||||
d.override_center.z,
|
||||
),
|
||||
edit(t!("Jog X").as_ref(), "jog_x", d.jog_point.x),
|
||||
edit(t!("Jog Y").as_ref(), "jog_y", d.jog_point.y),
|
||||
edit(t!("Jog Z").as_ref(), "jog_z", d.jog_point.z),
|
||||
edit_angle(
|
||||
t!("Jog Angle").as_ref(),
|
||||
"jog_angle",
|
||||
d.jog_angle.to_degrees(),
|
||||
),
|
||||
ro(
|
||||
t!("Measurement").as_ref(),
|
||||
"measurement",
|
||||
format!("{:.4}", d.measurement()),
|
||||
),
|
||||
],
|
||||
}];
|
||||
}
|
||||
let compact_linear = match dim {
|
||||
Dimension::Linear(d) => Some((
|
||||
&d.base,
|
||||
|
|
@ -281,21 +327,7 @@ fn properties(dim: &Dimension) -> Vec<PropSection> {
|
|||
props.push(edit(t!("Leader 2 Y").as_ref(), "leader2_y", d.second_leader_point.y));
|
||||
props.push(edit(t!("Leader 2 Z").as_ref(), "leader2_z", d.second_leader_point.z));
|
||||
}
|
||||
Dimension::LargeRadial(d) => {
|
||||
props.push(edit(t!("Center X").as_ref(), "definition_x", d.definition_point.x));
|
||||
props.push(edit(t!("Center Y").as_ref(), "definition_y", d.definition_point.y));
|
||||
props.push(edit(t!("Center Z").as_ref(), "definition_z", d.definition_point.z));
|
||||
props.push(edit(t!("Chord X").as_ref(), "chord_x", d.chord_point.x));
|
||||
props.push(edit(t!("Chord Y").as_ref(), "chord_y", d.chord_point.y));
|
||||
props.push(edit(t!("Chord Z").as_ref(), "chord_z", d.chord_point.z));
|
||||
props.push(edit(t!("Override Center X").as_ref(), "override_x", d.override_center.x));
|
||||
props.push(edit(t!("Override Center Y").as_ref(), "override_y", d.override_center.y));
|
||||
props.push(edit(t!("Override Center Z").as_ref(), "override_z", d.override_center.z));
|
||||
props.push(edit(t!("Jog X").as_ref(), "jog_x", d.jog_point.x));
|
||||
props.push(edit(t!("Jog Y").as_ref(), "jog_y", d.jog_point.y));
|
||||
props.push(edit(t!("Jog Z").as_ref(), "jog_z", d.jog_point.z));
|
||||
props.push(edit_angle(t!("Jog Angle").as_ref(), "jog_angle", d.jog_angle.to_degrees()));
|
||||
}
|
||||
Dimension::LargeRadial(_) => unreachable!("handled by compact large-radial properties"),
|
||||
}
|
||||
vec![PropSection {
|
||||
title: t!("Geometry").into_owned(),
|
||||
|
|
@ -1828,7 +1860,7 @@ pub fn style_sections(
|
|||
let linetype = |code, inherited| {
|
||||
linetype_name(document, ov::handle(data, code).unwrap_or(inherited))
|
||||
};
|
||||
let arrow_1 = if matches!(dimension, Dimension::Radius(_)) {
|
||||
let arrow_1 = if matches!(dimension, Dimension::Radius(_) | Dimension::LargeRadial(_)) {
|
||||
let inherited = if s.dimblk1.is_null() { s.dimblk } else { s.dimblk1 };
|
||||
let inherited_name = if s.dimblk1.is_null() {
|
||||
&s.dimblk_name
|
||||
|
|
@ -2530,7 +2562,10 @@ pub fn style_sections(
|
|||
],
|
||||
},
|
||||
];
|
||||
if matches!(dimension, Dimension::Radius(_) | Dimension::Diameter(_)) {
|
||||
if matches!(
|
||||
dimension,
|
||||
Dimension::Radius(_) | Dimension::Diameter(_) | Dimension::LargeRadial(_)
|
||||
) {
|
||||
let dimcen = real(ov::DIMCEN, s.dimcen);
|
||||
let center_type = if dimcen > 1e-12 {
|
||||
"Center marks"
|
||||
|
|
@ -2573,8 +2608,18 @@ pub fn style_sections(
|
|||
"dim_ext_line_ext",
|
||||
"dim_ext_line_offset",
|
||||
];
|
||||
const LARGE_RADIAL_LINE_FIELDS: &[&str] = &[
|
||||
"dim_arrowhead_1",
|
||||
"dim_arrow_size",
|
||||
"dim_line_lineweight",
|
||||
"dim_line_1",
|
||||
"dim_line_color",
|
||||
"dim_linetype",
|
||||
];
|
||||
let retained = if matches!(dimension, Dimension::Diameter(_)) {
|
||||
DIAMETER_LINE_FIELDS
|
||||
} else if matches!(dimension, Dimension::LargeRadial(_)) {
|
||||
LARGE_RADIAL_LINE_FIELDS
|
||||
} else {
|
||||
RADIUS_LINE_FIELDS
|
||||
};
|
||||
|
|
@ -3097,6 +3142,28 @@ fn tessellate_dimension_inner(
|
|||
return wires;
|
||||
}
|
||||
}
|
||||
if let Dimension::LargeRadial(radial) = dim {
|
||||
if let Some((local_radial, normal)) = large_radial_dimension_in_ocs(radial) {
|
||||
let mut wires = tessellate_dimension_inner(
|
||||
document,
|
||||
handle,
|
||||
&Dimension::LargeRadial(local_radial),
|
||||
selected,
|
||||
entity_color,
|
||||
line_weight_px,
|
||||
anno_scale,
|
||||
selected_set,
|
||||
active_viewport,
|
||||
bg_color,
|
||||
None,
|
||||
world_per_pixel,
|
||||
);
|
||||
for wire in &mut wires {
|
||||
map_wire_ocs_to_wcs(wire, normal);
|
||||
}
|
||||
return wires;
|
||||
}
|
||||
}
|
||||
let name = handle.value().to_string();
|
||||
// (Baked-block fast path moved up into scene::tessellate_entity so the
|
||||
// recursive call goes through the LOD ladder, not the kernel path.)
|
||||
|
|
@ -3464,8 +3531,7 @@ fn tessellate_dimension_inner(
|
|||
// DIMUPT governs interactive creation-time text placement; saved
|
||||
// geometry already carries the resulting position.
|
||||
let _ = s.dimupt;
|
||||
// DIMJOGANG is consumed by the jogged-radius path.
|
||||
let _ = s.dimjogang;
|
||||
let _ = (s.dimarcsym, s.dimjogang);
|
||||
// DIMUNIT is the obsolete pre-R2000 linear unit format; DIMLUNIT
|
||||
// supersedes it. Read but not honoured.
|
||||
let _ = s.dimunit;
|
||||
|
|
@ -4345,15 +4411,23 @@ fn dimension_geometry(
|
|||
let override_center = lv(d.override_center);
|
||||
let (near, far) =
|
||||
jogged_radial_break(chord, jog, override_center, d.jog_angle as f32);
|
||||
if !suppress.dim1 {
|
||||
add_segment(&mut g.dim_lines, chord, near);
|
||||
add_segment(&mut g.dim_lines, near, far);
|
||||
add_segment(&mut g.dim_lines, far, override_center);
|
||||
}
|
||||
append_arrow(
|
||||
&mut g,
|
||||
chord,
|
||||
normalized_or(near - chord, Vec3::X),
|
||||
arrow1,
|
||||
);
|
||||
append_center_mark(
|
||||
&mut g,
|
||||
lv(d.definition_point),
|
||||
params.dimcen,
|
||||
(chord - lv(d.definition_point)).length(),
|
||||
);
|
||||
}
|
||||
}
|
||||
g
|
||||
|
|
@ -4789,6 +4863,43 @@ pub(crate) fn arc_dimension_in_ocs(
|
|||
Some((local, normal))
|
||||
}
|
||||
|
||||
pub(crate) fn large_radial_dimension_in_ocs(
|
||||
dimension: &DimensionLargeRadial,
|
||||
) -> Option<(DimensionLargeRadial, Vector3)> {
|
||||
let length = dimension.base.normal.length();
|
||||
if !length.is_finite() || length <= 1.0e-12 {
|
||||
return None;
|
||||
}
|
||||
let normal = dimension.base.normal / length;
|
||||
if (normal - Vector3::UNIT_Z).length() <= 1.0e-12 {
|
||||
return None;
|
||||
}
|
||||
let normal_tuple = (normal.x, normal.y, normal.z);
|
||||
let to_ocs = |point: Vector3| {
|
||||
let point = crate::scene::view::transform::wcs_point_to_ocs(
|
||||
(point.x, point.y, point.z),
|
||||
normal_tuple,
|
||||
);
|
||||
Vector3::new(point.0, point.1, point.2)
|
||||
};
|
||||
let mut local = dimension.clone();
|
||||
local.definition_point = to_ocs(dimension.definition_point);
|
||||
let elevation = local.definition_point.z;
|
||||
let on_plane = |point: Vector3| {
|
||||
let mut point = to_ocs(point);
|
||||
point.z = elevation;
|
||||
point
|
||||
};
|
||||
local.chord_point = on_plane(dimension.chord_point);
|
||||
local.override_center = on_plane(dimension.override_center);
|
||||
local.jog_point = on_plane(dimension.jog_point);
|
||||
local.base.definition_point = local.definition_point;
|
||||
local.base.text_middle_point = on_plane(dimension.base.text_middle_point);
|
||||
local.base.insertion_point = on_plane(dimension.base.insertion_point);
|
||||
local.base.normal = Vector3::UNIT_Z;
|
||||
Some((local, normal))
|
||||
}
|
||||
|
||||
fn map_wire_ocs_to_wcs(wire: &mut WireModel, normal: Vector3) {
|
||||
let normal_tuple = (normal.x, normal.y, normal.z);
|
||||
let map = |x: f64, y: f64, z: f64| {
|
||||
|
|
|
|||
|
|
@ -767,6 +767,12 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
|
|||
"DIMJOGGED: created a jogged radius dimension." => Some(("annotate", "dimjogged-created-a-jogged-radius-dimension")),
|
||||
"DIMJOGGED: invalid radius." => Some(("annotate", "dimjogged-invalid-radius")),
|
||||
"DIMJOGGED: select an arc or circle first." => Some(("annotate", "dimjogged-select-an-arc-or-circle-first")),
|
||||
"DIMJOGGED Enter dimension text (blank = measured value):" => Some(("annotate", "dimjogged-enter-dimension-text-blank-measured")),
|
||||
"DIMJOGGED Select arc, circle, or polyline arc:" => Some(("annotate", "dimjogged-select-arc-circle-or-polyline-arc")),
|
||||
"DIMJOGGED Specify center location override:" => Some(("annotate", "dimjogged-specify-center-location-override")),
|
||||
"DIMJOGGED Specify dimension line location [Mtext/Text/Angle]:" => Some(("annotate", "dimjogged-specify-dimension-line-location-text")),
|
||||
"DIMJOGGED Specify jog location:" => Some(("annotate", "dimjogged-specify-jog-location")),
|
||||
"DIMJOGGED Specify text angle (degrees):" => Some(("annotate", "dimjogged-specify-text-angle-degrees")),
|
||||
"DIMJOGLINE Select linear or aligned dimension:" => Some(("annotate", "dimjogline-select-linear-or-aligned-dimension")),
|
||||
"DIMJOGLINE Specify jog location:" => Some(("annotate", "dimjogline-specify-jog-location")),
|
||||
"DIMJOGLINE: not yet implemented — nothing changed." => Some(("common", "dimjogline-not-yet-implemented-nothing-changed")),
|
||||
|
|
@ -1298,6 +1304,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
|
|||
"JUSTIFYTEXT: updated {n} text object(s)." => Some(("annotate", "justifytext-updated-n-text-object-s")),
|
||||
"Jog Angle" => Some(("properties", "jog-angle")),
|
||||
"Jog Line" => Some(("annotate", "jog-line")),
|
||||
"Jogged Radius" => Some(("common", "jogged-radius")),
|
||||
"Jog X" => Some(("properties", "jog-x")),
|
||||
"Jog Y" => Some(("properties", "jog-y")),
|
||||
"Jog Z" => Some(("properties", "jog-z")),
|
||||
|
|
|
|||
479
src/modules/annotate/jogged_radius_dim.rs
Normal file
479
src/modules/annotate/jogged_radius_dim.rs
Normal file
|
|
@ -0,0 +1,479 @@
|
|||
use acadrust::entities::{Dimension, DimensionLargeRadial};
|
||||
use acadrust::types::{Handle, Vector3};
|
||||
use acadrust::EntityType;
|
||||
use glam::{DVec3, Vec3};
|
||||
|
||||
use crate::command::{
|
||||
CadCommand, CmdOption, CmdResult, DimensionAssociationInput, DimensionAssociationSource,
|
||||
WorkingPlane,
|
||||
};
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
use crate::scene::creation_style::DimensionCreationDefaults;
|
||||
use crate::scene::dimension_assoc::RadialSourceGeometry;
|
||||
use crate::scene::model::wire_model::WireModel;
|
||||
use crate::t;
|
||||
|
||||
pub const ICON: IconKind = IconKind::Svg(include_bytes!("../../../assets/icons/dim_jog.svg"));
|
||||
|
||||
pub fn tool() -> ToolDef {
|
||||
ToolDef {
|
||||
id: "DIMJOGGED",
|
||||
label: "Jogged Radius",
|
||||
icon: ICON,
|
||||
event: ModuleEvent::Command("DIMJOGGED".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Step {
|
||||
SelectObject,
|
||||
OverrideCenter(RadialSourceGeometry),
|
||||
DimLine {
|
||||
source: RadialSourceGeometry,
|
||||
override_center: DVec3,
|
||||
},
|
||||
Jog {
|
||||
source: RadialSourceGeometry,
|
||||
override_center: DVec3,
|
||||
chord: DVec3,
|
||||
text_position: DVec3,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct JoggedRadiusDimensionCommand {
|
||||
step: Step,
|
||||
defaults: DimensionCreationDefaults,
|
||||
editor_height: f64,
|
||||
text_override: Option<String>,
|
||||
text_angle: Option<f64>,
|
||||
awaiting_text: bool,
|
||||
awaiting_angle: bool,
|
||||
picked_entity: Option<EntityType>,
|
||||
source_handle: Option<Handle>,
|
||||
}
|
||||
|
||||
impl JoggedRadiusDimensionCommand {
|
||||
pub fn new(defaults: DimensionCreationDefaults, annotation_multiplier: f64) -> Self {
|
||||
let display_scale = if defaults.annotative {
|
||||
annotation_multiplier.max(f64::EPSILON)
|
||||
} else {
|
||||
defaults.scale
|
||||
};
|
||||
let editor_height = defaults.text_height * display_scale;
|
||||
Self {
|
||||
step: Step::SelectObject,
|
||||
defaults,
|
||||
editor_height,
|
||||
text_override: None,
|
||||
text_angle: None,
|
||||
awaiting_text: false,
|
||||
awaiting_angle: false,
|
||||
picked_entity: None,
|
||||
source_handle: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn editor_anchor(&self) -> DVec3 {
|
||||
match self.step {
|
||||
Step::SelectObject => DVec3::ZERO,
|
||||
Step::OverrideCenter(source) => dvec(source.point_at_angle(source.start_angle)),
|
||||
Step::DimLine {
|
||||
override_center, ..
|
||||
}
|
||||
| Step::Jog {
|
||||
override_center, ..
|
||||
} => override_center,
|
||||
}
|
||||
}
|
||||
|
||||
fn commit_dimension(
|
||||
&self,
|
||||
source: RadialSourceGeometry,
|
||||
override_center_world: DVec3,
|
||||
chord_world: DVec3,
|
||||
text_world: DVec3,
|
||||
jog_world: DVec3,
|
||||
) -> CmdResult {
|
||||
let plane = source_plane(source);
|
||||
let center = plane.to_local(dvec(source.center_world()));
|
||||
let chord = plane.to_local(chord_world);
|
||||
let override_center = plane.to_local(override_center_world);
|
||||
let jog = project_jog(override_center, chord, plane.to_local(jog_world));
|
||||
let text_position = plane.to_local(text_world);
|
||||
|
||||
let mut dimension = DimensionLargeRadial::default();
|
||||
dimension.definition_point = v3(center);
|
||||
dimension.base.definition_point = v3(center);
|
||||
dimension.chord_point = v3(chord);
|
||||
dimension.override_center = v3(override_center);
|
||||
dimension.jog_point = v3(jog);
|
||||
dimension.jog_angle = self.defaults.jog_angle;
|
||||
dimension.base.style_name.clone_from(&self.defaults.style_name);
|
||||
dimension.base.text_middle_point = v3(text_position);
|
||||
dimension.base.insertion_point = v3(text_position);
|
||||
dimension.base.text_user_positioned = true;
|
||||
dimension.base.actual_measurement = dimension.measurement();
|
||||
crate::entities::dimension::set_dimension_text_override(
|
||||
&mut dimension.base,
|
||||
self.text_override.clone(),
|
||||
);
|
||||
if let Some(angle) = self.text_angle {
|
||||
dimension.base.text_rotation = angle;
|
||||
}
|
||||
|
||||
let association = self.source_handle.map_or_else(
|
||||
|| DimensionAssociationInput::Explicit(Vec::new()),
|
||||
|handle| {
|
||||
DimensionAssociationInput::Explicit(vec![Some(
|
||||
DimensionAssociationSource::explicit(
|
||||
handle,
|
||||
source.marker,
|
||||
source.angle_at(chord_world.to_array()),
|
||||
),
|
||||
)])
|
||||
},
|
||||
);
|
||||
|
||||
CmdResult::CommitDimension {
|
||||
entity: plane.place_entity(EntityType::Dimension(Dimension::LargeRadial(
|
||||
dimension,
|
||||
))),
|
||||
association,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CadCommand for JoggedRadiusDimensionCommand {
|
||||
fn set_working_plane(&mut self, _plane: WorkingPlane) {}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"DIMJOGGED"
|
||||
}
|
||||
|
||||
fn prompt(&self) -> String {
|
||||
if self.awaiting_text {
|
||||
return t!("DIMJOGGED Enter dimension text (blank = measured value):").into_owned();
|
||||
}
|
||||
if self.awaiting_angle {
|
||||
return t!("DIMJOGGED Specify text angle (degrees):").into_owned();
|
||||
}
|
||||
match self.step {
|
||||
Step::SelectObject => {
|
||||
t!("DIMJOGGED Select arc, circle, or polyline arc:").into_owned()
|
||||
}
|
||||
Step::OverrideCenter(_) => {
|
||||
t!("DIMJOGGED Specify center location override:").into_owned()
|
||||
}
|
||||
Step::DimLine { .. } => t!(
|
||||
"DIMJOGGED Specify dimension line location [Mtext/Text/Angle]:"
|
||||
)
|
||||
.into_owned(),
|
||||
Step::Jog { .. } => t!("DIMJOGGED Specify jog location:").into_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
fn on_point(&mut self, point: DVec3) -> CmdResult {
|
||||
match self.step {
|
||||
Step::SelectObject => CmdResult::NeedPoint,
|
||||
Step::OverrideCenter(source) => {
|
||||
self.step = Step::DimLine {
|
||||
source,
|
||||
override_center: point,
|
||||
};
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
Step::DimLine {
|
||||
source,
|
||||
override_center,
|
||||
} => {
|
||||
self.step = Step::Jog {
|
||||
source,
|
||||
override_center,
|
||||
chord: dvec(source.chord_at(point.to_array())),
|
||||
text_position: point,
|
||||
};
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
Step::Jog {
|
||||
source,
|
||||
override_center,
|
||||
chord,
|
||||
text_position,
|
||||
} => self.commit_dimension(
|
||||
source,
|
||||
override_center,
|
||||
chord,
|
||||
text_position,
|
||||
point,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn on_enter(&mut self) -> CmdResult {
|
||||
if self.awaiting_text {
|
||||
self.awaiting_text = false;
|
||||
return CmdResult::NeedPoint;
|
||||
}
|
||||
if self.awaiting_angle {
|
||||
self.awaiting_angle = false;
|
||||
return CmdResult::NeedPoint;
|
||||
}
|
||||
CmdResult::Cancel
|
||||
}
|
||||
|
||||
fn on_escape(&mut self) -> CmdResult {
|
||||
CmdResult::Cancel
|
||||
}
|
||||
|
||||
fn wants_text_input(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn point_step_accepts_keywords(&self) -> bool {
|
||||
!self.awaiting_text && !self.awaiting_angle
|
||||
}
|
||||
|
||||
fn wants_text_with_spaces(&self) -> bool {
|
||||
self.awaiting_text
|
||||
}
|
||||
|
||||
fn options(&self) -> Vec<CmdOption> {
|
||||
if matches!(self.step, Step::DimLine { .. })
|
||||
&& !self.awaiting_text
|
||||
&& !self.awaiting_angle
|
||||
{
|
||||
vec![
|
||||
CmdOption::new("MText", "MTEXT"),
|
||||
CmdOption::new("Text", "TEXT"),
|
||||
CmdOption::new("Angle", "ANGLE"),
|
||||
]
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
|
||||
if self.awaiting_text {
|
||||
let value = text.trim();
|
||||
self.text_override = if value.is_empty() || value == "<>" {
|
||||
None
|
||||
} else {
|
||||
Some(value.to_string())
|
||||
};
|
||||
self.awaiting_text = false;
|
||||
return Some(CmdResult::NeedPoint);
|
||||
}
|
||||
if self.awaiting_angle {
|
||||
let value = text.trim();
|
||||
self.text_angle = if value.is_empty() {
|
||||
None
|
||||
} else {
|
||||
crate::entities::common::parse_typed_angle(value)
|
||||
};
|
||||
self.awaiting_angle = false;
|
||||
return Some(CmdResult::NeedPoint);
|
||||
}
|
||||
if !matches!(self.step, Step::DimLine { .. }) {
|
||||
return None;
|
||||
}
|
||||
match text.trim().to_ascii_uppercase().as_str() {
|
||||
"T" | "TEXT" => {
|
||||
self.awaiting_text = true;
|
||||
Some(CmdResult::NeedPoint)
|
||||
}
|
||||
"M" | "MTEXT" => Some(CmdResult::SuspendForMTextInput {
|
||||
pos: self.editor_anchor(),
|
||||
initial: self.text_override.clone().unwrap_or_default(),
|
||||
height: self.editor_height,
|
||||
}),
|
||||
"A" | "ANGLE" => {
|
||||
self.awaiting_angle = true;
|
||||
Some(CmdResult::NeedPoint)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn on_editor_text(&mut self, value: String) {
|
||||
let value = value.trim();
|
||||
self.text_override = if value.is_empty() || value == "<>" {
|
||||
None
|
||||
} else {
|
||||
Some(value.to_string())
|
||||
};
|
||||
}
|
||||
|
||||
fn on_editor_closed(&mut self, _committed: bool) -> CmdResult {
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
|
||||
fn needs_entity_pick(&self) -> bool {
|
||||
matches!(self.step, Step::SelectObject)
|
||||
}
|
||||
|
||||
fn entity_pick_highlights_hover(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn inject_before_entity_pick(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn inject_picked_entity(&mut self, entity: EntityType) {
|
||||
self.picked_entity = Some(entity);
|
||||
}
|
||||
|
||||
fn on_entity_pick(&mut self, handle: Handle, point: DVec3) -> CmdResult {
|
||||
let Some(entity) = self.picked_entity.take() else {
|
||||
return CmdResult::NeedPoint;
|
||||
};
|
||||
let Some(source) = crate::scene::dimension_assoc::radial_source_at(
|
||||
&entity,
|
||||
Vector3::new(point.x, point.y, point.z),
|
||||
) else {
|
||||
return CmdResult::NeedPoint;
|
||||
};
|
||||
if !source.radius.is_finite() || source.radius <= 1e-12 {
|
||||
return CmdResult::NeedPoint;
|
||||
}
|
||||
self.source_handle = Some(handle);
|
||||
self.step = Step::OverrideCenter(source);
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
|
||||
fn on_mouse_move(&mut self, point: DVec3) -> Option<WireModel> {
|
||||
match self.step {
|
||||
Step::SelectObject => None,
|
||||
Step::OverrideCenter(source) => Some(preview_wire(vec![
|
||||
dvec(source.center_world()).as_vec3(),
|
||||
point.as_vec3(),
|
||||
])),
|
||||
Step::DimLine {
|
||||
source,
|
||||
override_center,
|
||||
} => {
|
||||
let chord = dvec(source.chord_at(point.to_array()));
|
||||
Some(preview_wire(vec![
|
||||
override_center.as_vec3(),
|
||||
chord.as_vec3(),
|
||||
Vec3::splat(f32::NAN),
|
||||
chord.as_vec3(),
|
||||
point.as_vec3(),
|
||||
]))
|
||||
}
|
||||
Step::Jog {
|
||||
source,
|
||||
override_center,
|
||||
chord,
|
||||
..
|
||||
} => {
|
||||
let plane = source_plane(source);
|
||||
let chord_local = plane.to_local(chord);
|
||||
let override_local = plane.to_local(override_center);
|
||||
let jog_local = project_jog(override_local, chord_local, plane.to_local(point));
|
||||
let (near, far) = jog_break(
|
||||
chord_local,
|
||||
jog_local,
|
||||
override_local,
|
||||
self.defaults.jog_angle,
|
||||
);
|
||||
Some(preview_wire(
|
||||
[chord_local, near, far, override_local]
|
||||
.into_iter()
|
||||
.map(|position| plane.to_world(position).as_vec3())
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn source_plane(source: RadialSourceGeometry) -> WorkingPlane {
|
||||
WorkingPlane::new(
|
||||
DVec3::from_array(source.plane.origin),
|
||||
DVec3::from_array(source.plane.x_axis),
|
||||
DVec3::from_array(source.plane.y_axis),
|
||||
)
|
||||
}
|
||||
|
||||
fn project_jog(override_center: DVec3, chord: DVec3, point: DVec3) -> DVec3 {
|
||||
let line = chord - override_center;
|
||||
let length_squared = line.length_squared();
|
||||
if length_squared <= 1e-18 {
|
||||
return override_center;
|
||||
}
|
||||
let factor = ((point - override_center).dot(line) / length_squared).clamp(0.0, 1.0);
|
||||
override_center + line * factor
|
||||
}
|
||||
|
||||
fn jog_break(
|
||||
chord: DVec3,
|
||||
jog: DVec3,
|
||||
override_center: DVec3,
|
||||
jog_angle: f64,
|
||||
) -> (DVec3, DVec3) {
|
||||
let radial = (chord - override_center).normalize_or_zero();
|
||||
let (sin, cos) = jog_angle.sin_cos();
|
||||
let transverse = DVec3::new(
|
||||
radial.x * cos - radial.y * sin,
|
||||
radial.x * sin + radial.y * cos,
|
||||
0.0,
|
||||
)
|
||||
.normalize_or_zero();
|
||||
let half = ((chord - override_center).length() * 0.04).max(1e-3);
|
||||
let first = jog - transverse * half;
|
||||
let second = jog + transverse * half;
|
||||
if chord.distance_squared(first) <= chord.distance_squared(second) {
|
||||
(first, second)
|
||||
} else {
|
||||
(second, first)
|
||||
}
|
||||
}
|
||||
|
||||
fn v3(point: DVec3) -> Vector3 {
|
||||
Vector3::new(point.x, point.y, point.z)
|
||||
}
|
||||
|
||||
fn dvec(point: Vector3) -> DVec3 {
|
||||
DVec3::new(point.x, point.y, point.z)
|
||||
}
|
||||
|
||||
fn preview_wire(points: Vec<Vec3>) -> WireModel {
|
||||
WireModel {
|
||||
point_marker: None,
|
||||
taper_widths: Vec::new(),
|
||||
pattern_stations: Vec::new(),
|
||||
world_width: 0.0,
|
||||
depth_override: None,
|
||||
display_visible: true,
|
||||
plot_visible: true,
|
||||
fill_is_3d: false,
|
||||
fill_is_2d_solid: false,
|
||||
render_instance: None,
|
||||
pick_tris: Vec::new(),
|
||||
pick_tris_low: Vec::new(),
|
||||
dash_from_start: false,
|
||||
dash_align_end: None,
|
||||
text_verts: Vec::new(),
|
||||
name: "dimjogged_preview".to_string(),
|
||||
points: points.into_iter().map(|point| point.to_array()).collect(),
|
||||
points_low: Vec::new(),
|
||||
color: WireModel::CYAN,
|
||||
selected: false,
|
||||
pattern_length: 0.0,
|
||||
pattern: [0.0; 8],
|
||||
line_weight_px: 1.0,
|
||||
snap_pts: Vec::new(),
|
||||
tangent_geoms: Vec::new(),
|
||||
aci: 0,
|
||||
key_vertices: Vec::new(),
|
||||
aabb: WireModel::UNBOUNDED_AABB,
|
||||
plinegen: true,
|
||||
fill_tris: Vec::new(),
|
||||
fill_tris_low: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
inventory::submit!(crate::command::CommandRegistration {
|
||||
names: &["DIMJOGGED", "DIMJOG"]
|
||||
});
|
||||
|
|
@ -16,6 +16,7 @@ pub mod dimspace;
|
|||
pub mod dimtedit;
|
||||
pub mod leader_cmd;
|
||||
pub mod linear_dim;
|
||||
pub mod jogged_radius_dim;
|
||||
pub mod mleader_cmd;
|
||||
pub mod mleader_edit;
|
||||
pub mod mtext;
|
||||
|
|
@ -109,6 +110,11 @@ impl CadModule for AnnotateModule {
|
|||
radius_dim::tool().label,
|
||||
radius_dim::tool().icon,
|
||||
),
|
||||
(
|
||||
jogged_radius_dim::tool().id,
|
||||
jogged_radius_dim::tool().label,
|
||||
jogged_radius_dim::tool().icon,
|
||||
),
|
||||
(
|
||||
diameter_dim::tool().id,
|
||||
diameter_dim::tool().label,
|
||||
|
|
|
|||
|
|
@ -927,6 +927,24 @@ fn explode_dimension(dim: &Dimension, doc: &CadDocument) -> Vec<EntityType> {
|
|||
.collect();
|
||||
}
|
||||
}
|
||||
if let Dimension::LargeRadial(radial) = dim {
|
||||
if let Some((local_radial, normal)) =
|
||||
crate::entities::dimension::large_radial_dimension_in_ocs(radial)
|
||||
{
|
||||
let (x_axis, y_axis) = crate::scene::view::transform::ocs_axes((
|
||||
normal.x, normal.y, normal.z,
|
||||
));
|
||||
let plane = WorkingPlane::new(
|
||||
DVec3::ZERO,
|
||||
DVec3::new(x_axis.0, x_axis.1, x_axis.2),
|
||||
DVec3::new(y_axis.0, y_axis.1, y_axis.2),
|
||||
);
|
||||
return explode_dimension(&Dimension::LargeRadial(local_radial), doc)
|
||||
.into_iter()
|
||||
.map(|entity| plane.place_entity(entity))
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
|
||||
let base = dim.base();
|
||||
let met = dim_metrics(dim, doc);
|
||||
|
|
@ -1235,9 +1253,11 @@ fn explode_dimension(dim: &Dimension, doc: &CadDocument) -> Vec<EntityType> {
|
|||
d.override_center,
|
||||
d.jog_angle,
|
||||
);
|
||||
if !met.dimsd1 {
|
||||
result.push(make_seg(&d.chord_point, &near, &dim_c));
|
||||
result.push(make_seg(&near, &far, &dim_c));
|
||||
result.push(make_seg(&far, &d.override_center, &dim_c));
|
||||
}
|
||||
let len = ((near.x - d.chord_point.x).powi(2)
|
||||
+ (near.y - d.chord_point.y).powi(2))
|
||||
.sqrt()
|
||||
|
|
@ -1249,6 +1269,15 @@ fn explode_dimension(dim: &Dimension, doc: &CadDocument) -> Vec<EntityType> {
|
|||
&met.arrow1,
|
||||
&dim_c,
|
||||
));
|
||||
let radius = ((d.definition_point.x - d.chord_point.x).powi(2)
|
||||
+ (d.definition_point.y - d.chord_point.y).powi(2))
|
||||
.sqrt();
|
||||
result.extend(dim_center_mark(
|
||||
d.definition_point,
|
||||
met.dimcen,
|
||||
radius,
|
||||
&dim_c,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ pub struct DimensionCreationDefaults {
|
|||
pub text_height: f64,
|
||||
pub gap: f64,
|
||||
pub arrow_size: f64,
|
||||
pub jog_angle: f64,
|
||||
pub scale: f64,
|
||||
pub annotative: bool,
|
||||
}
|
||||
|
|
@ -92,6 +93,9 @@ pub fn current_dimension_defaults(doc: &CadDocument) -> DimensionCreationDefault
|
|||
text_height: style.as_ref().map_or(2.5, |style| style.dimtxt),
|
||||
gap: style.as_ref().map_or(0.625, |style| style.dimgap),
|
||||
arrow_size: style.as_ref().map_or(2.5, |style| style.dimasz),
|
||||
jog_angle: style
|
||||
.as_ref()
|
||||
.map_or(std::f64::consts::FRAC_PI_4, |style| style.dimjogang),
|
||||
scale: style.as_ref().map_or(1.0, |style| {
|
||||
if style.annotative {
|
||||
1.0
|
||||
|
|
|
|||
|
|
@ -559,6 +559,7 @@ pub(crate) fn radial_extension_points(
|
|||
let target_point = match dimension_entity {
|
||||
Dimension::Radius(radius) => radius.definition_point,
|
||||
Dimension::Diameter(diameter) => diameter.angle_vertex,
|
||||
Dimension::LargeRadial(radial) => radial.chord_point,
|
||||
_ => return None,
|
||||
};
|
||||
let association = document.objects.values().find_map(|object| {
|
||||
|
|
@ -655,6 +656,11 @@ impl Scene {
|
|||
diameter.measurement() * 0.5,
|
||||
diameter.angle_vertex,
|
||||
)),
|
||||
Dimension::LargeRadial(radial) => Some((
|
||||
radial.definition_point,
|
||||
radial.measurement(),
|
||||
radial.chord_point,
|
||||
)),
|
||||
_ => None,
|
||||
};
|
||||
if let Some((center, measured_radius, chord)) = radial_data {
|
||||
|
|
@ -810,6 +816,11 @@ impl Scene {
|
|||
diameter.measurement() * 0.5,
|
||||
diameter.angle_vertex,
|
||||
)),
|
||||
Dimension::LargeRadial(radial) => Some((
|
||||
radial.definition_point,
|
||||
radial.measurement(),
|
||||
radial.chord_point,
|
||||
)),
|
||||
_ => None,
|
||||
};
|
||||
if let Some((center, radius, chord)) = radial_data {
|
||||
|
|
@ -1003,6 +1014,33 @@ impl Scene {
|
|||
}
|
||||
diameter.base.actual_measurement = diameter.measurement();
|
||||
}
|
||||
Dimension::LargeRadial(radial) => {
|
||||
let Some((source, angle)) = radial_source else {
|
||||
continue;
|
||||
};
|
||||
let old_center = radial.definition_point;
|
||||
let new_center = source.center_world();
|
||||
let new_chord = source.point_at_angle(angle);
|
||||
let center_delta = Vector3::new(
|
||||
new_center.x - old_center.x,
|
||||
new_center.y - old_center.y,
|
||||
new_center.z - old_center.z,
|
||||
);
|
||||
radial.definition_point = new_center;
|
||||
radial.base.definition_point = new_center;
|
||||
radial.chord_point = new_chord;
|
||||
if point_distance_squared(center_delta, Vector3::default()) > 1e-18 {
|
||||
radial.override_center = radial.override_center + center_delta;
|
||||
radial.jog_point = radial.jog_point + center_delta;
|
||||
if radial.base.text_user_positioned {
|
||||
radial.base.text_middle_point =
|
||||
radial.base.text_middle_point + center_delta;
|
||||
radial.base.insertion_point =
|
||||
radial.base.insertion_point + center_delta;
|
||||
}
|
||||
}
|
||||
radial.base.actual_measurement = radial.measurement();
|
||||
}
|
||||
Dimension::Ordinate(ordinate) => {
|
||||
if let Some(feature) = resolved[0] {
|
||||
ordinate.feature_location = feature;
|
||||
|
|
@ -1098,7 +1136,6 @@ impl Scene {
|
|||
}
|
||||
arc.base.actual_measurement = arc.measurement();
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
dimension.base_mut().actual_measurement = dimension.measurement();
|
||||
refreshed.push((association.dimension, ChangeKind::Modified));
|
||||
|
|
|
|||
Loading…
Reference in a new issue