Skip to content

Commit

Permalink
Merge pull request #888 from hannobraun/intersection
Browse files Browse the repository at this point in the history
Handle intersection of coincident curve/edge
  • Loading branch information
hannobraun authored Jul 29, 2022
2 parents 7684e10 + c7a5982 commit 1e22bc6
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 63 deletions.
149 changes: 94 additions & 55 deletions crates/fj-kernel/src/algorithms/intersection/curve_edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,24 @@ use crate::objects::{Curve, Edge};

/// The intersection between a [`Curve`] and an [`Edge`], in curve coordinates
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct CurveEdgeIntersection {
point_on_curve: Point<1>,
pub enum CurveEdgeIntersection {
/// The curve and edge intersect at a point
Point {
/// The intersection point, in curve coordinates on the curve
point_on_curve: Point<1>,
},

/// The edge lies on the curve
Coincident {
/// The first vertex of the edge, in curve coordinates
a_on_curve: Point<1>,

/// The second vertex of the edge, in curve coordinates
b_on_curve: Point<1>,
},
}

impl CurveEdgeIntersection {
/// Construct an instance from a point on a curve
pub fn from_point_on_curve(point_on_curve: impl Into<Point<1>>) -> Self {
let point_on_curve = point_on_curve.into();
Self { point_on_curve }
}

/// Compute the intersection
///
/// # Panics
Expand All @@ -29,26 +36,34 @@ impl CurveEdgeIntersection {
_ => todo!("Curve-edge intersection only supports lines"),
};

let edge_as_segment = {
let line = match edge.curve().local_form() {
Curve::Line(line) => line,
_ => {
todo!("Curve-edge intersection only supports line segments")
}
};

let vertices = match edge.vertices().get() {
Some(vertices) => vertices.map(|vertex| {
line.point_from_line_coords(vertex.position())
}),
None => todo!(
"Curve-edge intersection does not support continuous edges"
),
};

Segment::from_points(vertices)
let edge_curve_as_line = match edge.curve().local_form() {
Curve::Line(line) => line,
_ => {
todo!("Curve-edge intersection only supports line segments")
}
};

let edge_vertices = match edge.vertices().get() {
Some(vertices) => vertices.map(|vertex| {
edge_curve_as_line.point_from_line_coords(vertex.position())
}),
None => todo!(
"Curve-edge intersection does not support continuous edges"
),
};

let edge_as_segment = Segment::from_points(edge_vertices);

if curve_as_line.is_coincident_with(edge_curve_as_line) {
let [a_on_curve, b_on_curve] = edge_vertices
.map(|vertex| curve_as_line.point_to_line_coords(vertex));

return Some(Self::Coincident {
a_on_curve,
b_on_curve,
});
}

let ray = Ray {
origin: curve_as_line.origin.to_na(),
dir: curve_as_line.direction.to_na(),
Expand All @@ -70,23 +85,18 @@ impl CurveEdgeIntersection {
);

if let Some(result) = result {
return Some(Self {
return Some(Self::Point {
point_on_curve: Point::from([result]),
});
}
if let Some(result_inv) = result_inv {
return Some(Self {
return Some(Self::Point {
point_on_curve: Point::from([-result_inv]),
});
}

None
}

/// Access the intersection point on the curve
pub fn point_on_curve(&self) -> Point<1> {
self.point_on_curve
}
}

#[cfg(test)]
Expand All @@ -98,37 +108,66 @@ mod tests {
use super::CurveEdgeIntersection;

#[test]
fn compute() {
fn compute_edge_in_front_of_curve_origin() {
let surface = Surface::xy_plane();

let curve = Curve::u_axis();
let edge = Edge::build()
.line_segment_from_points(&surface, [[1., -1.], [1., 1.]]);

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

let edge_left = Edge::build()
assert_eq!(
intersection,
Some(CurveEdgeIntersection::Point {
point_on_curve: Point::from([1.])
})
);
}

#[test]
fn compute_edge_behind_curve_origin() {
let surface = Surface::xy_plane();
let curve = Curve::u_axis();
let edge = Edge::build()
.line_segment_from_points(&surface, [[-1., -1.], [-1., 1.]]);
let edge_right = Edge::build()
.line_segment_from_points(&surface, [[1., -1.], [1., 1.]]);
let edge_below = Edge::build()
.line_segment_from_points(&surface, [[-1., -1.], [1., -1.]]);

let intersection_with_edge_left =
CurveEdgeIntersection::compute(&curve, &edge_left);
let intersection_with_edge_right =
CurveEdgeIntersection::compute(&curve, &edge_right);
let intersection_with_edge_below =
CurveEdgeIntersection::compute(&curve, &edge_below);
let intersection = CurveEdgeIntersection::compute(&curve, &edge);

assert_eq!(
intersection_with_edge_left,
Some(CurveEdgeIntersection::from_point_on_curve(Point::from([
-1.
])))
intersection,
Some(CurveEdgeIntersection::Point {
point_on_curve: Point::from([-1.])
})
);
}

#[test]
fn compute_edge_parallel_to_curve() {
let surface = Surface::xy_plane();
let curve = Curve::u_axis();
let edge = Edge::build()
.line_segment_from_points(&surface, [[-1., -1.], [1., -1.]]);

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

assert!(intersection.is_none());
}

#[test]
fn compute_edge_on_curve() {
let surface = Surface::xy_plane();
let curve = Curve::u_axis();
let edge = Edge::build()
.line_segment_from_points(&surface, [[-1., 0.], [1., 0.]]);

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

assert_eq!(
intersection_with_edge_right,
Some(CurveEdgeIntersection::from_point_on_curve(Point::from([
1.
])))
intersection,
Some(CurveEdgeIntersection::Coincident {
a_on_curve: Point::from([-1.]),
b_on_curve: Point::from([1.]),
})
);
assert!(intersection_with_edge_below.is_none());
}
}
23 changes: 15 additions & 8 deletions crates/fj-kernel/src/algorithms/intersection/curve_face.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ impl CurveFaceIntersectionList {
) -> Self {
let intervals = intervals
.into_iter()
.map(|interval| {
interval
.map(Into::into)
.map(CurveEdgeIntersection::from_point_on_curve)
})
.map(|interval| interval.map(Into::into))
.collect();
Self { intervals }
}
Expand All @@ -44,7 +40,18 @@ impl CurveFaceIntersectionList {
let intersection = CurveEdgeIntersection::compute(curve, &edge);

if let Some(intersection) = intersection {
intersections.push(intersection);
match intersection {
CurveEdgeIntersection::Point { point_on_curve } => {
intersections.push(point_on_curve);
}
CurveEdgeIntersection::Coincident {
a_on_curve,
b_on_curve,
} => {
intersections.push(a_on_curve);
intersections.push(b_on_curve);
}
}
}
}

Expand All @@ -57,7 +64,7 @@ impl CurveFaceIntersectionList {
let intervals = intersections
.chunks(2)
.map(|chunk| {
// Can't panic, as we passed `2` to `windows`.
// Can't panic, as we passed `2` to `chunks`.
[chunk[0], chunk[1]]
})
.collect();
Expand Down Expand Up @@ -133,7 +140,7 @@ impl IntoIterator for CurveFaceIntersectionList {
}

/// An intersection between a curve and a face, in curve coordinates
pub type CurveFaceIntersection = [CurveEdgeIntersection; 2];
pub type CurveFaceIntersection = [Point<1>; 2];

#[cfg(test)]
mod tests {
Expand Down

0 comments on commit 1e22bc6

Please sign in to comment.