Skip to content

Commit

Permalink
Merge pull request #1614 from hannobraun/intersect
Browse files Browse the repository at this point in the history
Simplify intersection code that uses or produces curves
  • Loading branch information
hannobraun authored Feb 24, 2023
2 parents c757811 + 51623d5 commit eb6b27f
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 105 deletions.
36 changes: 13 additions & 23 deletions crates/fj-kernel/src/algorithms/intersect/curve_edge.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
use fj_math::{Point, Segment};

use crate::{
geometry::path::SurfacePath,
objects::{Curve, HalfEdge},
};
use crate::{geometry::path::SurfacePath, objects::HalfEdge};

use super::LineSegmentIntersection;

/// The intersection between a [`Curve`] and a [`HalfEdge`]
/// The intersection between a curve and a [`HalfEdge`]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum CurveEdgeIntersection {
/// The curve and edge intersect at a point
Expand All @@ -29,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 [`HalfEdge`] is
/// computed. Panics, if a different type of curve or [`HalfEdge`] is
/// passed.
pub fn compute(curve: &Curve, half_edge: &HalfEdge) -> Option<Self> {
let curve_as_line = match curve.path() {
pub fn compute(curve: &SurfacePath, half_edge: &HalfEdge) -> Option<Self> {
let curve_as_line = match curve {
SurfacePath::Line(line) => line,
_ => todo!("Curve-edge intersection only supports lines"),
};
Expand All @@ -53,7 +50,7 @@ impl CurveEdgeIntersection {
};

let intersection =
LineSegmentIntersection::compute(&curve_as_line, &edge_as_segment)?;
LineSegmentIntersection::compute(curve_as_line, &edge_as_segment)?;

let intersection = match intersection {
LineSegmentIntersection::Point { point_on_line } => Self::Point {
Expand All @@ -75,8 +72,9 @@ mod tests {
use fj_math::Point;

use crate::{
builder::{CurveBuilder, HalfEdgeBuilder},
partial::{PartialCurve, PartialHalfEdge, PartialObject},
builder::HalfEdgeBuilder,
geometry::path::SurfacePath,
partial::{PartialHalfEdge, PartialObject},
services::Services,
};

Expand All @@ -87,9 +85,7 @@ mod tests {
let mut services = Services::new();

let surface = services.objects.surfaces.xy_plane();
let mut curve = PartialCurve::default();
curve.update_as_u_axis();
let curve = curve.build(&mut services.objects);
let curve = SurfacePath::u_axis();
let half_edge = {
let mut half_edge = PartialHalfEdge::default();
half_edge.update_as_line_segment_from_points([[1., -1.], [1., 1.]]);
Expand All @@ -113,9 +109,7 @@ mod tests {
let mut services = Services::new();

let surface = services.objects.surfaces.xy_plane();
let mut curve = PartialCurve::default();
curve.update_as_u_axis();
let curve = curve.build(&mut services.objects);
let curve = SurfacePath::u_axis();
let half_edge = {
let mut half_edge = PartialHalfEdge::default();
half_edge
Expand All @@ -140,9 +134,7 @@ mod tests {
let mut services = Services::new();

let surface = services.objects.surfaces.xy_plane();
let mut curve = PartialCurve::default();
curve.update_as_u_axis();
let curve = curve.build(&mut services.objects);
let curve = SurfacePath::u_axis();
let half_edge = {
let mut half_edge = PartialHalfEdge::default();
half_edge
Expand All @@ -162,9 +154,7 @@ mod tests {
let mut services = Services::new();

let surface = services.objects.surfaces.xy_plane();
let mut curve = PartialCurve::default();
curve.update_as_u_axis();
let curve = curve.build(&mut services.objects);
let curve = SurfacePath::u_axis();
let half_edge = {
let mut half_edge = PartialHalfEdge::default();
half_edge.update_as_line_segment_from_points([[-1., 0.], [1., 0.]]);
Expand Down
17 changes: 8 additions & 9 deletions crates/fj-kernel/src/algorithms/intersect/curve_face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ use std::vec;
use fj_interop::ext::SliceExt;
use fj_math::Point;

use crate::objects::{Curve, Face};
use crate::{geometry::path::SurfacePath, objects::Face};

use super::CurveEdgeIntersection;

/// 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 CurveFaceIntersection {
/// The intervals where the curve and face intersect, in curve coordinates
Expand All @@ -27,8 +27,8 @@ impl CurveFaceIntersection {
Self { intervals }
}

/// Compute the intersections between a [`Curve`] and a [`Face`]
pub fn compute(curve: &Curve, face: &Face) -> Self {
/// Compute the intersection
pub fn compute(curve: &SurfacePath, face: &Face) -> Self {
let half_edges = face.all_cycles().flat_map(|cycle| cycle.half_edges());

let mut intersections = Vec::new();
Expand Down Expand Up @@ -150,8 +150,9 @@ where
#[cfg(test)]
mod tests {
use crate::{
builder::{CurveBuilder, CycleBuilder, FaceBuilder},
partial::{Partial, PartialCurve, PartialFace, PartialObject},
builder::{CycleBuilder, FaceBuilder},
geometry::path::SurfacePath,
partial::{Partial, PartialFace, PartialObject},
services::Services,
};

Expand All @@ -161,9 +162,7 @@ mod tests {
fn compute() {
let mut services = Services::new();

let mut curve = PartialCurve::default();
curve.update_as_line_from_points([[-3., 0.], [-2., 0.]]);
let curve = curve.build(&mut services.objects);
let (curve, _) = SurfacePath::line_from_points([[-3., 0.], [-2., 0.]]);

#[rustfmt::skip]
let exterior = [
Expand Down
34 changes: 11 additions & 23 deletions crates/fj-kernel/src/algorithms/intersect/face_face.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
use fj_interop::ext::ArrayExt;
use iter_fixed::IntoIteratorFixed;

use crate::{
objects::{Curve, Face, Objects},
services::Service,
storage::Handle,
};
use crate::{geometry::path::SurfacePath, objects::Face};

use super::{CurveFaceIntersection, SurfaceSurfaceIntersection};

Expand All @@ -18,7 +14,7 @@ pub struct FaceFaceIntersection {
/// representation of the intersection on the respective face's surface.
///
/// They both represent the same global curve.
pub intersection_curves: [Handle<Curve>; 2],
pub intersection_curves: [SurfacePath; 2],

/// The interval of this intersection, in curve coordinates
///
Expand All @@ -28,14 +24,11 @@ pub struct FaceFaceIntersection {

impl FaceFaceIntersection {
/// Compute the intersections between two faces
pub fn compute(
faces: [&Face; 2],
objects: &mut Service<Objects>,
) -> Option<Self> {
pub fn compute(faces: [&Face; 2]) -> Option<Self> {
let surfaces = faces.map(|face| face.surface().clone());

let intersection_curves =
match SurfaceSurfaceIntersection::compute(surfaces, objects) {
match SurfaceSurfaceIntersection::compute(surfaces) {
Some(intersection) => intersection.intersection_curves,
None => return None,
};
Expand Down Expand Up @@ -69,9 +62,9 @@ mod tests {

use crate::{
algorithms::intersect::CurveFaceIntersection,
builder::{CurveBuilder, CycleBuilder},
insert::Insert,
partial::{Partial, PartialCurve, PartialFace, PartialObject},
builder::CycleBuilder,
geometry::path::SurfacePath,
partial::{Partial, PartialFace, PartialObject},
services::Services,
};

Expand Down Expand Up @@ -102,8 +95,7 @@ mod tests {
face.build(&mut services.objects)
});

let intersection =
FaceFaceIntersection::compute([&a, &b], &mut services.objects);
let intersection = FaceFaceIntersection::compute([&a, &b]);

assert!(intersection.is_none());
}
Expand Down Expand Up @@ -133,15 +125,11 @@ mod tests {
face.build(&mut services.objects)
});

let intersection =
FaceFaceIntersection::compute([&a, &b], &mut services.objects);
let intersection = FaceFaceIntersection::compute([&a, &b]);

let expected_curves = surfaces.map(|_| {
let mut curve = PartialCurve::default();
curve.update_as_line_from_points([[0., 0.], [1., 0.]]);
curve
.build(&mut services.objects)
.insert(&mut services.objects)
let (path, _) = SurfacePath::line_from_points([[0., 0.], [1., 0.]]);
path
});
let expected_intervals =
CurveFaceIntersection::from_intervals([[[-1.], [1.]]]);
Expand Down
57 changes: 16 additions & 41 deletions crates/fj-kernel/src/algorithms/intersect/surface_surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,20 @@ use fj_math::{Line, Plane, Point, Scalar};

use crate::{
geometry::path::{GlobalPath, SurfacePath},
insert::Insert,
objects::{Curve, Objects, Surface},
services::Service,
objects::Surface,
storage::Handle,
};

/// The intersection between two surfaces
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct SurfaceSurfaceIntersection {
/// The intersection curves
pub intersection_curves: [Handle<Curve>; 2],
pub intersection_curves: [SurfacePath; 2],
}

impl SurfaceSurfaceIntersection {
/// Compute the intersection between two surfaces
pub fn compute(
surfaces: [Handle<Surface>; 2],
objects: &mut Service<Objects>,
) -> Option<Self> {
pub fn compute(surfaces: [Handle<Surface>; 2]) -> Option<Self> {
// Algorithm from Real-Time Collision Detection by Christer Ericson. See
// section 5.4.4, Intersection of Two Planes.
//
Expand Down Expand Up @@ -53,10 +48,8 @@ impl SurfaceSurfaceIntersection {

let line = Line::from_origin_and_direction(origin, direction);

let curves = planes.map(|plane| {
let path = SurfacePath::Line(plane.project_line(&line));
Curve::new(path).insert(objects)
});
let curves =
planes.map(|plane| SurfacePath::Line(plane.project_line(&line)));

Some(Self {
intersection_curves: curves,
Expand All @@ -83,10 +76,7 @@ mod tests {
use pretty_assertions::assert_eq;

use crate::{
algorithms::transform::TransformObject,
builder::CurveBuilder,
insert::Insert,
partial::{PartialCurve, PartialObject},
algorithms::transform::TransformObject, geometry::path::SurfacePath,
services::Services,
};

Expand All @@ -101,36 +91,21 @@ mod tests {

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

let mut expected_xy = PartialCurve::default();
expected_xy.update_as_u_axis();
let expected_xy = expected_xy
.build(&mut services.objects)
.insert(&mut services.objects);

let mut expected_xz = PartialCurve::default();
expected_xz.update_as_u_axis();
let expected_xz = expected_xz
.build(&mut services.objects)
.insert(&mut services.objects);
let expected_xy = SurfacePath::u_axis();
let expected_xz = SurfacePath::u_axis();

assert_eq!(
SurfaceSurfaceIntersection::compute(
[xy, xz],
&mut services.objects
),
SurfaceSurfaceIntersection::compute([xy, xz],),
Some(SurfaceSurfaceIntersection {
intersection_curves: [expected_xy, expected_xz],
})
Expand Down
16 changes: 7 additions & 9 deletions crates/fj-kernel/src/builder/curve.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use fj_math::{Point, Scalar, Vector};
use fj_math::{Point, Scalar};

use crate::{geometry::path::SurfacePath, partial::PartialCurve};

Expand Down Expand Up @@ -50,17 +50,15 @@ pub trait CurveBuilder {

impl CurveBuilder for PartialCurve {
fn update_as_u_axis(&mut self) -> SurfacePath {
let a = Point::origin();
let b = a + Vector::unit_u();

self.update_as_line_from_points([a, b])
let path = SurfacePath::u_axis();
self.path = Some(path.into());
path
}

fn update_as_v_axis(&mut self) -> SurfacePath {
let a = Point::origin();
let b = a + Vector::unit_v();

self.update_as_line_from_points([a, b])
let path = SurfacePath::v_axis();
self.path = Some(path.into());
path
}

fn update_as_circle_from_radius(
Expand Down
18 changes: 18 additions & 0 deletions crates/fj-kernel/src/geometry/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,24 @@ impl SurfacePath {
Self::Circle(Circle::from_center_and_radius(center, radius))
}

/// Build a line that represents the u-axis of the surface its on
pub fn u_axis() -> Self {
let a = Point::origin();
let b = a + Vector::unit_u();

let (self_, _) = Self::line_from_points([a, b]);
self_
}

/// Build a line that represents the v-axis of the surface its on
pub fn v_axis() -> Self {
let a = Point::origin();
let b = a + Vector::unit_v();

let (self_, _) = Self::line_from_points([a, b]);
self_
}

/// Construct a line from two points
///
/// Also returns the coordinates of the points on the path.
Expand Down

0 comments on commit eb6b27f

Please sign in to comment.