From b1f6819754eb22f98c4d3ec56949e70136a51673 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 1 Feb 2023 13:02:35 +0100 Subject: [PATCH 1/4] Make test a bit more robust --- crates/fj-math/src/plane.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fj-math/src/plane.rs b/crates/fj-math/src/plane.rs index 9e0a4a7d5..63df5fb05 100644 --- a/crates/fj-math/src/plane.rs +++ b/crates/fj-math/src/plane.rs @@ -103,7 +103,7 @@ mod tests { #[test] fn project_vector() { let plane = - Plane::from_parametric([0., 0., 0.], [1., 0., 0.], [0., 1., 0.]); + Plane::from_parametric([1., 1., 1.], [1., 0., 0.], [0., 1., 0.]); assert_eq!(plane.project_vector([1., 0., 1.]), Vector::from([1., 0.])); assert_eq!(plane.project_vector([0., 1., 1.]), Vector::from([0., 1.])); From 2b89c6784d80c7d280ba777a2fe8ca3fcdb6e36f Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 1 Feb 2023 13:09:28 +0100 Subject: [PATCH 2/4] Add `Plane::project_point` --- crates/fj-math/src/plane.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/fj-math/src/plane.rs b/crates/fj-math/src/plane.rs index 63df5fb05..957671167 100644 --- a/crates/fj-math/src/plane.rs +++ b/crates/fj-math/src/plane.rs @@ -65,6 +65,13 @@ impl Plane { self.normal().dot(vector) == Scalar::ZERO } + /// Project a point into the plane + pub fn project_point(&self, point: impl Into>) -> Point<2> { + let origin_to_point = point.into() - self.origin(); + let coords = self.project_vector(origin_to_point); + Point { coords } + } + /// Project a vector into the plane pub fn project_vector(&self, vector: impl Into>) -> Vector<2> { let vector = vector.into(); @@ -98,7 +105,16 @@ impl Plane { #[cfg(test)] mod tests { - use crate::{Plane, Vector}; + use crate::{Plane, Point, Vector}; + + #[test] + fn project_point() { + let plane = + Plane::from_parametric([1., 1., 1.], [1., 0., 0.], [0., 1., 0.]); + + assert_eq!(plane.project_point([2., 1., 2.]), Point::from([1., 0.])); + assert_eq!(plane.project_point([1., 2., 2.]), Point::from([0., 1.])); + } #[test] fn project_vector() { From 0c83922ab2cab2938a87cc6433676bc2a1964658 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 1 Feb 2023 13:10:12 +0100 Subject: [PATCH 3/4] Refactor --- crates/fj-math/src/plane.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/crates/fj-math/src/plane.rs b/crates/fj-math/src/plane.rs index 957671167..6191735f8 100644 --- a/crates/fj-math/src/plane.rs +++ b/crates/fj-math/src/plane.rs @@ -84,16 +84,7 @@ impl Plane { /// Project a line into the plane pub fn project_line(&self, line: &Line<3>) -> Line<2> { - let line_origin_relative_to_plane = line.origin() - self.origin(); - let line_origin_in_plane = Point { - coords: Vector::from([ - self.u() - .scalar_projection_onto(&line_origin_relative_to_plane), - self.v() - .scalar_projection_onto(&line_origin_relative_to_plane), - ]), - }; - + let line_origin_in_plane = self.project_point(line.origin()); let line_direction_in_plane = self.project_vector(line.direction()); Line::from_origin_and_direction( From 1a0fa272268bc73aa8d14819d9629dfe85b215cd Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 2 Feb 2023 12:29:30 +0100 Subject: [PATCH 4/4] Fix `Plane::project_vector` Turns out that it worked only for plane coordinate systems in which the `u` and `v` vectors where orthogonal. --- crates/fj-math/src/plane.rs | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/crates/fj-math/src/plane.rs b/crates/fj-math/src/plane.rs index 6191735f8..aa33df731 100644 --- a/crates/fj-math/src/plane.rs +++ b/crates/fj-math/src/plane.rs @@ -74,12 +74,29 @@ impl Plane { /// Project a vector into the plane pub fn project_vector(&self, vector: impl Into>) -> Vector<2> { - let vector = vector.into(); - - Vector::from([ - vector.scalar_projection_onto(&self.u()), - vector.scalar_projection_onto(&self.v()), - ]) + // The vector we want to project can be expressed as a linear + // combination of `self.u()`, `self.v()`, and `self.normal()`: + // `v = a*u + b*v + c*n` + // + // All we need to do is to solve this equation. `a` and `b` are the + // components of the projected vector. `c` is the distance of the points + // that the original and projected vectors point to. + // + // To solve the equation, let's change it into the standard `Mx = b` + // form, then we can let nalgebra do the actual solving. + let m = + nalgebra::Matrix::<_, _, nalgebra::Const<3>, _>::from_columns(&[ + self.u().to_na(), + self.v().to_na(), + self.normal().to_na(), + ]); + let b = vector.into(); + let x = m + .lu() + .solve(&b.to_na()) + .expect("Expected matrix to be invertible"); + + Vector::from([x.x, x.y]) } /// Project a line into the plane @@ -114,5 +131,9 @@ mod tests { assert_eq!(plane.project_vector([1., 0., 1.]), Vector::from([1., 0.])); assert_eq!(plane.project_vector([0., 1., 1.]), Vector::from([0., 1.])); + + let plane = + Plane::from_parametric([1., 1., 1.], [1., 0., 0.], [1., 1., 0.]); + assert_eq!(plane.project_vector([0., 1., 0.]), Vector::from([-1., 1.])); } }