From 3274d6d0fd60212584be9ef71b2c44fa2da4202d Mon Sep 17 00:00:00 2001 From: Christopher Overbeck Date: Tue, 15 Sep 2026 14:51:58 -0500 Subject: [PATCH] Validate viewport object picks and cover angular arc acquisition --- docs/viewport-dimensions.md | 2 ++ src/app/viewport_dimension_tests.rs | 46 ++++++++++++++++++++++++++++- src/scene/viewport_dim_seam.rs | 6 ++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/docs/viewport-dimensions.md b/docs/viewport-dimensions.md index 09f85208c..119b2361a 100644 --- a/docs/viewport-dimensions.md +++ b/docs/viewport-dimensions.md @@ -11,6 +11,8 @@ Snapping and object picking share viewport draw order, visibility, and clipping rules. Object picking uses the resident interaction index and applies block instance transforms. Nonuniformly transformed circles and circular arcs are declined as radial object picks because their displayed geometry is elliptical. +Array inserts without an addressable instance index are also declined; resolved +block geometry must remain within the original pick aperture. ## Input and measurement rules diff --git a/src/app/viewport_dimension_tests.rs b/src/app/viewport_dimension_tests.rs index 5ac9cb658..3b47db064 100644 --- a/src/app/viewport_dimension_tests.rs +++ b/src/app/viewport_dimension_tests.rs @@ -239,11 +239,20 @@ fn viewport_dimension_linear_aligned_and_radial_object_picks() { #[test] fn viewport_dimension_angular_preserves_angle_without_length_factor() { let (mut app, line, frame) = fixture(); + let i = app.active_tab; + app.tabs[i].scene.set_current_layout("Model".into()); + let vertical = app.tabs[i] + .scene + .add_entity(EntityType::Line(Line::from_points( + Vector3::ZERO, + Vector3::new(0.0, 100.0, 0.0), + ))); + app.tabs[i].scene.set_current_layout("Dimensions".into()); let _ = app.dispatch_command("DIMANGULAR"); let _ = app.feed_command(StepInput::Enter); point(&mut app, frame, line, DVec3::ZERO); point(&mut app, frame, line, DVec3::X * 100.0); - point(&mut app, frame, line, DVec3::Y * 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 doc = &app.tabs[app.active_tab].scene.document; assert!((dimension(doc).measurement() - 90.0).abs() < 1e-5); @@ -377,3 +386,38 @@ fn viewport_dimension_exploded_commit_uses_compensated_text_and_undo() { .entities() .any(|e| matches!(e, EntityType::Text(_) | EntityType::MText(_)))); } + +#[test] +fn viewport_dimension_angular_object_picks_measure_arc_features() { + use acadrust::entities::{Arc, LwPolyline}; + use acadrust::types::Vector2; + for bulged in [false, true] { + let (mut app, _, frame) = fixture(); + let i = app.active_tab; + app.tabs[i].scene.set_current_layout("Model".into()); + let entity = if bulged { + let mut poly = + LwPolyline::from_points(vec![Vector2::new(100.0, 200.0), Vector2::new(0.0, 300.0)]); + poly.vertices[0].bulge = (std::f64::consts::PI / 8.0).tan(); + EntityType::LwPolyline(poly) + } else { + let mut arc = Arc::new(); + arc.center = Vector3::new(0.0, 200.0, 0.0); + arc.radius = 100.0; + arc.start_angle = 0.0; + arc.end_angle = std::f64::consts::FRAC_PI_2; + EntityType::Arc(arc) + }; + app.tabs[i].scene.add_entity(entity); + app.tabs[i].scene.set_current_layout("Dimensions".into()); + let _ = app.dispatch_command("DIMANGULAR"); + let model = DVec3::new(100.0 / 2.0_f64.sqrt(), 200.0 + 100.0 / 2.0_f64.sqrt(), 0.0); + let result = app + .try_dimension_viewport_entity_pick(i, frame.model_to_paper(model), 0.5) + .unwrap(); + let _ = app.apply_cmd_result(result); + assert_eq!(app.accepted_snaps().len(), 3); + let _ = app.feed_command(StepInput::Point(DVec3::new(65.0, 85.0, 0.0))); + assert!((displayed(&app.tabs[i].scene.document) - 90.0).abs() < 1e-5); + } +} diff --git a/src/scene/viewport_dim_seam.rs b/src/scene/viewport_dim_seam.rs index 1954d240a..5f4ca3ce4 100644 --- a/src/scene/viewport_dim_seam.rs +++ b/src/scene/viewport_dim_seam.rs @@ -84,6 +84,9 @@ impl Scene { continue; }; + if !planar_pick_distance(&entity, model_point).is_some_and(|d| d <= aperture_model) { + continue; + } let mut paper_entity = entity; crate::scene::view::dispatch::apply_transform( &mut paper_entity, @@ -212,6 +215,9 @@ impl Scene { let EntityType::Insert(insert) = &insert_entity else { return None; }; + if insert.row_count > 1 || insert.column_count > 1 { + return None; + } let insert_handle = insert.common.handle; let local = crate::scene::render_graph::insert_transform(&self.document, insert); let combined = local.then(&outer);