diff --git a/src/app/visibility.rs b/src/app/visibility.rs index 7854f9e8e..9a8ca32ab 100644 --- a/src/app/visibility.rs +++ b/src/app/visibility.rs @@ -221,7 +221,21 @@ impl OpenCADStudio { .then(|| { view.rows .iter() - .position(|r| r.iter().zip(&values).all(|(a, b)| (a - b).abs() <= 1e-9)) + .position(|row| { + row.iter().zip(&values).zip(&view.columns).all( + |((row_value, value), column)| { + let difference = if column + .connection_name + .eq_ignore_ascii_case("UpdatedAngle") + { + crate::scene::block_actions::angle_distance(*row_value, *value) + } else { + (row_value - value).abs() + }; + difference <= 1e-9 + }, + ) + }) }) .flatten(); self.tabs[i].selected_grips.push(GripDef { diff --git a/src/scene/block_actions.rs b/src/scene/block_actions.rs index bc69b209b..14bf80956 100644 --- a/src/scene/block_actions.rs +++ b/src/scene/block_actions.rs @@ -11,6 +11,14 @@ use glam::DVec3; pub(crate) mod instance; mod representation; mod stretch; + +/// Smallest signed distance between two angles in radians, accounting for the +/// wrap at ±π. Used for BPT rotation snapping and current-row detection. +pub(crate) fn angle_distance(a: f64, b: f64) -> f64 { + ((a - b + std::f64::consts::PI).rem_euclid(std::f64::consts::TAU) + - std::f64::consts::PI) + .abs() +} #[cfg(test)] mod tests; @@ -1097,9 +1105,8 @@ fn evaluate_impl( .iter() .filter_map(|row| row.get(col).copied()) .min_by(|a, b| { - (a - angle) - .abs() - .total_cmp(&(b - angle).abs()) + angle_distance(*a, angle) + .total_cmp(&angle_distance(*b, angle)) .then_with(|| a.total_cmp(b)) }) { diff --git a/src/scene/block_actions/tests.rs b/src/scene/block_actions/tests.rs index 09edd01a1..04d61af69 100644 --- a/src/scene/block_actions/tests.rs +++ b/src/scene/block_actions/tests.rs @@ -3,6 +3,14 @@ use crate::scene::{block_distance_parameter as distance, block_point_parameter a use codec::{DwgReader, DwgWriter, DxfReader, DxfWriter}; use std::io::Cursor; +#[test] +fn rotation_table_angles_match_across_pi_wrap() { + let near_positive_pi = std::f64::consts::PI - 0.01; + let near_negative_pi = -std::f64::consts::PI + 0.01; + assert!((super::angle_distance(near_positive_pi, near_negative_pi) - 0.02).abs() < 1e-12); + assert!(super::angle_distance(near_positive_pi, 0.0) > 3.0); +} + fn fixture() -> (CadDocument, Handle, Vec) { let mut scene = Scene::new(); scene.define_block_raw(