From 68a1a555a741a466c51ce55f5cd766ac00e487e0 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 29 Sep 2022 15:10:41 +0200 Subject: [PATCH 1/8] Add `Plane` --- .../algorithms/intersect/surface_surface.rs | 61 +++++++------------ crates/fj-math/src/lib.rs | 2 + crates/fj-math/src/plane.rs | 36 +++++++++++ 3 files changed, 59 insertions(+), 40 deletions(-) create mode 100644 crates/fj-math/src/plane.rs diff --git a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs index 8c969863e..aa38b93e5 100644 --- a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs @@ -1,4 +1,4 @@ -use fj_math::{Line, Point, Scalar, Vector}; +use fj_math::{Line, Plane, Point, Scalar, Vector}; use crate::{ objects::{Curve, GlobalCurve, Surface}, @@ -23,7 +23,7 @@ impl SurfaceSurfaceIntersection { // coordinates for each surface. let planes_parametric = surfaces.map(|surface| { - let plane = PlaneParametric::extract_from_surface(surface); + let plane = plane_from_surface(surface); (*surface, plane) }); let [a, b] = planes_parametric.map(|(_, plane)| { @@ -64,33 +64,17 @@ impl SurfaceSurfaceIntersection { } } -/// A plane in parametric form -#[derive(Clone, Copy)] -struct PlaneParametric { - pub origin: Point<3>, - pub u: Vector<3>, - pub v: Vector<3>, -} - -impl PlaneParametric { - pub fn extract_from_surface(surface: &Surface) -> Self { - let (line, path) = { - let line = match surface.u() { - GlobalPath::Line(line) => line, - _ => todo!( - "Only plane-plane intersection is currently supported." - ), - }; - - (line, surface.v()) +fn plane_from_surface(surface: &Surface) -> Plane { + let (line, path) = { + let line = match surface.u() { + GlobalPath::Line(line) => line, + _ => todo!("Only plane-plane intersection is currently supported."), }; - Self { - origin: line.origin(), - u: line.direction(), - v: path, - } - } + (line, surface.v()) + }; + + Plane::from_parametric(line.origin(), line.direction(), path) } /// A plane in constant-normal form @@ -103,11 +87,11 @@ impl PlaneConstantNormal { /// Extract a plane in constant-normal form from a `Surface` /// /// Panics, if the given `Surface` is not a plane. - pub fn from_parametric_plane(plane: &PlaneParametric) -> Self { + pub fn from_parametric_plane(plane: &Plane) -> Self { // Convert plane from parametric form to three-point form. - let a = plane.origin; - let b = plane.origin + plane.u; - let c = plane.origin + plane.v; + let a = plane.origin(); + let b = plane.origin() + plane.u(); + let c = plane.origin() + plane.v(); // Convert plane from three-point form to constant-normal form. See // Real-Time Collision Detection by Christer Ericson, section 3.6, Planes @@ -119,23 +103,20 @@ impl PlaneConstantNormal { } } -fn project_line_into_plane( - line: &Line<3>, - plane: &PlaneParametric, -) -> SurfacePath { - let line_origin_relative_to_plane = line.origin() - plane.origin; +fn project_line_into_plane(line: &Line<3>, plane: &Plane) -> SurfacePath { + let line_origin_relative_to_plane = line.origin() - plane.origin(); let line_origin_in_plane = Vector::from([ plane - .u + .u() .scalar_projection_onto(&line_origin_relative_to_plane), plane - .v + .v() .scalar_projection_onto(&line_origin_relative_to_plane), ]); let line_direction_in_plane = Vector::from([ - plane.u.scalar_projection_onto(&line.direction()), - plane.v.scalar_projection_onto(&line.direction()), + plane.u().scalar_projection_onto(&line.direction()), + plane.v().scalar_projection_onto(&line.direction()), ]); let line = Line::from_origin_and_direction( diff --git a/crates/fj-math/src/lib.rs b/crates/fj-math/src/lib.rs index ce3976e99..bc43ae832 100644 --- a/crates/fj-math/src/lib.rs +++ b/crates/fj-math/src/lib.rs @@ -39,6 +39,7 @@ mod aabb; mod circle; mod coordinates; mod line; +mod plane; mod point; mod poly_chain; mod scalar; @@ -52,6 +53,7 @@ pub use self::{ circle::Circle, coordinates::{Uv, Xyz, T}, line::Line, + plane::Plane, point::Point, poly_chain::PolyChain, scalar::{Scalar, Sign}, diff --git a/crates/fj-math/src/plane.rs b/crates/fj-math/src/plane.rs new file mode 100644 index 000000000..20edea05c --- /dev/null +++ b/crates/fj-math/src/plane.rs @@ -0,0 +1,36 @@ +use crate::{Point, Vector}; + +/// A plane +#[derive(Clone, Copy, Default, Eq, PartialEq, Hash, Ord, PartialOrd)] +#[repr(C)] +pub struct Plane { + origin: Point<3>, + u: Vector<3>, + v: Vector<3>, +} + +impl Plane { + /// Create a `Plane` from a parametric description + pub fn from_parametric( + origin: Point<3>, + u: Vector<3>, + v: Vector<3>, + ) -> Self { + Self { origin, u, v } + } + + /// Access the origin of the plane + pub fn origin(&self) -> Point<3> { + self.origin + } + + /// Access the u-vector of the plane + pub fn u(&self) -> Vector<3> { + self.u + } + + /// Access the v-vector of the plane + pub fn v(&self) -> Vector<3> { + self.v + } +} From aa08a42d263d6af345ed7d9803d0731956fe8d58 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 29 Sep 2022 15:22:01 +0200 Subject: [PATCH 2/8] Add `Plane::three_point_form` --- .../src/algorithms/intersect/surface_surface.rs | 5 +---- crates/fj-math/src/plane.rs | 9 +++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs index aa38b93e5..56c48aa5c 100644 --- a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs @@ -88,10 +88,7 @@ impl PlaneConstantNormal { /// /// Panics, if the given `Surface` is not a plane. pub fn from_parametric_plane(plane: &Plane) -> Self { - // Convert plane from parametric form to three-point form. - let a = plane.origin(); - let b = plane.origin() + plane.u(); - let c = plane.origin() + plane.v(); + let [a, b, c] = plane.three_point_form(); // Convert plane from three-point form to constant-normal form. See // Real-Time Collision Detection by Christer Ericson, section 3.6, Planes diff --git a/crates/fj-math/src/plane.rs b/crates/fj-math/src/plane.rs index 20edea05c..b7784c0fe 100644 --- a/crates/fj-math/src/plane.rs +++ b/crates/fj-math/src/plane.rs @@ -33,4 +33,13 @@ impl Plane { pub fn v(&self) -> Vector<3> { self.v } + + /// Convert the plane to three-point form + pub fn three_point_form(&self) -> [Point<3>; 3] { + let a = self.origin(); + let b = self.origin() + self.u(); + let c = self.origin() + self.v(); + + [a, b, c] + } } From d22ceaa19be862010bcb59c88ff67aacfe79d354 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 29 Sep 2022 15:25:49 +0200 Subject: [PATCH 3/8] Add `Plane::constant_normal_form` --- .../src/algorithms/intersect/surface_surface.rs | 8 +------- crates/fj-math/src/plane.rs | 14 +++++++++++++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs index 56c48aa5c..d2ea6e22f 100644 --- a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs @@ -88,13 +88,7 @@ impl PlaneConstantNormal { /// /// Panics, if the given `Surface` is not a plane. pub fn from_parametric_plane(plane: &Plane) -> Self { - let [a, b, c] = plane.three_point_form(); - - // Convert plane from three-point form to constant-normal form. See - // Real-Time Collision Detection by Christer Ericson, section 3.6, Planes - // and Halfspaces. - let normal = (b - a).cross(&(c - a)).normalize(); - let distance = normal.dot(&a.coords); + let (distance, normal) = plane.constant_normal_form(); PlaneConstantNormal { distance, normal } } diff --git a/crates/fj-math/src/plane.rs b/crates/fj-math/src/plane.rs index b7784c0fe..f7cd3ead9 100644 --- a/crates/fj-math/src/plane.rs +++ b/crates/fj-math/src/plane.rs @@ -1,4 +1,4 @@ -use crate::{Point, Vector}; +use crate::{Point, Scalar, Vector}; /// A plane #[derive(Clone, Copy, Default, Eq, PartialEq, Hash, Ord, PartialOrd)] @@ -42,4 +42,16 @@ impl Plane { [a, b, c] } + + /// Convert the plane to constant-normal form + pub fn constant_normal_form(&self) -> (Scalar, Vector<3>) { + let [a, b, c] = 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 distance = normal.dot(&a.coords); + + (distance, normal) + } } From e457839b60109cf3d2520595139d65e085c8b64b Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 29 Sep 2022 15:29:02 +0200 Subject: [PATCH 4/8] Refactor --- .../src/algorithms/intersect/surface_surface.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs index d2ea6e22f..30ced1dae 100644 --- a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs @@ -30,7 +30,12 @@ impl SurfaceSurfaceIntersection { PlaneConstantNormal::from_parametric_plane(&plane) }); - let direction = a.normal.cross(&b.normal); + let a_normal = a.normal; + let b_normal = b.normal; + let a_distance = a.distance; + let b_distance = b.distance; + + let direction = a_normal.cross(&b_normal); let denom = direction.dot(&direction); if denom == Scalar::ZERO { @@ -44,7 +49,7 @@ impl SurfaceSurfaceIntersection { return None; } - let origin = (b.normal * a.distance - a.normal * b.distance) + let origin = (b_normal * a_distance - a_normal * b_distance) .cross(&direction) / denom; let origin = Point { coords: origin }; From d629df43fa7b153ea242bd22e0eacb5662974945 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 29 Sep 2022 15:31:08 +0200 Subject: [PATCH 5/8] Refactor --- .../algorithms/intersect/surface_surface.rs | 27 +++---------------- 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs index 30ced1dae..35639df00 100644 --- a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs @@ -26,14 +26,10 @@ impl SurfaceSurfaceIntersection { let plane = plane_from_surface(surface); (*surface, plane) }); - let [a, b] = planes_parametric.map(|(_, plane)| { - PlaneConstantNormal::from_parametric_plane(&plane) - }); + let [a, b] = planes_parametric.map(|(_, plane)| plane); - let a_normal = a.normal; - let b_normal = b.normal; - let a_distance = a.distance; - let b_distance = b.distance; + let (a_distance, a_normal) = a.constant_normal_form(); + let (b_distance, b_normal) = b.constant_normal_form(); let direction = a_normal.cross(&b_normal); @@ -82,23 +78,6 @@ fn plane_from_surface(surface: &Surface) -> Plane { Plane::from_parametric(line.origin(), line.direction(), path) } -/// A plane in constant-normal form -struct PlaneConstantNormal { - pub distance: Scalar, - pub normal: Vector<3>, -} - -impl PlaneConstantNormal { - /// Extract a plane in constant-normal form from a `Surface` - /// - /// Panics, if the given `Surface` is not a plane. - pub fn from_parametric_plane(plane: &Plane) -> Self { - let (distance, normal) = plane.constant_normal_form(); - - PlaneConstantNormal { distance, normal } - } -} - fn project_line_into_plane(line: &Line<3>, plane: &Plane) -> SurfacePath { let line_origin_relative_to_plane = line.origin() - plane.origin(); let line_origin_in_plane = Vector::from([ From 430fcff6cb1ef27404f8509b259d02258c180290 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 29 Sep 2022 15:31:34 +0200 Subject: [PATCH 6/8] Make variable name more descriptive --- .../fj-kernel/src/algorithms/intersect/surface_surface.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs index 35639df00..0506f5362 100644 --- a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs @@ -22,11 +22,11 @@ impl SurfaceSurfaceIntersection { // Adaptations were made to get the intersection curves in local // coordinates for each surface. - let planes_parametric = surfaces.map(|surface| { + let surfaces_and_planes = surfaces.map(|surface| { let plane = plane_from_surface(surface); (*surface, plane) }); - let [a, b] = planes_parametric.map(|(_, plane)| plane); + let [a, b] = surfaces_and_planes.map(|(_, plane)| plane); let (a_distance, a_normal) = a.constant_normal_form(); let (b_distance, b_normal) = b.constant_normal_form(); @@ -52,7 +52,7 @@ impl SurfaceSurfaceIntersection { let line = Line::from_origin_and_direction(origin, direction); - let curves = planes_parametric.map(|(surface, plane)| { + let curves = surfaces_and_planes.map(|(surface, plane)| { let path = project_line_into_plane(&line, &plane); let global_form = GlobalCurve::new(stores); From ffbbd28485957a4f5beab92ab6af781b072fed5d Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 29 Sep 2022 15:36:07 +0200 Subject: [PATCH 7/8] Add `Plane::project_line` --- .../algorithms/intersect/surface_surface.rs | 25 ++----------------- crates/fj-math/src/plane.rs | 25 ++++++++++++++++++- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs index 0506f5362..cce4740db 100644 --- a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs @@ -1,4 +1,4 @@ -use fj_math::{Line, Plane, Point, Scalar, Vector}; +use fj_math::{Line, Plane, Point, Scalar}; use crate::{ objects::{Curve, GlobalCurve, Surface}, @@ -79,28 +79,7 @@ fn plane_from_surface(surface: &Surface) -> Plane { } fn project_line_into_plane(line: &Line<3>, plane: &Plane) -> SurfacePath { - let line_origin_relative_to_plane = line.origin() - plane.origin(); - let line_origin_in_plane = Vector::from([ - plane - .u() - .scalar_projection_onto(&line_origin_relative_to_plane), - plane - .v() - .scalar_projection_onto(&line_origin_relative_to_plane), - ]); - - let line_direction_in_plane = Vector::from([ - plane.u().scalar_projection_onto(&line.direction()), - plane.v().scalar_projection_onto(&line.direction()), - ]); - - let line = Line::from_origin_and_direction( - Point { - coords: line_origin_in_plane, - }, - line_direction_in_plane, - ); - + let line = plane.project_line(line); SurfacePath::Line(line) } diff --git a/crates/fj-math/src/plane.rs b/crates/fj-math/src/plane.rs index f7cd3ead9..f47549b5d 100644 --- a/crates/fj-math/src/plane.rs +++ b/crates/fj-math/src/plane.rs @@ -1,4 +1,4 @@ -use crate::{Point, Scalar, Vector}; +use crate::{Line, Point, Scalar, Vector}; /// A plane #[derive(Clone, Copy, Default, Eq, PartialEq, Hash, Ord, PartialOrd)] @@ -54,4 +54,27 @@ impl Plane { (distance, normal) } + + /// 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_direction_in_plane = Vector::from([ + self.u().scalar_projection_onto(&line.direction()), + self.v().scalar_projection_onto(&line.direction()), + ]); + + Line::from_origin_and_direction( + line_origin_in_plane, + line_direction_in_plane, + ) + } } From 669b2be658ef69a1c4d368713e5ad244e78be66c Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Thu, 29 Sep 2022 15:38:29 +0200 Subject: [PATCH 8/8] Refactor --- .../fj-kernel/src/algorithms/intersect/surface_surface.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs index cce4740db..a117eff72 100644 --- a/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersect/surface_surface.rs @@ -53,7 +53,7 @@ impl SurfaceSurfaceIntersection { let line = Line::from_origin_and_direction(origin, direction); let curves = surfaces_and_planes.map(|(surface, plane)| { - let path = project_line_into_plane(&line, &plane); + let path = SurfacePath::Line(plane.project_line(&line)); let global_form = GlobalCurve::new(stores); Curve::new(surface, path, global_form) @@ -78,11 +78,6 @@ fn plane_from_surface(surface: &Surface) -> Plane { Plane::from_parametric(line.origin(), line.direction(), path) } -fn project_line_into_plane(line: &Line<3>, plane: &Plane) -> SurfacePath { - let line = plane.project_line(line); - SurfacePath::Line(line) -} - #[cfg(test)] mod tests { use fj_math::Transform;