mirror of
https://github.com/hannobraun/Fornjot
synced 2025-01-26 18:16:11 +00:00
Merge pull request #1614 from hannobraun/intersect
Simplify intersection code that uses or produces curves
This commit is contained in:
commit
eb6b27f5be
@ -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
|
||||
@ -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"),
|
||||
};
|
||||
@ -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 {
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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.]]);
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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.]]);
|
||||
|
@ -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
|
||||
@ -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();
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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 = [
|
||||
|
@ -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};
|
||||
|
||||
@ -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
|
||||
///
|
||||
@ -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,
|
||||
};
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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());
|
||||
}
|
||||
@ -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.]]]);
|
||||
|
@ -2,9 +2,7 @@ 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,
|
||||
};
|
||||
|
||||
@ -12,15 +10,12 @@ use crate::{
|
||||
#[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.
|
||||
//
|
||||
@ -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,
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
use fj_math::{Point, Scalar, Vector};
|
||||
use fj_math::{Point, Scalar};
|
||||
|
||||
use crate::{geometry::path::SurfacePath, partial::PartialCurve};
|
||||
|
||||
@ -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(
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user