Skip to content

Commit

Permalink
Merge pull request #890 from hannobraun/intersection
Browse files Browse the repository at this point in the history
Clean up surface/surface intersection
  • Loading branch information
hannobraun authored Jul 29, 2022
2 parents bf499bd + 5bcc4a8 commit 0766e6c
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 44 deletions.
2 changes: 1 addition & 1 deletion crates/fj-kernel/src/algorithms/intersection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ pub use self::{
curve_edge::CurveEdgeIntersection,
curve_face::{CurveFaceIntersection, CurveFaceIntersectionList},
line_segment::LineSegmentIntersection,
surface_surface::surface_surface,
surface_surface::SurfaceSurfaceIntersection,
};
101 changes: 58 additions & 43 deletions crates/fj-kernel/src/algorithms/intersection/surface_surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,61 @@ 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<(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);

let a = PlaneConstantNormal::from_parametric_plane(&a_parametric);
let b = PlaneConstantNormal::from_parametric_plane(&b_parametric);

let direction = a.normal.cross(&b.normal);

let denom = direction.dot(&direction);
if denom == Scalar::ZERO {
// Comparing `denom` against zero looks fishy. It's probably better to
// compare it against an epsilon value, but I don't know how large that
// epsilon should be.
/// The intersection between two surfaces
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct SurfaceSurfaceIntersection {
/// The intersection curves, in the coordinates of the input surfaces
pub local_intersection_curves: [Curve<2>; 2],

/// The intersection curve, in global coordinates
pub global_intersection_curve: Curve<3>,
}

impl SurfaceSurfaceIntersection {
/// Compute the intersection between two surfaces
pub fn compute(a: &Surface, b: &Surface) -> Option<Self> {
// Algorithm from Real-Time Collision Detection by Christer Ericson. See
// section 5.4.4, Intersection of Two Planes.
//
// I'll just leave it like that, until we had the opportunity to collect
// some experience with this code.
// - @hannobraun
return None;
}
// 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);

let a = PlaneConstantNormal::from_parametric_plane(&a_parametric);
let b = PlaneConstantNormal::from_parametric_plane(&b_parametric);

let direction = a.normal.cross(&b.normal);

let denom = direction.dot(&direction);
if denom == Scalar::ZERO {
// Comparing `denom` against zero looks fishy. It's probably better
// to compare it against an epsilon value, but I don't know how
// large that epsilon should be.
//
// I'll just leave it like that, until we had the opportunity to
// collect some experience with this code.
// - @hannobraun
return None;
}

let origin = (b.normal * a.distance - a.normal * b.distance)
.cross(&direction)
/ denom;
let origin = Point { coords: origin };
let origin = (b.normal * a.distance - a.normal * b.distance)
.cross(&direction)
/ denom;
let origin = Point { coords: origin };

let line = Line { origin, direction };
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 });
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_a, curve_b, curve_global))
Some(Self {
local_intersection_curves: [curve_a, curve_b],
global_intersection_curve: curve_global,
})
}
}

/// A plane in parametric form
Expand Down Expand Up @@ -134,17 +146,17 @@ mod tests {
objects::{Curve, Surface},
};

use super::surface_surface;
use super::SurfaceSurfaceIntersection;

#[test]
fn plane_plane() {
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!(SurfaceSurfaceIntersection::compute(&xy, &xy), None);
assert_eq!(
surface_surface(
SurfaceSurfaceIntersection::compute(
&xy,
&xy.transform(&Transform::translation([0., 0., 1.]))
),
Expand All @@ -156,8 +168,11 @@ mod tests {
let expected_global = Curve::x_axis();

assert_eq!(
surface_surface(&xy, &xz),
Some((expected_xy, expected_xz, expected_global))
SurfaceSurfaceIntersection::compute(&xy, &xz),
Some(SurfaceSurfaceIntersection {
local_intersection_curves: [expected_xy, expected_xz],
global_intersection_curve: expected_global,
})
);
}
}

0 comments on commit 0766e6c

Please sign in to comment.