Skip to content

Commit

Permalink
Merge pull request #905 from hannobraun/intersection
Browse files Browse the repository at this point in the history
Clean up intersection code
  • Loading branch information
hannobraun authored Aug 2, 2022
2 parents 449a654 + 964a2b4 commit bf4a9ca
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 47 deletions.
18 changes: 9 additions & 9 deletions crates/fj-kernel/src/algorithms/intersection/curve_edge.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use fj_math::{Point, Segment};

use crate::objects::{CurveKind, Edge};
use crate::objects::{Curve, CurveKind, Edge};

use super::LineSegmentIntersection;

/// The intersection between a curve and an [`Edge`], in curve coordinates
/// The intersection between a [`Curve`] and an [`Edge`], in curve coordinates
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum CurveEdgeIntersection {
/// The curve and edge intersect at a point
Expand All @@ -26,10 +26,10 @@ impl CurveEdgeIntersection {
/// # Panics
///
/// Currently, only intersections between lines and line segments can be
/// computed. Panics, if a different type of curve or [`Edge`] is
/// computed. Panics, if a different type of [`Curve`] or [`Edge`] is
/// passed.
pub fn compute(curve: &CurveKind<2>, edge: &Edge) -> Option<Self> {
let curve_as_line = match curve {
pub fn compute(curve: &Curve, edge: &Edge) -> Option<Self> {
let curve_as_line = match curve.kind() {
CurveKind::Line(line) => line,
_ => todo!("Curve-edge intersection only supports lines"),
};
Expand Down Expand Up @@ -87,7 +87,7 @@ mod tests {
let edge = Edge::build()
.line_segment_from_points(&surface, [[1., -1.], [1., 1.]]);

let intersection = CurveEdgeIntersection::compute(curve.kind(), &edge);
let intersection = CurveEdgeIntersection::compute(&curve, &edge);

assert_eq!(
intersection,
Expand All @@ -104,7 +104,7 @@ mod tests {
let edge = Edge::build()
.line_segment_from_points(&surface, [[-1., -1.], [-1., 1.]]);

let intersection = CurveEdgeIntersection::compute(curve.kind(), &edge);
let intersection = CurveEdgeIntersection::compute(&curve, &edge);

assert_eq!(
intersection,
Expand All @@ -121,7 +121,7 @@ mod tests {
let edge = Edge::build()
.line_segment_from_points(&surface, [[-1., -1.], [1., -1.]]);

let intersection = CurveEdgeIntersection::compute(curve.kind(), &edge);
let intersection = CurveEdgeIntersection::compute(&curve, &edge);

assert!(intersection.is_none());
}
Expand All @@ -133,7 +133,7 @@ mod tests {
let edge = Edge::build()
.line_segment_from_points(&surface, [[-1., 0.], [1., 0.]]);

let intersection = CurveEdgeIntersection::compute(curve.kind(), &edge);
let intersection = CurveEdgeIntersection::compute(&curve, &edge);

assert_eq!(
intersection,
Expand Down
21 changes: 9 additions & 12 deletions crates/fj-kernel/src/algorithms/intersection/curve_face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use fj_math::Point;

use crate::{
algorithms::intersection::CurveEdgeIntersection,
objects::{CurveKind, Face},
objects::{Curve, Face},
};

/// The intersections between a curve and a [`Face`], in curve coordinates
/// The intersections between a [`Curve`] and a [`Face`], in curve coordinates
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct CurveFaceIntersectionList {
intervals: Vec<CurveFaceIntersection>,
Expand All @@ -27,8 +27,8 @@ impl CurveFaceIntersectionList {
Self { intervals }
}

/// Compute the intersections between a curve and a [`Face`]
pub fn compute(curve: &CurveKind<2>, face: &Face) -> Self {
/// Compute the intersections between a [`Curve`] and a [`Face`]
pub fn compute(curve: &Curve, face: &Face) -> Self {
let edges = face.all_cycles().flat_map(|cycle| {
let edges: Vec<_> = cycle.edges().cloned().collect();
edges
Expand Down Expand Up @@ -140,18 +140,16 @@ pub type CurveFaceIntersection = [Point<1>; 2];

#[cfg(test)]
mod tests {
use fj_math::{Line, Point, Vector};

use crate::objects::{CurveKind, Face, Surface};
use crate::objects::{Curve, Face, Surface};

use super::CurveFaceIntersectionList;

#[test]
fn compute() {
let curve = CurveKind::Line(Line {
origin: Point::from([-3., 0.]),
direction: Vector::from([1., 0.]),
});
let surface = Surface::xy_plane();

let curve =
Curve::build(surface).line_from_points([[-3., 0.], [-2., 0.]]);

#[rustfmt::skip]
let exterior = [
Expand All @@ -168,7 +166,6 @@ mod tests {
[-1., 1.],
];

let surface = Surface::xy_plane();
let face = Face::build(surface)
.polygon_from_points(exterior)
.with_hole(interior);
Expand Down
47 changes: 21 additions & 26 deletions crates/fj-kernel/src/algorithms/intersection/surface_surface.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
use fj_math::{Line, Point, Scalar, Vector};

use crate::objects::{CurveKind, Surface};
use crate::objects::{Curve, CurveKind, GlobalCurve, Surface};

/// 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: [CurveKind<2>; 2],

/// The intersection curve, in global coordinates
pub global_intersection_curve: CurveKind<3>,
/// The intersection curves
pub intersection_curves: [Curve; 2],
}

impl SurfaceSurfaceIntersection {
/// Compute the intersection between two surfaces
pub fn compute(a: &Surface, b: &Surface) -> Option<Self> {
pub fn compute(surfaces: [&Surface; 2]) -> Option<Self> {
// 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 planes_parametric =
surfaces.map(PlaneParametric::extract_from_surface);
let [a, b] = planes_parametric
.map(|plane| PlaneConstantNormal::from_parametric_plane(&plane));

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

Expand All @@ -48,18 +44,21 @@ impl SurfaceSurfaceIntersection {

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 = CurveKind::Line(Line { origin, direction });
let curves = planes_parametric.map(|plane| {
let local = project_line_into_plane(&line, &plane);
let global = CurveKind::Line(Line { origin, direction });

Curve::new(local, GlobalCurve::from_kind(global))
});

Some(Self {
local_intersection_curves: [curve_a, curve_b],
global_intersection_curve: curve_global,
intersection_curves: curves,
})
}
}

/// A plane in parametric form
#[derive(Clone, Copy)]
struct PlaneParametric {
pub origin: Point<3>,
pub u: Vector<3>,
Expand Down Expand Up @@ -154,26 +153,22 @@ mod tests {
let xz = Surface::xz_plane();

// Coincident and parallel planes don't have an intersection curve.
assert_eq!(SurfaceSurfaceIntersection::compute(&xy, &xy), None);
assert_eq!(SurfaceSurfaceIntersection::compute([&xy, &xy]), None);
assert_eq!(
SurfaceSurfaceIntersection::compute(
SurfaceSurfaceIntersection::compute([
&xy,
&xy.transform(&Transform::translation([0., 0., 1.]))
),
]),
None,
);

let expected_xy = Curve::build(xy).u_axis();
let expected_xz = Curve::build(xz).u_axis();

assert_eq!(
SurfaceSurfaceIntersection::compute(&xy, &xz),
SurfaceSurfaceIntersection::compute([&xy, &xz]),
Some(SurfaceSurfaceIntersection {
local_intersection_curves: [
*expected_xy.kind(),
*expected_xz.kind()
],
global_intersection_curve: *expected_xy.global().kind(),
intersection_curves: [expected_xy, expected_xz],
})
);
}
Expand Down

0 comments on commit bf4a9ca

Please sign in to comment.