Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more information to Face/Point intersection result #977

Merged
merged 5 commits into from
Aug 22, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 79 additions & 17 deletions crates/fj-kernel/src/algorithms/intersect/face_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use fj_math::Point;

use crate::objects::Face;
use crate::objects::{Edge, Face, Vertex};

use super::{
ray_segment::RaySegmentIntersection, HorizontalRayToTheRight, Intersect,
Expand Down Expand Up @@ -35,17 +35,26 @@ impl Intersect for (&Face, &Point<2>) {

let count_hit = match (hit, previous_hit) {
(
Some(
RaySegmentIntersection::RayStartsOnSegment
| RaySegmentIntersection::RayStartsOnOnFirstVertex
| RaySegmentIntersection::RayStartsOnSecondVertex,
),
Some(RaySegmentIntersection::RayStartsOnSegment),
_,
) => {
// If the ray starts on the boundary of the face,
// there's nothing to else check. By the definition of
// this intersection test, the face contains the point.
return Some(FacePointIntersection::FaceContainsPoint);
// there's nothing to else check.
return Some(
FacePointIntersection::PointIsOnEdge(*edge)
);
}
(Some(RaySegmentIntersection::RayStartsOnOnFirstVertex), _) => {
let vertex = edge.vertices().expect_vertices()[0];
return Some(
FacePointIntersection::PointIsOnVertex(vertex)
);
}
(Some(RaySegmentIntersection::RayStartsOnSecondVertex), _) => {
let vertex = edge.vertices().expect_vertices()[1];
return Some(
FacePointIntersection::PointIsOnVertex(vertex)
);
}
(Some(RaySegmentIntersection::RayHitsSegment), _) => {
// We're hitting a segment right-on. Clear case.
Expand Down Expand Up @@ -96,7 +105,7 @@ impl Intersect for (&Face, &Point<2>) {
}

if num_hits % 2 == 1 {
Some(FacePointIntersection::FaceContainsPoint)
Some(FacePointIntersection::PointIsInsideFace)
} else {
None
}
Expand All @@ -107,15 +116,23 @@ impl Intersect for (&Face, &Point<2>) {
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum FacePointIntersection {
/// The point is inside of the face
FaceContainsPoint,
PointIsInsideFace,

/// The point is coincident with an edge
PointIsOnEdge(Edge),

/// The point is coincident with a vertex
PointIsOnVertex(Vertex),
}

#[cfg(test)]
mod tests {
use fj_math::Point;
use pretty_assertions::assert_eq;

use crate::{
algorithms::intersect::{face_point::FacePointIntersection, Intersect},
iter::ObjectIters,
objects::{Face, Surface},
};

Expand All @@ -140,22 +157,21 @@ mod tests {
let intersection = (&face, &point).intersect();
assert_eq!(
intersection,
Some(FacePointIntersection::FaceContainsPoint)
Some(FacePointIntersection::PointIsInsideFace)
);
}

#[test]
fn ray_hits_vertex_at_cycle_seam() {
let face = Face::build(Surface::xy_plane())
.polygon_from_points([[4., 2.], [0., 4.], [0., 0.]])
.with_hole([[1., 1.], [2., 1.], [1., 3.]])
.into_face();
let point = Point::from([1., 2.]);

let intersection = (&face, &point).intersect();
assert_eq!(
intersection,
Some(FacePointIntersection::FaceContainsPoint)
Some(FacePointIntersection::PointIsInsideFace)
);
}

Expand All @@ -169,7 +185,7 @@ mod tests {
let intersection = (&face, &point).intersect();
assert_eq!(
intersection,
Some(FacePointIntersection::FaceContainsPoint)
Some(FacePointIntersection::PointIsInsideFace)
);
}

Expand All @@ -183,7 +199,7 @@ mod tests {
let intersection = (&face, &point).intersect();
assert_eq!(
intersection,
Some(FacePointIntersection::FaceContainsPoint)
Some(FacePointIntersection::PointIsInsideFace)
);
}

Expand All @@ -203,7 +219,53 @@ mod tests {
let intersection = (&face, &point).intersect();
assert_eq!(
intersection,
Some(FacePointIntersection::FaceContainsPoint)
Some(FacePointIntersection::PointIsInsideFace)
);
}

#[test]
fn point_is_coincident_with_edge() {
let face = Face::build(Surface::xy_plane())
.polygon_from_points([[0., 0.], [2., 0.], [0., 1.]])
.into_face();
let point = Point::from([1., 0.]);

let intersection = (&face, &point).intersect();

let edge = face
.edge_iter()
.copied()
.find(|edge| {
let [a, b] = edge.vertices().expect_vertices();
a.global().position() == Point::from([0., 0., 0.])
&& b.global().position() == Point::from([2., 0., 0.])
})
.unwrap();
assert_eq!(
intersection,
Some(FacePointIntersection::PointIsOnEdge(edge))
);
}

#[test]
fn point_is_coincident_with_vertex() {
let face = Face::build(Surface::xy_plane())
.polygon_from_points([[0., 0.], [1., 0.], [0., 1.]])
.into_face();
let point = Point::from([1., 0.]);

let intersection = (&face, &point).intersect();

let vertex = face
.vertex_iter()
.copied()
.find(|vertex| {
vertex.global().position() == Point::from([1., 0., 0.])
})
.unwrap();
assert_eq!(
intersection,
Some(FacePointIntersection::PointIsOnVertex(vertex))
);
}
}