From 557f13f25d2b460dad51297a74d8797c6c7d108f Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 13 Jul 2022 14:06:29 +0200 Subject: [PATCH 1/7] Simplify data handling in surface intersection --- .../algorithms/intersection/surface_surface.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs index 2ec355905..30393f043 100644 --- a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs @@ -7,10 +7,10 @@ pub fn surface_surface(a: &Surface, b: &Surface) -> Option> { // Algorithm from Real-Time Collision Detection by Christer Ericson. See // section 5.4.4, Intersection of Two Planes. - let (a_normal, a_distance) = extract_plane(a); - let (b_normal, b_distance) = extract_plane(b); + let a = extract_plane(a); + let b = extract_plane(b); - let direction = a_normal.cross(&b_normal); + let direction = a.normal.cross(&b.normal); let denom = direction.dot(&direction); if denom == Scalar::ZERO { @@ -24,7 +24,7 @@ pub fn surface_surface(a: &Surface, b: &Surface) -> Option> { 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 }; @@ -32,10 +32,16 @@ pub fn surface_surface(a: &Surface, b: &Surface) -> Option> { Some(Curve::Line(Line { origin, direction })) } +/// A plane in constant-normal form +struct PlaneConstantNormal { + pub distance: Scalar, + pub normal: Vector<3>, +} + /// Extract a plane in constant-normal form from a `Surface` /// /// Panics, if the given `Surface` is not a plane. -fn extract_plane(surface: &Surface) -> (Vector<3>, Scalar) { +fn extract_plane(surface: &Surface) -> PlaneConstantNormal { let Surface::SweptCurve(surface) = surface; let line = match surface.curve { Curve::Line(line) => line, @@ -53,7 +59,7 @@ fn extract_plane(surface: &Surface) -> (Vector<3>, Scalar) { let normal = (b - a).cross(&(c - a)).normalize(); let distance = normal.dot(&a.coords); - (normal, distance) + PlaneConstantNormal { distance, normal } } #[cfg(test)] From 60299318bc3b00b6f4c595c98e85254aa669efb4 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 13 Jul 2022 14:10:42 +0200 Subject: [PATCH 2/7] Separate plane extraction from conversion This adds an intermediate plane representation, `PlaneParametric`, that is going to come in handy for an extension to the algorithm that I'm working on. --- .../intersection/surface_surface.rs | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs index 30393f043..b01c9d6fc 100644 --- a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs @@ -32,6 +32,29 @@ pub fn surface_surface(a: &Surface, b: &Surface) -> Option> { Some(Curve::Line(Line { origin, direction })) } +/// A plane in parametric form +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 Surface::SweptCurve(surface) = surface; + let line = match surface.curve { + Curve::Line(line) => line, + _ => todo!("Only plane-plane intersection is currently supported."), + }; + + Self { + origin: line.origin, + u: line.direction, + v: surface.path, + } + } +} + /// A plane in constant-normal form struct PlaneConstantNormal { pub distance: Scalar, @@ -42,16 +65,12 @@ struct PlaneConstantNormal { /// /// Panics, if the given `Surface` is not a plane. fn extract_plane(surface: &Surface) -> PlaneConstantNormal { - let Surface::SweptCurve(surface) = surface; - let line = match surface.curve { - Curve::Line(line) => line, - _ => todo!("Only plane-plane intersection is currently supported."), - }; + let plane = PlaneParametric::extract_from_surface(surface); // Convert plane from parametric form to three-point form. - let a = line.origin; - let b = line.origin + line.direction; - let c = line.origin + surface.path; + 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 From 7141b822c8ebc402b4b07ddf42bd70afb73ae0b5 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 13 Jul 2022 14:12:52 +0200 Subject: [PATCH 3/7] Refactor --- .../src/algorithms/intersection/surface_surface.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs index b01c9d6fc..4246f1683 100644 --- a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs @@ -7,8 +7,11 @@ pub fn surface_surface(a: &Surface, b: &Surface) -> Option> { // Algorithm from Real-Time Collision Detection by Christer Ericson. See // section 5.4.4, Intersection of Two Planes. - let a = extract_plane(a); - let b = extract_plane(b); + let a_parametric = PlaneParametric::extract_from_surface(a); + let b_parametric = PlaneParametric::extract_from_surface(b); + + let a = extract_plane(&a_parametric); + let b = extract_plane(&b_parametric); let direction = a.normal.cross(&b.normal); @@ -64,9 +67,7 @@ struct PlaneConstantNormal { /// Extract a plane in constant-normal form from a `Surface` /// /// Panics, if the given `Surface` is not a plane. -fn extract_plane(surface: &Surface) -> PlaneConstantNormal { - let plane = PlaneParametric::extract_from_surface(surface); - +fn extract_plane(plane: &PlaneParametric) -> PlaneConstantNormal { // Convert plane from parametric form to three-point form. let a = plane.origin; let b = plane.origin + plane.u; From 428a3c2ba2238c6f968f24b2347a4758cf820450 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 13 Jul 2022 14:13:54 +0200 Subject: [PATCH 4/7] Convert free function into method --- .../intersection/surface_surface.rs | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs index 4246f1683..cefd4b897 100644 --- a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs @@ -10,8 +10,8 @@ pub fn surface_surface(a: &Surface, b: &Surface) -> Option> { let a_parametric = PlaneParametric::extract_from_surface(a); let b_parametric = PlaneParametric::extract_from_surface(b); - let a = extract_plane(&a_parametric); - let b = extract_plane(&b_parametric); + let a = PlaneConstantNormal::extract_plane(&a_parametric); + let b = PlaneConstantNormal::extract_plane(&b_parametric); let direction = a.normal.cross(&b.normal); @@ -64,22 +64,24 @@ struct PlaneConstantNormal { pub normal: Vector<3>, } -/// Extract a plane in constant-normal form from a `Surface` -/// -/// Panics, if the given `Surface` is not a plane. -fn extract_plane(plane: &PlaneParametric) -> PlaneConstantNormal { - // 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; - - // 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); - - PlaneConstantNormal { distance, normal } +impl PlaneConstantNormal { + /// Extract a plane in constant-normal form from a `Surface` + /// + /// Panics, if the given `Surface` is not a plane. + pub fn extract_plane(plane: &PlaneParametric) -> 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; + + // 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); + + PlaneConstantNormal { distance, normal } + } } #[cfg(test)] From c9cfbc31bd0e9111a07b1599a5241ad4589992fc Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 13 Jul 2022 14:14:24 +0200 Subject: [PATCH 5/7] Update method name --- .../src/algorithms/intersection/surface_surface.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs index cefd4b897..0482b39db 100644 --- a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs @@ -10,8 +10,8 @@ pub fn surface_surface(a: &Surface, b: &Surface) -> Option> { let a_parametric = PlaneParametric::extract_from_surface(a); let b_parametric = PlaneParametric::extract_from_surface(b); - let a = PlaneConstantNormal::extract_plane(&a_parametric); - let b = PlaneConstantNormal::extract_plane(&b_parametric); + let a = PlaneConstantNormal::from_parametric_plane(&a_parametric); + let b = PlaneConstantNormal::from_parametric_plane(&b_parametric); let direction = a.normal.cross(&b.normal); @@ -68,7 +68,7 @@ impl PlaneConstantNormal { /// Extract a plane in constant-normal form from a `Surface` /// /// Panics, if the given `Surface` is not a plane. - pub fn extract_plane(plane: &PlaneParametric) -> Self { + pub fn from_parametric_plane(plane: &PlaneParametric) -> Self { // Convert plane from parametric form to three-point form. let a = plane.origin; let b = plane.origin + plane.u; From 8d74bb2ce6457eadb203c3f47c71a3f6c3762462 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 13 Jul 2022 14:17:49 +0200 Subject: [PATCH 6/7] Extract variable from expression --- .../fj-kernel/src/algorithms/intersection/surface_surface.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs index 0482b39db..1012b18fc 100644 --- a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs @@ -32,7 +32,9 @@ pub fn surface_surface(a: &Surface, b: &Surface) -> Option> { / denom; let origin = Point { coords: origin }; - Some(Curve::Line(Line { origin, direction })) + let curve_global = Curve::Line(Line { origin, direction }); + + Some(curve_global) } /// A plane in parametric form From c97cd7f5b92e9132160a9c8213c1af19ee1a9016 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 13 Jul 2022 14:47:27 +0200 Subject: [PATCH 7/7] Return local curves from surface intersection These local curves are going to be needed when using the function in the union algorithm. --- .../intersection/surface_surface.rs | 55 ++++++++++++++++++- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs index 1012b18fc..c64e4351b 100644 --- a/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs +++ b/crates/fj-kernel/src/algorithms/intersection/surface_surface.rs @@ -3,9 +3,15 @@ use fj_math::{Line, Point, Scalar, Vector}; use crate::objects::{Curve, Surface}; /// Test intersection between two surfaces -pub fn surface_surface(a: &Surface, b: &Surface) -> Option> { +pub fn surface_surface( + a: &Surface, + b: &Surface, +) -> Option<(Curve<2>, Curve<2>, Curve<3>)> { // Algorithm from Real-Time Collision Detection by Christer Ericson. See // section 5.4.4, Intersection of Two Planes. + // + // Adaptations were made to get the intersection curves in local coordinates + // for each surface. let a_parametric = PlaneParametric::extract_from_surface(a); let b_parametric = PlaneParametric::extract_from_surface(b); @@ -32,9 +38,13 @@ pub fn surface_surface(a: &Surface, b: &Surface) -> Option> { / denom; let origin = Point { coords: origin }; + let line = Line { origin, direction }; + + let curve_a = project_line_into_plane(&line, &a_parametric); + let curve_b = project_line_into_plane(&line, &b_parametric); let curve_global = Curve::Line(Line { origin, direction }); - Some(curve_global) + Some((curve_a, curve_b, curve_global)) } /// A plane in parametric form @@ -86,6 +96,36 @@ impl PlaneConstantNormal { } } +fn project_line_into_plane( + line: &Line<3>, + plane: &PlaneParametric, +) -> Curve<2> { + let line_origin_relative_to_plane = line.origin - plane.origin; + dbg!(&line_origin_relative_to_plane); + 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 { + origin: Point { + coords: line_origin_in_plane, + }, + direction: line_direction_in_plane, + }; + + Curve::Line(line) +} + #[cfg(test)] mod tests { use fj_math::Transform; @@ -99,6 +139,7 @@ mod tests { let xy = Surface::xy_plane(); let xz = Surface::xz_plane(); + // Coincident and parallel planes don't have an intersection curve. assert_eq!(surface_surface(&xy, &xy), None); assert_eq!( surface_surface( @@ -107,6 +148,14 @@ mod tests { ), None, ); - assert_eq!(surface_surface(&xy, &xz), Some(Curve::x_axis())); + + let expected_xy = Curve::u_axis(); + let expected_xz = Curve::u_axis(); + let expected_global = Curve::x_axis(); + + assert_eq!( + surface_surface(&xy, &xz), + Some((expected_xy, expected_xz, expected_global)) + ); } }