From 684f7827a4a52c8dd433dec7f4dd50947f54722e Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 30 Sep 2022 11:24:01 +0200 Subject: [PATCH 1/6] Make use of `Plane` in ray/face intersection test --- .../src/algorithms/intersect/ray_face.rs | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs index 359de4a50..f31000cc4 100644 --- a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs @@ -1,6 +1,6 @@ //! Intersection between a ray and a face, in 3D -use fj_math::{Point, Scalar}; +use fj_math::{Plane, Point, Scalar}; use crate::{ algorithms::intersect::face_point::FacePointIntersection, @@ -16,25 +16,26 @@ impl Intersect for (&HorizontalRayToTheRight<3>, &Face) { fn intersect(self) -> Option { let (ray, face) = self; - let (plane_origin, plane_direction_1, plane_direction_2) = - match face.surface().u() { - GlobalPath::Circle(_) => todo!( - "Casting a ray against a swept circle is not supported yet" - ), - GlobalPath::Line(line) => { - (line.origin(), line.direction(), face.surface().v()) - } - }; + let plane = match face.surface().u() { + GlobalPath::Circle(_) => todo!( + "Casting a ray against a swept circle is not supported yet" + ), + GlobalPath::Line(line) => Plane::from_parametric( + line.origin(), + line.direction(), + face.surface().v(), + ), + }; let plane_and_ray_are_parallel = { - let plane_normal = plane_direction_1.cross(&plane_direction_2); + let plane_normal = plane.u().cross(&plane.v()); plane_normal.dot(&ray.direction()) == Scalar::ZERO }; if plane_and_ray_are_parallel { - let a = plane_origin; - let b = plane_origin + plane_direction_1; - let c = plane_origin + plane_direction_2; + let a = plane.origin(); + let b = plane.origin() + plane.u(); + let c = plane.origin() + plane.v(); let d = ray.origin; let [a, b, c, d] = [a, b, c, d] @@ -63,8 +64,8 @@ impl Intersect for (&HorizontalRayToTheRight<3>, &Face) { // We already handled the case of the ray and plane being parallel // above. The following assertion should thus never be triggered. assert_ne!( - plane_direction_1.y * plane_direction_2.z, - plane_direction_1.z * plane_direction_2.y, + plane.u().y * plane.v().z, + plane.u().z * plane.v().y, "Plane and ray are parallel; should have been ruled out previously" ); @@ -75,15 +76,15 @@ impl Intersect for (&HorizontalRayToTheRight<3>, &Face) { let orx = ray.origin.x; let ory = ray.origin.y; let orz = ray.origin.z; - let opx = plane_origin.x; - let opy = plane_origin.y; - let opz = plane_origin.z; - let d1x = plane_direction_1.x; - let d1y = plane_direction_1.y; - let d1z = plane_direction_1.z; - let d2x = plane_direction_2.x; - let d2y = plane_direction_2.y; - let d2z = plane_direction_2.z; + let opx = plane.origin().x; + let opy = plane.origin().y; + let opz = plane.origin().z; + let d1x = plane.u().x; + let d1y = plane.u().y; + let d1z = plane.u().z; + let d2x = plane.v().x; + let d2y = plane.v().y; + let d2z = plane.v().z; // Let's figure out where the intersection between the ray and the // plane is. By equating the parametric equations of the ray and the From 694aad4b089a640e6dd4b3773f100a64b3956920 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 30 Sep 2022 11:28:49 +0200 Subject: [PATCH 2/6] Add `Plane::normal` --- crates/fj-kernel/src/algorithms/intersect/ray_face.rs | 6 ++---- crates/fj-math/src/plane.rs | 9 +++++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs index f31000cc4..075371b52 100644 --- a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs @@ -27,10 +27,8 @@ impl Intersect for (&HorizontalRayToTheRight<3>, &Face) { ), }; - let plane_and_ray_are_parallel = { - let plane_normal = plane.u().cross(&plane.v()); - plane_normal.dot(&ray.direction()) == Scalar::ZERO - }; + let plane_and_ray_are_parallel = + plane.normal().dot(&ray.direction()) == Scalar::ZERO; if plane_and_ray_are_parallel { let a = plane.origin(); diff --git a/crates/fj-math/src/plane.rs b/crates/fj-math/src/plane.rs index f47549b5d..2cb6a81da 100644 --- a/crates/fj-math/src/plane.rs +++ b/crates/fj-math/src/plane.rs @@ -34,6 +34,11 @@ impl Plane { self.v } + /// Compute the normal of the plane + pub fn normal(&self) -> Vector<3> { + self.u().cross(&self.v()).normalize() + } + /// Convert the plane to three-point form pub fn three_point_form(&self) -> [Point<3>; 3] { let a = self.origin(); @@ -45,11 +50,11 @@ impl Plane { /// Convert the plane to constant-normal form pub fn constant_normal_form(&self) -> (Scalar, Vector<3>) { - let [a, b, c] = self.three_point_form(); + let [a, _, _] = self.three_point_form(); // See Real-Time Collision Detection by Christer Ericson, section 3.6, // Planes and Halfspaces. - let normal = (b - a).cross(&(c - a)).normalize(); + let normal = self.normal(); let distance = normal.dot(&a.coords); (distance, normal) From c501bf441e0481e37d42c72bf7cb3afdad10e05c Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 30 Sep 2022 11:29:36 +0200 Subject: [PATCH 3/6] Simplify code --- crates/fj-math/src/plane.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/fj-math/src/plane.rs b/crates/fj-math/src/plane.rs index 2cb6a81da..6efcf7493 100644 --- a/crates/fj-math/src/plane.rs +++ b/crates/fj-math/src/plane.rs @@ -50,12 +50,10 @@ impl Plane { /// Convert the plane to constant-normal form pub fn constant_normal_form(&self) -> (Scalar, Vector<3>) { - let [a, _, _] = self.three_point_form(); - // See Real-Time Collision Detection by Christer Ericson, section 3.6, // Planes and Halfspaces. let normal = self.normal(); - let distance = normal.dot(&a.coords); + let distance = normal.dot(&self.origin().coords); (distance, normal) } From 8db6db1d4957c7de4d2880202f185cda56a75bae Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 30 Sep 2022 11:30:11 +0200 Subject: [PATCH 4/6] Remove outdated comment --- crates/fj-math/src/plane.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/fj-math/src/plane.rs b/crates/fj-math/src/plane.rs index 6efcf7493..fda4361ec 100644 --- a/crates/fj-math/src/plane.rs +++ b/crates/fj-math/src/plane.rs @@ -50,8 +50,6 @@ impl Plane { /// Convert the plane to constant-normal form pub fn constant_normal_form(&self) -> (Scalar, Vector<3>) { - // See Real-Time Collision Detection by Christer Ericson, section 3.6, - // Planes and Halfspaces. let normal = self.normal(); let distance = normal.dot(&self.origin().coords); From 1f7be3356ee07b263b0c07446f6ed22882784140 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 30 Sep 2022 11:36:04 +0200 Subject: [PATCH 5/6] Add `Plane::is_parallel_to_vector` --- crates/fj-kernel/src/algorithms/intersect/ray_face.rs | 5 +---- crates/fj-math/src/plane.rs | 5 +++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs index 075371b52..9bcdcac8a 100644 --- a/crates/fj-kernel/src/algorithms/intersect/ray_face.rs +++ b/crates/fj-kernel/src/algorithms/intersect/ray_face.rs @@ -27,10 +27,7 @@ impl Intersect for (&HorizontalRayToTheRight<3>, &Face) { ), }; - let plane_and_ray_are_parallel = - plane.normal().dot(&ray.direction()) == Scalar::ZERO; - - if plane_and_ray_are_parallel { + if plane.is_parallel_to_vector(&ray.direction()) { let a = plane.origin(); let b = plane.origin() + plane.u(); let c = plane.origin() + plane.v(); diff --git a/crates/fj-math/src/plane.rs b/crates/fj-math/src/plane.rs index fda4361ec..3b6841cb0 100644 --- a/crates/fj-math/src/plane.rs +++ b/crates/fj-math/src/plane.rs @@ -56,6 +56,11 @@ impl Plane { (distance, normal) } + /// Determine whether the plane is parallel to the given vector + pub fn is_parallel_to_vector(&self, vector: &Vector<3>) -> bool { + self.normal().dot(vector) == Scalar::ZERO + } + /// 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(); From d3f6b6b95911b37f25c3052374d4e28353de0026 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Fri, 30 Sep 2022 11:45:10 +0200 Subject: [PATCH 6/6] Add `Plane::project_vector` --- crates/fj-math/src/plane.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/crates/fj-math/src/plane.rs b/crates/fj-math/src/plane.rs index 3b6841cb0..e405ed7c4 100644 --- a/crates/fj-math/src/plane.rs +++ b/crates/fj-math/src/plane.rs @@ -61,6 +61,14 @@ impl Plane { self.normal().dot(vector) == Scalar::ZERO } + /// Project a vector into the plane + pub fn project_vector(&self, vector: &Vector<3>) -> Vector<2> { + Vector::from([ + self.u().scalar_projection_onto(vector), + self.v().scalar_projection_onto(vector), + ]) + } + /// 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(); @@ -73,10 +81,7 @@ impl Plane { ]), }; - let line_direction_in_plane = Vector::from([ - self.u().scalar_projection_onto(&line.direction()), - self.v().scalar_projection_onto(&line.direction()), - ]); + let line_direction_in_plane = self.project_vector(&line.direction()); Line::from_origin_and_direction( line_origin_in_plane,