diff --git a/Cargo.lock b/Cargo.lock index 3df83216f..df1179392 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -921,7 +921,7 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cadkernel" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=35aa7a5#35aa7a541ab7c020cd23f43978373337523e25df" +source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=7e43598#7e435984d9ba32999d2471930c18449a2ab58d67" dependencies = [ "acadrust", "cavalier_contours", @@ -932,7 +932,7 @@ dependencies = [ [[package]] name = "cadkernel-constraints" version = "0.1.0" -source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=35aa7a5#35aa7a541ab7c020cd23f43978373337523e25df" +source = "git+https://github.com/HakanSeven12/cadkernel.git?rev=7e43598#7e435984d9ba32999d2471930c18449a2ab58d67" dependencies = [ "nalgebra", ] diff --git a/Cargo.toml b/Cargo.toml index fb9fbd71d..055fe4598 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,8 +34,8 @@ clap = { version = "4", features = ["derive", "string"] } env_logger = "0.11" log = "0.4" acadrust = { git = "https://github.com/HakanSeven12/cadcodec.git", rev = "8a28c21", features = ["serde"] } -cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "35aa7a5", features = ["acis", "offset"] } -cadkernel-constraints = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "35aa7a5" } +cadkernel = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "7e43598", features = ["acis", "offset"] } +cadkernel-constraints = { git = "https://github.com/HakanSeven12/cadkernel.git", rev = "7e43598" } dwg-thumbnailer = { path = "crates/dwg-thumbnailer" } flate2 = "1" image = { version = "0.25", default-features = false, features = ["png", "jpeg", "bmp", "tiff"] } diff --git a/src/app/command_driver.rs b/src/app/command_driver.rs index c3e5b0763..f5dab062d 100644 --- a/src/app/command_driver.rs +++ b/src/app/command_driver.rs @@ -3266,62 +3266,6 @@ impl OpenCADStudio { self.tabs[i] .scene .record_undo_parametric_constraints_before(scope, constraints_before); - if first.entity != second.entity { - use crate::scene::parametric_constraints::directional_reference_endpoints; - - let fixed_axis = self.tabs[i] - .scene - .document - .get_entity(first.entity) - .and_then(|entity| directional_reference_endpoints(entity, first)); - let moving_axis = self.tabs[i] - .scene - .document - .get_entity(second.entity) - .and_then(|entity| directional_reference_endpoints(entity, second)); - if let (Some([fixed_start, fixed_end]), Some([moving_start, moving_end])) = - (fixed_axis, moving_axis) - { - let fixed_direction = fixed_end - fixed_start; - let moving_direction = moving_end - moving_start; - if fixed_direction.length_squared() > 1.0e-24 - && moving_direction.length_squared() > 1.0e-24 - { - let fixed_angle = fixed_direction.y.atan2(fixed_direction.x); - let moving_angle = moving_direction.y.atan2(moving_direction.x); - let normalize = |angle: f64| { - (angle + std::f64::consts::PI) - .rem_euclid(std::f64::consts::TAU) - - std::f64::consts::PI - }; - let positive = normalize( - fixed_angle + std::f64::consts::FRAC_PI_2 - moving_angle, - ); - let negative = normalize( - fixed_angle - std::f64::consts::FRAC_PI_2 - moving_angle, - ); - let angle_rad = if positive.abs() <= negative.abs() { - positive - } else { - negative - }; - if angle_rad.abs() > 1.0e-12 { - self.tabs[i].scene.transform_entities( - &[second.entity], - &crate::command::EntityTransform::Rotate { - center: glam::DVec3::new( - moving_start.x, - moving_start.y, - moving_start.z, - ), - axis: glam::DVec3::Z, - angle_rad, - }, - ); - } - } - } - } let id = self.tabs[i].scene.parametric_constraint_set_mut(scope).add( ConstraintKind::Perpendicular, refs, @@ -3336,7 +3280,7 @@ impl OpenCADStudio { .into_iter() .map(|handle| (handle, crate::scene::ChangeKind::Modified)) .collect::>(); - self.tabs[i].scene.bump_entities_with_parametric_policy( + self.tabs[i].scene.bump_entities_with_initial_parametric_policy( &changes, &[first_fixed, second_start], true, @@ -8506,6 +8450,40 @@ mod parametric_constraint_undo_tests { ); } + #[test] + fn perpendicular_initial_solve_rotates_parallel_second_line_in_kernel() { + let mut app = OpenCADStudio::new_for_test(); + let _ = app.automation_op(r#"{"op":"new"}"#); + let first = add_line(&mut app, 0.0, 0.0, 10.0, 0.0); + let second = add_line(&mut app, 20.0, 0.0, 30.0, 0.0); + + let _ = app.apply_cmd_result(CmdResult::AddPerpendicularConstraint { + first: ParametricRef::whole(first), + second: ParametricRef::whole(second), + first_fixed: ParametricRef::whole(first), + second_start: ParametricRef::point(second, 0), + label: "Perpendicular constraint", + }); + + let line = |handle| match app.tabs[app.active_tab].scene.document.get_entity(handle) { + Some(acadrust::EntityType::Line(line)) => line.clone(), + other => panic!("expected a Line, got {other:?}"), + }; + let fixed = line(first); + let moving = line(second); + assert_eq!(fixed.start, acadrust::types::Vector3::new(0.0, 0.0, 0.0)); + assert_eq!(fixed.end, acadrust::types::Vector3::new(10.0, 0.0, 0.0)); + assert!((moving.start - acadrust::types::Vector3::new(20.0, 0.0, 0.0)).length() < 1.0e-9); + assert!((moving.length() - 10.0).abs() < 1.0e-7); + assert!( + (fixed.end - fixed.start) + .dot(&(moving.end - moving.start)) + .abs() + < 1.0e-7, + "fixed={fixed:?}, moving={moving:?}" + ); + } + /// Drawing commands must not create parametric constraints implicitly. #[test] fn drawing_a_line_onto_an_existing_endpoint_does_not_add_a_constraint() { diff --git a/src/modules/parametric/perpendicular.rs b/src/modules/parametric/perpendicular.rs index 8621e64ce..0bdd8a247 100644 --- a/src/modules/parametric/perpendicular.rs +++ b/src/modules/parametric/perpendicular.rs @@ -234,4 +234,26 @@ mod tests { assert_eq!(first_fixed, ParametricRef::whole(first)); assert_eq!(second_start, ParametricRef::point(second, 0)); } + + #[test] + fn preselection_uses_the_first_straight_polyline_segment() { + let handle = Handle::new(11); + let mut polyline = acadrust::entities::LwPolyline::new(); + polyline.vertices = vec![ + acadrust::entities::LwVertex::with_bulge( + acadrust::types::Vector2::new(0.0, 0.0), + 1.0, + ), + acadrust::entities::LwVertex::from_coords(4.0, 0.0), + acadrust::entities::LwVertex::from_coords(8.0, 0.0), + ]; + + let pick = PerpendicularConstraintCommand::preselected_reference( + &EntityType::LwPolyline(polyline), + handle, + ) + .expect("straight segment"); + assert_eq!(pick.reference, ParametricRef::segment(handle, 1)); + assert_eq!(pick.start_reference, ParametricRef::point(handle, 1)); + } } diff --git a/src/scene/parametric_constraints.rs b/src/scene/parametric_constraints.rs index f6b1363fd..467f8d779 100644 --- a/src/scene/parametric_constraints.rs +++ b/src/scene/parametric_constraints.rs @@ -186,33 +186,6 @@ pub(crate) fn directional_axis_endpoints( } } -/// Finite endpoints used to orient a line-like constraint reference. -pub(crate) fn directional_reference_endpoints( - entity: &acadrust::EntityType, - reference: ParametricRef, -) -> Option<[Vector3; 2]> { - if reference.directional_axis().is_some() { - return directional_axis_endpoints(entity, reference); - } - match entity { - acadrust::EntityType::Line(line) if reference.marker.is_none() => { - Some([line.start, line.end]) - } - acadrust::EntityType::LwPolyline(_) | acadrust::EntityType::Polyline2D(_) => { - let index = reference.segment_index()?; - let points = super::dimension_assoc::source_points(entity); - let start = *points.get(index)?; - let end = if let Some(end) = points.get(index + 1) { - *end - } else { - *points.first()? - }; - Some([start, end]) - } - _ => None, - } -} - /// Grabbed points are exact kernel inputs; the solver anchors the remaining /// endpoint coordinates according to the line's directional constraints. pub(crate) fn grip_solve_anchor_refs(