mirror of
https://github.com/hannobraun/Fornjot
synced 2025-01-27 10:29:28 +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 fj_math::{Point, Segment};
|
||||||
|
|
||||||
use crate::{
|
use crate::{geometry::path::SurfacePath, objects::HalfEdge};
|
||||||
geometry::path::SurfacePath,
|
|
||||||
objects::{Curve, HalfEdge},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::LineSegmentIntersection;
|
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)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||||
pub enum CurveEdgeIntersection {
|
pub enum CurveEdgeIntersection {
|
||||||
/// The curve and edge intersect at a point
|
/// The curve and edge intersect at a point
|
||||||
@ -29,10 +26,10 @@ impl CurveEdgeIntersection {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Currently, only intersections between lines and line segments can be
|
/// 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.
|
/// passed.
|
||||||
pub fn compute(curve: &Curve, half_edge: &HalfEdge) -> Option<Self> {
|
pub fn compute(curve: &SurfacePath, half_edge: &HalfEdge) -> Option<Self> {
|
||||||
let curve_as_line = match curve.path() {
|
let curve_as_line = match curve {
|
||||||
SurfacePath::Line(line) => line,
|
SurfacePath::Line(line) => line,
|
||||||
_ => todo!("Curve-edge intersection only supports lines"),
|
_ => todo!("Curve-edge intersection only supports lines"),
|
||||||
};
|
};
|
||||||
@ -53,7 +50,7 @@ impl CurveEdgeIntersection {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let intersection =
|
let intersection =
|
||||||
LineSegmentIntersection::compute(&curve_as_line, &edge_as_segment)?;
|
LineSegmentIntersection::compute(curve_as_line, &edge_as_segment)?;
|
||||||
|
|
||||||
let intersection = match intersection {
|
let intersection = match intersection {
|
||||||
LineSegmentIntersection::Point { point_on_line } => Self::Point {
|
LineSegmentIntersection::Point { point_on_line } => Self::Point {
|
||||||
@ -75,8 +72,9 @@ mod tests {
|
|||||||
use fj_math::Point;
|
use fj_math::Point;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
builder::{CurveBuilder, HalfEdgeBuilder},
|
builder::HalfEdgeBuilder,
|
||||||
partial::{PartialCurve, PartialHalfEdge, PartialObject},
|
geometry::path::SurfacePath,
|
||||||
|
partial::{PartialHalfEdge, PartialObject},
|
||||||
services::Services,
|
services::Services,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -87,9 +85,7 @@ mod tests {
|
|||||||
let mut services = Services::new();
|
let mut services = Services::new();
|
||||||
|
|
||||||
let surface = services.objects.surfaces.xy_plane();
|
let surface = services.objects.surfaces.xy_plane();
|
||||||
let mut curve = PartialCurve::default();
|
let curve = SurfacePath::u_axis();
|
||||||
curve.update_as_u_axis();
|
|
||||||
let curve = curve.build(&mut services.objects);
|
|
||||||
let half_edge = {
|
let half_edge = {
|
||||||
let mut half_edge = PartialHalfEdge::default();
|
let mut half_edge = PartialHalfEdge::default();
|
||||||
half_edge.update_as_line_segment_from_points([[1., -1.], [1., 1.]]);
|
half_edge.update_as_line_segment_from_points([[1., -1.], [1., 1.]]);
|
||||||
@ -113,9 +109,7 @@ mod tests {
|
|||||||
let mut services = Services::new();
|
let mut services = Services::new();
|
||||||
|
|
||||||
let surface = services.objects.surfaces.xy_plane();
|
let surface = services.objects.surfaces.xy_plane();
|
||||||
let mut curve = PartialCurve::default();
|
let curve = SurfacePath::u_axis();
|
||||||
curve.update_as_u_axis();
|
|
||||||
let curve = curve.build(&mut services.objects);
|
|
||||||
let half_edge = {
|
let half_edge = {
|
||||||
let mut half_edge = PartialHalfEdge::default();
|
let mut half_edge = PartialHalfEdge::default();
|
||||||
half_edge
|
half_edge
|
||||||
@ -140,9 +134,7 @@ mod tests {
|
|||||||
let mut services = Services::new();
|
let mut services = Services::new();
|
||||||
|
|
||||||
let surface = services.objects.surfaces.xy_plane();
|
let surface = services.objects.surfaces.xy_plane();
|
||||||
let mut curve = PartialCurve::default();
|
let curve = SurfacePath::u_axis();
|
||||||
curve.update_as_u_axis();
|
|
||||||
let curve = curve.build(&mut services.objects);
|
|
||||||
let half_edge = {
|
let half_edge = {
|
||||||
let mut half_edge = PartialHalfEdge::default();
|
let mut half_edge = PartialHalfEdge::default();
|
||||||
half_edge
|
half_edge
|
||||||
@ -162,9 +154,7 @@ mod tests {
|
|||||||
let mut services = Services::new();
|
let mut services = Services::new();
|
||||||
|
|
||||||
let surface = services.objects.surfaces.xy_plane();
|
let surface = services.objects.surfaces.xy_plane();
|
||||||
let mut curve = PartialCurve::default();
|
let curve = SurfacePath::u_axis();
|
||||||
curve.update_as_u_axis();
|
|
||||||
let curve = curve.build(&mut services.objects);
|
|
||||||
let half_edge = {
|
let half_edge = {
|
||||||
let mut half_edge = PartialHalfEdge::default();
|
let mut half_edge = PartialHalfEdge::default();
|
||||||
half_edge.update_as_line_segment_from_points([[-1., 0.], [1., 0.]]);
|
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_interop::ext::SliceExt;
|
||||||
use fj_math::Point;
|
use fj_math::Point;
|
||||||
|
|
||||||
use crate::objects::{Curve, Face};
|
use crate::{geometry::path::SurfacePath, objects::Face};
|
||||||
|
|
||||||
use super::CurveEdgeIntersection;
|
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)]
|
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||||
pub struct CurveFaceIntersection {
|
pub struct CurveFaceIntersection {
|
||||||
/// The intervals where the curve and face intersect, in curve coordinates
|
/// The intervals where the curve and face intersect, in curve coordinates
|
||||||
@ -27,8 +27,8 @@ impl CurveFaceIntersection {
|
|||||||
Self { intervals }
|
Self { intervals }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the intersections between a [`Curve`] and a [`Face`]
|
/// Compute the intersection
|
||||||
pub fn compute(curve: &Curve, face: &Face) -> Self {
|
pub fn compute(curve: &SurfacePath, face: &Face) -> Self {
|
||||||
let half_edges = face.all_cycles().flat_map(|cycle| cycle.half_edges());
|
let half_edges = face.all_cycles().flat_map(|cycle| cycle.half_edges());
|
||||||
|
|
||||||
let mut intersections = Vec::new();
|
let mut intersections = Vec::new();
|
||||||
@ -150,8 +150,9 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
builder::{CurveBuilder, CycleBuilder, FaceBuilder},
|
builder::{CycleBuilder, FaceBuilder},
|
||||||
partial::{Partial, PartialCurve, PartialFace, PartialObject},
|
geometry::path::SurfacePath,
|
||||||
|
partial::{Partial, PartialFace, PartialObject},
|
||||||
services::Services,
|
services::Services,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -161,9 +162,7 @@ mod tests {
|
|||||||
fn compute() {
|
fn compute() {
|
||||||
let mut services = Services::new();
|
let mut services = Services::new();
|
||||||
|
|
||||||
let mut curve = PartialCurve::default();
|
let (curve, _) = SurfacePath::line_from_points([[-3., 0.], [-2., 0.]]);
|
||||||
curve.update_as_line_from_points([[-3., 0.], [-2., 0.]]);
|
|
||||||
let curve = curve.build(&mut services.objects);
|
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let exterior = [
|
let exterior = [
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
use fj_interop::ext::ArrayExt;
|
use fj_interop::ext::ArrayExt;
|
||||||
use iter_fixed::IntoIteratorFixed;
|
use iter_fixed::IntoIteratorFixed;
|
||||||
|
|
||||||
use crate::{
|
use crate::{geometry::path::SurfacePath, objects::Face};
|
||||||
objects::{Curve, Face, Objects},
|
|
||||||
services::Service,
|
|
||||||
storage::Handle,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{CurveFaceIntersection, SurfaceSurfaceIntersection};
|
use super::{CurveFaceIntersection, SurfaceSurfaceIntersection};
|
||||||
|
|
||||||
@ -18,7 +14,7 @@ pub struct FaceFaceIntersection {
|
|||||||
/// representation of the intersection on the respective face's surface.
|
/// representation of the intersection on the respective face's surface.
|
||||||
///
|
///
|
||||||
/// They both represent the same global curve.
|
/// 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
|
/// The interval of this intersection, in curve coordinates
|
||||||
///
|
///
|
||||||
@ -28,14 +24,11 @@ pub struct FaceFaceIntersection {
|
|||||||
|
|
||||||
impl FaceFaceIntersection {
|
impl FaceFaceIntersection {
|
||||||
/// Compute the intersections between two faces
|
/// Compute the intersections between two faces
|
||||||
pub fn compute(
|
pub fn compute(faces: [&Face; 2]) -> Option<Self> {
|
||||||
faces: [&Face; 2],
|
|
||||||
objects: &mut Service<Objects>,
|
|
||||||
) -> Option<Self> {
|
|
||||||
let surfaces = faces.map(|face| face.surface().clone());
|
let surfaces = faces.map(|face| face.surface().clone());
|
||||||
|
|
||||||
let intersection_curves =
|
let intersection_curves =
|
||||||
match SurfaceSurfaceIntersection::compute(surfaces, objects) {
|
match SurfaceSurfaceIntersection::compute(surfaces) {
|
||||||
Some(intersection) => intersection.intersection_curves,
|
Some(intersection) => intersection.intersection_curves,
|
||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
@ -69,9 +62,9 @@ mod tests {
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algorithms::intersect::CurveFaceIntersection,
|
algorithms::intersect::CurveFaceIntersection,
|
||||||
builder::{CurveBuilder, CycleBuilder},
|
builder::CycleBuilder,
|
||||||
insert::Insert,
|
geometry::path::SurfacePath,
|
||||||
partial::{Partial, PartialCurve, PartialFace, PartialObject},
|
partial::{Partial, PartialFace, PartialObject},
|
||||||
services::Services,
|
services::Services,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -102,8 +95,7 @@ mod tests {
|
|||||||
face.build(&mut services.objects)
|
face.build(&mut services.objects)
|
||||||
});
|
});
|
||||||
|
|
||||||
let intersection =
|
let intersection = FaceFaceIntersection::compute([&a, &b]);
|
||||||
FaceFaceIntersection::compute([&a, &b], &mut services.objects);
|
|
||||||
|
|
||||||
assert!(intersection.is_none());
|
assert!(intersection.is_none());
|
||||||
}
|
}
|
||||||
@ -133,15 +125,11 @@ mod tests {
|
|||||||
face.build(&mut services.objects)
|
face.build(&mut services.objects)
|
||||||
});
|
});
|
||||||
|
|
||||||
let intersection =
|
let intersection = FaceFaceIntersection::compute([&a, &b]);
|
||||||
FaceFaceIntersection::compute([&a, &b], &mut services.objects);
|
|
||||||
|
|
||||||
let expected_curves = surfaces.map(|_| {
|
let expected_curves = surfaces.map(|_| {
|
||||||
let mut curve = PartialCurve::default();
|
let (path, _) = SurfacePath::line_from_points([[0., 0.], [1., 0.]]);
|
||||||
curve.update_as_line_from_points([[0., 0.], [1., 0.]]);
|
path
|
||||||
curve
|
|
||||||
.build(&mut services.objects)
|
|
||||||
.insert(&mut services.objects)
|
|
||||||
});
|
});
|
||||||
let expected_intervals =
|
let expected_intervals =
|
||||||
CurveFaceIntersection::from_intervals([[[-1.], [1.]]]);
|
CurveFaceIntersection::from_intervals([[[-1.], [1.]]]);
|
||||||
|
@ -2,9 +2,7 @@ use fj_math::{Line, Plane, Point, Scalar};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::path::{GlobalPath, SurfacePath},
|
geometry::path::{GlobalPath, SurfacePath},
|
||||||
insert::Insert,
|
objects::Surface,
|
||||||
objects::{Curve, Objects, Surface},
|
|
||||||
services::Service,
|
|
||||||
storage::Handle,
|
storage::Handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -12,15 +10,12 @@ use crate::{
|
|||||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||||
pub struct SurfaceSurfaceIntersection {
|
pub struct SurfaceSurfaceIntersection {
|
||||||
/// The intersection curves
|
/// The intersection curves
|
||||||
pub intersection_curves: [Handle<Curve>; 2],
|
pub intersection_curves: [SurfacePath; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SurfaceSurfaceIntersection {
|
impl SurfaceSurfaceIntersection {
|
||||||
/// Compute the intersection between two surfaces
|
/// Compute the intersection between two surfaces
|
||||||
pub fn compute(
|
pub fn compute(surfaces: [Handle<Surface>; 2]) -> Option<Self> {
|
||||||
surfaces: [Handle<Surface>; 2],
|
|
||||||
objects: &mut Service<Objects>,
|
|
||||||
) -> Option<Self> {
|
|
||||||
// Algorithm from Real-Time Collision Detection by Christer Ericson. See
|
// Algorithm from Real-Time Collision Detection by Christer Ericson. See
|
||||||
// section 5.4.4, Intersection of Two Planes.
|
// section 5.4.4, Intersection of Two Planes.
|
||||||
//
|
//
|
||||||
@ -53,10 +48,8 @@ impl SurfaceSurfaceIntersection {
|
|||||||
|
|
||||||
let line = Line::from_origin_and_direction(origin, direction);
|
let line = Line::from_origin_and_direction(origin, direction);
|
||||||
|
|
||||||
let curves = planes.map(|plane| {
|
let curves =
|
||||||
let path = SurfacePath::Line(plane.project_line(&line));
|
planes.map(|plane| SurfacePath::Line(plane.project_line(&line)));
|
||||||
Curve::new(path).insert(objects)
|
|
||||||
});
|
|
||||||
|
|
||||||
Some(Self {
|
Some(Self {
|
||||||
intersection_curves: curves,
|
intersection_curves: curves,
|
||||||
@ -83,10 +76,7 @@ mod tests {
|
|||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algorithms::transform::TransformObject,
|
algorithms::transform::TransformObject, geometry::path::SurfacePath,
|
||||||
builder::CurveBuilder,
|
|
||||||
insert::Insert,
|
|
||||||
partial::{PartialCurve, PartialObject},
|
|
||||||
services::Services,
|
services::Services,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -101,36 +91,21 @@ mod tests {
|
|||||||
|
|
||||||
// Coincident and parallel planes don't have an intersection curve.
|
// Coincident and parallel planes don't have an intersection curve.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
SurfaceSurfaceIntersection::compute(
|
SurfaceSurfaceIntersection::compute([
|
||||||
[
|
xy.clone(),
|
||||||
xy.clone(),
|
xy.clone().transform(
|
||||||
xy.clone().transform(
|
&Transform::translation([0., 0., 1.],),
|
||||||
&Transform::translation([0., 0., 1.],),
|
&mut services.objects
|
||||||
&mut services.objects
|
)
|
||||||
)
|
],),
|
||||||
],
|
|
||||||
&mut services.objects
|
|
||||||
),
|
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut expected_xy = PartialCurve::default();
|
let expected_xy = SurfacePath::u_axis();
|
||||||
expected_xy.update_as_u_axis();
|
let expected_xz = SurfacePath::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);
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
SurfaceSurfaceIntersection::compute(
|
SurfaceSurfaceIntersection::compute([xy, xz],),
|
||||||
[xy, xz],
|
|
||||||
&mut services.objects
|
|
||||||
),
|
|
||||||
Some(SurfaceSurfaceIntersection {
|
Some(SurfaceSurfaceIntersection {
|
||||||
intersection_curves: [expected_xy, expected_xz],
|
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};
|
use crate::{geometry::path::SurfacePath, partial::PartialCurve};
|
||||||
|
|
||||||
@ -50,17 +50,15 @@ pub trait CurveBuilder {
|
|||||||
|
|
||||||
impl CurveBuilder for PartialCurve {
|
impl CurveBuilder for PartialCurve {
|
||||||
fn update_as_u_axis(&mut self) -> SurfacePath {
|
fn update_as_u_axis(&mut self) -> SurfacePath {
|
||||||
let a = Point::origin();
|
let path = SurfacePath::u_axis();
|
||||||
let b = a + Vector::unit_u();
|
self.path = Some(path.into());
|
||||||
|
path
|
||||||
self.update_as_line_from_points([a, b])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_as_v_axis(&mut self) -> SurfacePath {
|
fn update_as_v_axis(&mut self) -> SurfacePath {
|
||||||
let a = Point::origin();
|
let path = SurfacePath::v_axis();
|
||||||
let b = a + Vector::unit_v();
|
self.path = Some(path.into());
|
||||||
|
path
|
||||||
self.update_as_line_from_points([a, b])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_as_circle_from_radius(
|
fn update_as_circle_from_radius(
|
||||||
|
@ -43,6 +43,24 @@ impl SurfacePath {
|
|||||||
Self::Circle(Circle::from_center_and_radius(center, radius))
|
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
|
/// Construct a line from two points
|
||||||
///
|
///
|
||||||
/// Also returns the coordinates of the points on the path.
|
/// Also returns the coordinates of the points on the path.
|
||||||
|
Loading…
Reference in New Issue
Block a user