forked from 1b-agent/opencadstudio-upstream
Merge pull request #1320 from ghost/styled-dimension-preview
This commit is contained in:
commit
79bc800728
23 files changed
+724
-138
No files matched your search
+119
-14
@@ -2,7 +2,7 @@
|
||||
//! supplies a viewport scale; sheet-only dimensions retain paper units.
|
||||
|
||||
use super::OpenCADStudio;
|
||||
use crate::command::DimensionAssociationSource;
|
||||
use crate::command::{DimensionAssociationSource, DimensionPreview};
|
||||
use crate::entities::dim_override;
|
||||
use crate::scene::viewport_ref::{AcceptedSnap, MeasurementScale, SnapSourceRef, ViewportFrame};
|
||||
use acadrust::entities::Dimension;
|
||||
@@ -27,12 +27,25 @@ impl OpenCADStudio {
|
||||
}
|
||||
|
||||
pub(crate) fn dimension_measure_space(&self, i: usize) -> DimensionMeasureSpace {
|
||||
self.dimension_measure_space_with_candidate(i, None)
|
||||
}
|
||||
|
||||
fn dimension_measure_space_with_candidate(
|
||||
&self,
|
||||
i: usize,
|
||||
candidate: Option<ViewportFrame>,
|
||||
) -> DimensionMeasureSpace {
|
||||
let scene = &self.tabs[i].scene;
|
||||
if scene.current_layout == "Model" || scene.active_viewport.is_some() {
|
||||
return DimensionMeasureSpace::Direct;
|
||||
}
|
||||
let mut frame: Option<ViewportFrame> = None;
|
||||
for f in self.accepted_snaps().iter().filter_map(|snap| snap.frame) {
|
||||
for f in self
|
||||
.accepted_snaps()
|
||||
.iter()
|
||||
.filter_map(|snap| snap.frame)
|
||||
.chain(candidate)
|
||||
{
|
||||
match frame {
|
||||
None => frame = Some(f),
|
||||
Some(previous) if previous.viewport == f.viewport => {}
|
||||
@@ -122,13 +135,10 @@ impl OpenCADStudio {
|
||||
i: usize,
|
||||
entity: &mut EntityType,
|
||||
) -> bool {
|
||||
let EntityType::Dimension(dimension) = entity else {
|
||||
if !matches!(entity, EntityType::Dimension(_)) {
|
||||
return true;
|
||||
};
|
||||
let angular = matches!(
|
||||
dimension,
|
||||
Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_)
|
||||
);
|
||||
}
|
||||
let angular = is_angular_dimension(entity);
|
||||
let frame = match self.dimension_measure_space(i) {
|
||||
DimensionMeasureSpace::Direct => return true,
|
||||
DimensionMeasureSpace::ConflictingViewports => {
|
||||
@@ -140,18 +150,106 @@ impl OpenCADStudio {
|
||||
if angular {
|
||||
return true;
|
||||
}
|
||||
let Some(scale) = self.viewport_dimension_scale(i, entity, frame) else {
|
||||
return false;
|
||||
};
|
||||
// Owner is needed even by DIMASSOC=0's explode path, before insertion.
|
||||
entity.common_mut().owner_handle = self.tabs[i].scene.current_layout_block_handle_pub();
|
||||
scale.write_to_entity(entity);
|
||||
true
|
||||
}
|
||||
|
||||
fn viewport_dimension_scale(
|
||||
&self,
|
||||
i: usize,
|
||||
entity: &EntityType,
|
||||
frame: ViewportFrame,
|
||||
) -> Option<MeasurementScale> {
|
||||
let dimlfac = self.pending_dimension_style_dimlfac(i, entity);
|
||||
let scale = MeasurementScale {
|
||||
user_lfac: MeasurementScale::user_lfac_for_space(dimlfac, true),
|
||||
viewport_compensation: frame.paper_to_model_length_factor(),
|
||||
};
|
||||
if !scale.paper_factor().is_finite() || scale.paper_factor() <= 0.0 {
|
||||
return false;
|
||||
(scale.paper_factor().is_finite() && scale.paper_factor() > 0.0).then_some(scale)
|
||||
}
|
||||
|
||||
/// Styled dimensions for the placement preview at `cursor`, carrying the
|
||||
/// same style and viewport measurement the commit path would apply.
|
||||
/// `None` when the active command has no committable dimension at this
|
||||
/// stage; an empty list when the candidate geometry or scale is invalid.
|
||||
pub(crate) fn dimension_preview_entities(
|
||||
&self,
|
||||
i: usize,
|
||||
cursor: DVec3,
|
||||
) -> Option<Vec<EntityType>> {
|
||||
let command = self.tabs[i].active_cmd.as_ref()?;
|
||||
let previews = command.dimension_preview(cursor)?;
|
||||
let scene = &self.tabs[i].scene;
|
||||
let measure_space = if command.measures_through_viewports() {
|
||||
// The hovered model snap supplies a provisional viewport only while
|
||||
// the second definition point is still being acquired.
|
||||
let candidate = if command.dimension_placement_pending() {
|
||||
None
|
||||
} else {
|
||||
self.vp_snap_frame.filter(|frame| {
|
||||
self.tabs[i]
|
||||
.snap_result
|
||||
.is_some_and(|hit| hit.viewport == Some(frame.viewport))
|
||||
})
|
||||
};
|
||||
self.dimension_measure_space_with_candidate(i, candidate)
|
||||
} else {
|
||||
DimensionMeasureSpace::Direct
|
||||
};
|
||||
if matches!(measure_space, DimensionMeasureSpace::ConflictingViewports) {
|
||||
return Some(Vec::new());
|
||||
}
|
||||
// Owner is needed even by DIMASSOC=0's explode path, before insertion.
|
||||
entity.common_mut().owner_handle = self.tabs[i].scene.current_layout_block_handle_pub();
|
||||
scale.write_to_entity(entity);
|
||||
true
|
||||
let mut entities = Vec::with_capacity(previews.len());
|
||||
for DimensionPreview {
|
||||
mut entity,
|
||||
preserve_base_style,
|
||||
} in previews
|
||||
{
|
||||
if !preserve_base_style {
|
||||
crate::scene::creation_style::apply_current_creation_styles(
|
||||
&scene.document,
|
||||
&mut entity,
|
||||
);
|
||||
}
|
||||
entity.common_mut().owner_handle = scene.current_layout_block_handle_pub();
|
||||
if let DimensionMeasureSpace::Viewport(frame) = measure_space {
|
||||
if !is_angular_dimension(&entity) {
|
||||
let Some(scale) = self.viewport_dimension_scale(i, &entity, frame) else {
|
||||
return Some(Vec::new());
|
||||
};
|
||||
scale.write_to_entity(&mut entity);
|
||||
}
|
||||
}
|
||||
entities.push(entity);
|
||||
}
|
||||
Some(entities)
|
||||
}
|
||||
|
||||
pub(crate) fn dimension_preview_wires(
|
||||
&self,
|
||||
i: usize,
|
||||
cursor: DVec3,
|
||||
) -> Option<Vec<crate::scene::WireModel>> {
|
||||
let entities = self.dimension_preview_entities(i, cursor)?;
|
||||
// Degenerate geometry, an invalid scale, or conflicting viewports
|
||||
// produce no styled dimension. Returning None lets the command's
|
||||
// plain rubber-band preview run, which shows no value to mistrust.
|
||||
if entities.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let mut wires = self.tabs[i].scene.wires_for_entities(&entities);
|
||||
for wire in &mut wires {
|
||||
wire.color = crate::scene::WireModel::CYAN;
|
||||
for vertex in &mut wire.text_verts {
|
||||
vertex.color = crate::scene::WireModel::CYAN;
|
||||
}
|
||||
}
|
||||
Some(wires)
|
||||
}
|
||||
|
||||
pub(crate) fn try_dimension_viewport_entity_pick(
|
||||
@@ -254,3 +352,10 @@ impl OpenCADStudio {
|
||||
.bump_entities(&[(dimension, crate::scene::ChangeKind::Modified)]);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_angular_dimension(entity: &EntityType) -> bool {
|
||||
matches!(
|
||||
entity,
|
||||
EntityType::Dimension(Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_))
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
//! Styled placement previews must show the text and geometry the command
|
||||
//! commits at the same stage. Viewport measurement cases live in
|
||||
//! `viewport_dimension_tests`; these cover the remaining creation commands
|
||||
//! in model space, style inheritance, batches, and degenerate stages.
|
||||
|
||||
use super::viewport_dimension_tests::preview_text as text;
|
||||
use super::OpenCADStudio;
|
||||
use crate::command::StepInput;
|
||||
use acadrust::entities::{Arc, Circle, Line};
|
||||
use acadrust::types::{Handle, Vector3};
|
||||
use acadrust::EntityType;
|
||||
use glam::DVec3;
|
||||
|
||||
fn app() -> (OpenCADStudio, usize) {
|
||||
let mut app = OpenCADStudio::new_for_test();
|
||||
app.automation_op(r#"{"op":"new"}"#);
|
||||
let i = app.active_tab;
|
||||
(app, i)
|
||||
}
|
||||
|
||||
fn style_name(entity: &EntityType) -> String {
|
||||
let EntityType::Dimension(dimension) = entity else {
|
||||
panic!("expected dimension")
|
||||
};
|
||||
dimension.base().style_name.clone()
|
||||
}
|
||||
|
||||
fn committed(app: &OpenCADStudio) -> Vec<EntityType> {
|
||||
app.tabs[app.active_tab]
|
||||
.scene
|
||||
.document
|
||||
.entities()
|
||||
.filter(|entity| matches!(entity, EntityType::Dimension(_)))
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Styled preview entities at `cursor`, asserting they also tessellate.
|
||||
fn preview(app: &OpenCADStudio, i: usize, cursor: DVec3) -> Vec<EntityType> {
|
||||
let entities = app.dimension_preview_entities(i, cursor).unwrap();
|
||||
assert!(!entities.is_empty(), "no styled preview at {cursor}");
|
||||
assert!(!app.dimension_preview_wires(i, cursor).unwrap().is_empty());
|
||||
entities
|
||||
}
|
||||
|
||||
fn commit_and_compare(app: &mut OpenCADStudio, i: usize, cursor: DVec3) -> EntityType {
|
||||
let previewed = preview(app, i, cursor);
|
||||
assert_eq!(previewed.len(), 1);
|
||||
let before = committed(app).len();
|
||||
let _ = app.feed_command(StepInput::Point(cursor));
|
||||
let after = committed(app);
|
||||
assert_eq!(after.len(), before + 1, "commit did not add one dimension");
|
||||
let entity = after.last().unwrap().clone();
|
||||
assert_eq!(text(app, &entity), text(app, &previewed[0]));
|
||||
assert_eq!(style_name(&entity), style_name(&previewed[0]));
|
||||
entity
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordinate_preview_matches_commit() {
|
||||
let (mut app, i) = app();
|
||||
let _ = app.dispatch_command("DIMORDINATE");
|
||||
assert!(app.dimension_preview_entities(i, DVec3::ZERO).is_none());
|
||||
let _ = app.feed_command(StepInput::Point(DVec3::new(12.5, 40.0, 0.0)));
|
||||
let entity = commit_and_compare(&mut app, i, DVec3::new(12.5, 90.0, 0.0));
|
||||
assert_eq!(text(&app, &entity), "12.5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arc_length_preview_matches_commit_for_full_and_partial_arcs() {
|
||||
let (mut app, i) = app();
|
||||
let mut arc = Arc::new();
|
||||
arc.center = Vector3::ZERO;
|
||||
arc.radius = 50.0;
|
||||
arc.start_angle = 0.0;
|
||||
arc.end_angle = std::f64::consts::FRAC_PI_2;
|
||||
let handle = app.tabs[i].scene.add_entity(EntityType::Arc(arc));
|
||||
let on_arc = |degrees: f64| {
|
||||
let radians = degrees.to_radians();
|
||||
DVec3::new(50.0 * radians.cos(), 50.0 * radians.sin(), 0.0)
|
||||
};
|
||||
|
||||
let _ = app.dispatch_command("DIMARC");
|
||||
let _ = app.feed_command(StepInput::EntityPick(handle, on_arc(45.0)));
|
||||
let full = commit_and_compare(&mut app, i, DVec3::new(60.0, 60.0, 0.0));
|
||||
|
||||
let _ = app.dispatch_command("DIMARC");
|
||||
let _ = app.feed_command(StepInput::EntityPick(handle, on_arc(45.0)));
|
||||
let _ = app.feed_command(StepInput::Text("P".into()));
|
||||
let _ = app.feed_command(StepInput::Point(on_arc(10.0)));
|
||||
// While the second partial point is acquired the command has no
|
||||
// committable dimension; the plain arc preview stays in charge.
|
||||
assert!(app.dimension_preview_entities(i, on_arc(80.0)).is_none());
|
||||
let _ = app.feed_command(StepInput::Point(on_arc(80.0)));
|
||||
let partial = commit_and_compare(&mut app, i, DVec3::new(60.0, 60.0, 0.0));
|
||||
assert_ne!(text(&app, &full), text(&app, &partial));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn jogged_radius_preview_matches_commit_at_text_and_jog_stages() {
|
||||
let (mut app, i) = app();
|
||||
let mut circle = Circle::new();
|
||||
circle.center = Vector3::ZERO;
|
||||
circle.radius = 100.0;
|
||||
let handle = app.tabs[i].scene.add_entity(EntityType::Circle(circle));
|
||||
let _ = app.dispatch_command("DIMJOGGED");
|
||||
let _ = app.feed_command(StepInput::EntityPick(handle, DVec3::new(100.0, 0.0, 0.0)));
|
||||
assert!(app
|
||||
.dimension_preview_entities(i, DVec3::new(30.0, 0.0, 0.0))
|
||||
.is_none());
|
||||
let _ = app.feed_command(StepInput::Point(DVec3::new(30.0, 0.0, 0.0)));
|
||||
let text_position = DVec3::new(150.0, 40.0, 0.0);
|
||||
let staged = preview(&app, i, text_position);
|
||||
assert_eq!(staged.len(), 1);
|
||||
let _ = app.feed_command(StepInput::Point(text_position));
|
||||
let entity = commit_and_compare(&mut app, i, DVec3::new(90.0, 20.0, 0.0));
|
||||
assert_eq!(text(&app, &entity), text(&app, &staged[0]));
|
||||
assert_eq!(text(&app, &entity), "R100");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn angular_three_point_preview_matches_commit() {
|
||||
let (mut app, i) = app();
|
||||
let _ = app.dispatch_command("DIMANGULAR");
|
||||
let _ = app.feed_command(StepInput::Point(DVec3::ZERO));
|
||||
let _ = app.feed_command(StepInput::Point(DVec3::new(100.0, 0.0, 0.0)));
|
||||
assert!(app
|
||||
.dimension_preview_entities(i, DVec3::new(0.0, 100.0, 0.0))
|
||||
.is_none());
|
||||
let _ = app.feed_command(StepInput::Point(DVec3::new(0.0, 100.0, 0.0)));
|
||||
let entity = commit_and_compare(&mut app, i, DVec3::new(70.0, 70.0, 0.0));
|
||||
assert_eq!(text(&app, &entity), "90°");
|
||||
}
|
||||
|
||||
fn place_linear(app: &mut OpenCADStudio, first: DVec3, second: DVec3, line: DVec3) -> Handle {
|
||||
let _ = app.dispatch_command("DIMLINEAR");
|
||||
let _ = app.feed_command(StepInput::Point(first));
|
||||
let _ = app.feed_command(StepInput::Point(second));
|
||||
let _ = app.feed_command(StepInput::Point(line));
|
||||
committed(app).last().unwrap().common().handle
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn continue_and_baseline_previews_follow_style_inheritance() {
|
||||
let (mut app, i) = app();
|
||||
let default_style = app.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.header
|
||||
.current_dimstyle_name
|
||||
.clone();
|
||||
let mut style = acadrust::tables::DimStyle::new("Inherit");
|
||||
style.dimlfac = 2.0;
|
||||
app.tabs[i].scene.document.dim_styles.add(style).unwrap();
|
||||
app.tabs[i].scene.document.header.current_dimstyle_name = "Inherit".into();
|
||||
let base = place_linear(
|
||||
&mut app,
|
||||
DVec3::ZERO,
|
||||
DVec3::new(100.0, 0.0, 0.0),
|
||||
DVec3::new(50.0, -20.0, 0.0),
|
||||
);
|
||||
assert_eq!(text(&app, committed(&app).last().unwrap()), "200");
|
||||
app.tabs[i].scene.document.header.current_dimstyle_name = default_style;
|
||||
|
||||
// DIMCONTINUEMODE=1 keeps the base dimension's style in the preview.
|
||||
app.dimension_continue_mode = 1;
|
||||
app.tabs[i].scene.last_created_dimension = Some(base);
|
||||
let _ = app.dispatch_command("DIMCONTINUE");
|
||||
let inherited = commit_and_compare(&mut app, i, DVec3::new(250.0, 0.0, 0.0));
|
||||
assert_eq!(style_name(&inherited), "Inherit");
|
||||
assert_eq!(text(&app, &inherited), "300");
|
||||
|
||||
// DIMCONTINUEMODE=0 runs the current creation defaults over the built
|
||||
// dimension instead; preview and commit must still agree.
|
||||
app.dimension_continue_mode = 0;
|
||||
app.tabs[i].scene.last_created_dimension = Some(inherited.common().handle);
|
||||
let _ = app.dispatch_command("DIMCONTINUE");
|
||||
commit_and_compare(&mut app, i, DVec3::new(350.0, 0.0, 0.0));
|
||||
|
||||
app.dimension_continue_mode = 1;
|
||||
app.tabs[i].scene.last_created_dimension = Some(base);
|
||||
let _ = app.dispatch_command("DIMBASELINE");
|
||||
let baseline = commit_and_compare(&mut app, i, DVec3::new(300.0, 0.0, 0.0));
|
||||
assert_eq!(style_name(&baseline), "Inherit");
|
||||
assert_eq!(text(&app, &baseline), "600");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn qdim_preview_matches_the_committed_batch() {
|
||||
let (mut app, i) = app();
|
||||
let segments = [(0.0, 40.0), (40.0, 100.0), (100.0, 130.0)];
|
||||
for (start, end) in segments {
|
||||
let line = Line::from_points(Vector3::new(start, 0.0, 0.0), Vector3::new(end, 0.0, 0.0));
|
||||
let handle = app.tabs[i].scene.add_entity(EntityType::Line(line));
|
||||
app.tabs[i].scene.select_entity(handle, false);
|
||||
}
|
||||
let _ = app.dispatch_command("QDIM");
|
||||
let cursor = DVec3::new(60.0, 40.0, 0.0);
|
||||
let previewed = preview(&app, i, cursor);
|
||||
assert_eq!(previewed.len(), segments.len());
|
||||
let mut preview_texts: Vec<String> = previewed.iter().map(|e| text(&app, e)).collect();
|
||||
let _ = app.feed_command(StepInput::Point(cursor));
|
||||
let mut committed_texts: Vec<String> = committed(&app).iter().map(|e| text(&app, e)).collect();
|
||||
preview_texts.sort();
|
||||
committed_texts.sort();
|
||||
assert_eq!(committed_texts, preview_texts);
|
||||
assert_eq!(committed_texts, ["30", "40", "60"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn degenerate_linear_preview_defers_to_plain_rubber_band() {
|
||||
let (mut app, i) = app();
|
||||
let _ = app.dispatch_command("DIMLINEAR");
|
||||
assert!(app.dimension_preview_entities(i, DVec3::ZERO).is_none());
|
||||
let _ = app.feed_command(StepInput::Point(DVec3::ZERO));
|
||||
assert!(app
|
||||
.dimension_preview_entities(i, DVec3::ZERO)
|
||||
.is_some_and(|entities| entities.is_empty()));
|
||||
assert!(app.dimension_preview_wires(i, DVec3::ZERO).is_none());
|
||||
assert!(committed(&app).is_empty());
|
||||
let cursor = DVec3::new(80.0, 0.0, 0.0);
|
||||
let styled = preview(&app, i, cursor);
|
||||
assert_eq!(text(&app, &styled[0]), "80");
|
||||
assert!(committed(&app).is_empty(), "hover must not commit");
|
||||
}
|
||||
@@ -13,6 +13,8 @@ pub(crate) mod commands;
|
||||
pub(crate) mod dim_viewport;
|
||||
#[cfg(test)]
|
||||
mod viewport_dimension_tests;
|
||||
#[cfg(test)]
|
||||
mod dimension_preview_tests;
|
||||
mod document;
|
||||
mod drafting_settings;
|
||||
pub(crate) mod expr_eval;
|
||||
|
||||
@@ -2547,6 +2547,8 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
p
|
||||
} else if let Some(wires) = self.dimension_preview_wires(i, effective) {
|
||||
wires
|
||||
} else {
|
||||
self.tabs[i]
|
||||
.active_cmd
|
||||
|
||||
@@ -87,6 +87,14 @@ fn displayed(doc: &CadDocument) -> f64 {
|
||||
dim.measurement() * MeasurementScale::user_lfac_for_space(factor, true)
|
||||
}
|
||||
|
||||
pub(super) fn preview_text(app: &OpenCADStudio, entity: &EntityType) -> String {
|
||||
let EntityType::Dimension(dimension) = entity else { panic!("expected dimension") };
|
||||
let doc = &app.tabs[app.active_tab].scene.document;
|
||||
let source = doc.dim_styles.get(&dimension.base().style_name).unwrap();
|
||||
let style = crate::entities::dimension::resolved_dimension_style(source, dimension, doc);
|
||||
crate::entities::dimension::dimension_text_value(dimension, Some(&style)).unwrap()
|
||||
}
|
||||
|
||||
fn finish_aligned(app: &mut OpenCADStudio, line: Handle, frame: ViewportFrame) {
|
||||
let _ = app.dispatch_command("DIMALIGNED");
|
||||
point(app, frame, line, DVec3::ZERO);
|
||||
@@ -300,7 +308,13 @@ fn viewport_dimension_linear_aligned_and_radial_object_picks() {
|
||||
if radial { 1 } else { 2 },
|
||||
"{name}"
|
||||
);
|
||||
let _ = app.feed_command(StepInput::Point(DVec3::new(55.0, 80.0, 0.0)));
|
||||
let place = DVec3::new(55.0, 80.0, 0.0);
|
||||
let preview = app.dimension_preview_entities(i, place).unwrap();
|
||||
assert_eq!(preview.len(), 1, "{name}");
|
||||
let value = preview_text(&app, &preview[0]);
|
||||
assert!(!app.dimension_preview_wires(i, place).unwrap().is_empty(), "{name}");
|
||||
let _ = app.feed_command(StepInput::Point(place));
|
||||
assert_eq!(preview_text(&app, &EntityType::Dimension(dimension(&app.tabs[i].scene.document).clone())), value, "{name}");
|
||||
assert!(
|
||||
(displayed(&app.tabs[i].scene.document) - expected).abs() < 1e-4,
|
||||
"{name}: {}",
|
||||
@@ -326,12 +340,45 @@ fn viewport_dimension_angular_preserves_angle_without_length_factor() {
|
||||
point(&mut app, frame, line, DVec3::ZERO);
|
||||
point(&mut app, frame, line, DVec3::X * 100.0);
|
||||
point(&mut app, frame, vertical, DVec3::Y * 100.0);
|
||||
let _ = app.feed_command(StepInput::Point(DVec3::new(70.0, 70.0, 0.0)));
|
||||
let place = DVec3::new(70.0, 70.0, 0.0);
|
||||
let preview = app.dimension_preview_entities(i, place).unwrap();
|
||||
assert_eq!(preview.len(), 1);
|
||||
assert!(MeasurementScale::read(&preview[0].common().extended_data).is_none());
|
||||
let value = preview_text(&app, &preview[0]);
|
||||
let _ = app.feed_command(StepInput::Point(place));
|
||||
let doc = &app.tabs[app.active_tab].scene.document;
|
||||
assert_eq!(preview_text(&app, &EntityType::Dimension(dimension(doc).clone())), value);
|
||||
assert!((dimension(doc).measurement() - 90.0).abs() < 1e-5);
|
||||
assert!(MeasurementScale::read(&dimension(doc).base().common.extended_data).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn viewport_dimension_preview_uses_candidate_scale_only_before_second_pick() {
|
||||
for command in ["DIMLINEAR", "DIMALIGNED"] {
|
||||
let (mut app, model, frame) = fixture();
|
||||
let i = app.active_tab;
|
||||
let mut style = acadrust::tables::DimStyle::new("PreviewUnits");
|
||||
style.dimlfac = 25.4;
|
||||
app.tabs[i].scene.document.dim_styles.add(style).unwrap();
|
||||
app.tabs[i].scene.document.header.current_dimstyle_name = "PreviewUnits".into();
|
||||
let _ = app.dispatch_command(command);
|
||||
let _ = app.feed_command(StepInput::Point(DVec3::new(55.0, 50.0, 0.0)));
|
||||
let target = hit(frame, model, DVec3::X * 100.0);
|
||||
let sheet = app.dimension_preview_entities(i, target.world).unwrap();
|
||||
assert_eq!(preview_text(&app, &sheet[0]), "127");
|
||||
app.vp_snap_frame = Some(frame);
|
||||
app.tabs[i].snap_result = Some(target);
|
||||
let model_preview = app.dimension_preview_entities(i, target.world).unwrap();
|
||||
assert_eq!(preview_text(&app, &model_preview[0]), "1270");
|
||||
point(&mut app, frame, model, DVec3::X * 100.0);
|
||||
let other = ViewportFrame { viewport: Handle::new(0xFFFF), scale: frame.scale * 2.0, ..frame };
|
||||
app.vp_snap_frame = Some(other);
|
||||
app.tabs[i].snap_result = Some(hit(other, model, DVec3::X * 100.0));
|
||||
let placement = app.dimension_preview_entities(i, DVec3::new(60.0, 80.0, 0.0)).unwrap();
|
||||
assert_eq!(preview_text(&app, &placement[0]), "1270");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn viewport_dimension_snap_query_matches_pan_scale_and_twist() {
|
||||
for (height, twist, target) in [
|
||||
|
||||
Reference in new issue
Block a user