Skip to content

Commit

Permalink
Merge pull request #950 from hannobraun/ray-segment
Browse files Browse the repository at this point in the history
Return more information from ray/segment intersection
  • Loading branch information
hannobraun authored Aug 12, 2022
2 parents 4272929 + b33399f commit f536e77
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 14 deletions.
13 changes: 13 additions & 0 deletions crates/fj-kernel/src/algorithms/intersect/face_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ impl Intersect for (&Face, &Point<2>) {
let hit = (&ray, edge).intersect();

let count_hit = match (hit, previous_hit) {
(
Some(
RaySegmentIntersection::OnSegment
| RaySegmentIntersection::OnFirstVertex
| RaySegmentIntersection::OnSecondVertex,
),
_,
) => {
// 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);
}
(Some(RaySegmentIntersection::Segment), _) => {
// We're hitting a segment right-on. Clear case.
true
Expand Down
77 changes: 63 additions & 14 deletions crates/fj-kernel/src/algorithms/intersect/ray_segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ impl Intersect for (&HorizontalRayToTheRight<2>, &Segment<2>) {

let [a, b] = segment.points();
let [lower, upper] = if a.v <= b.v { [a, b] } else { [b, a] };
let right = if a.u > b.u { a } else { b };
let [left, right] = if a.u <= b.u { [a, b] } else { [b, a] };

if ray.origin.v > upper.v {
// ray is above segment
Expand All @@ -30,6 +30,16 @@ impl Intersect for (&HorizontalRayToTheRight<2>, &Segment<2>) {
return None;
}

if ray.origin.u == a.u {
return Some(RaySegmentIntersection::OnFirstVertex);
}
if ray.origin.u == b.u {
return Some(RaySegmentIntersection::OnSecondVertex);
}
if ray.origin.u > left.u && ray.origin.u < right.u {
return Some(RaySegmentIntersection::OnSegment);
}

return Some(RaySegmentIntersection::Parallel);
}

Expand All @@ -46,8 +56,21 @@ impl Intersect for (&HorizontalRayToTheRight<2>, &Segment<2>) {
y: ray.origin.v,
};

if robust::orient2d(pa, pb, pc) >= 0. {
// ray starts on the line or left of it
if robust::orient2d(pa, pb, pc) == 0. {
// ray starts on the line

if ray.origin.v == a.v {
return Some(RaySegmentIntersection::OnFirstVertex);
}
if ray.origin.v == b.v {
return Some(RaySegmentIntersection::OnSecondVertex);
}

return Some(RaySegmentIntersection::OnSegment);
}

if robust::orient2d(pa, pb, pc) > 0. {
// ray starts left of the line

if ray.origin.v == upper.v {
return Some(RaySegmentIntersection::UpperVertex);
Expand Down Expand Up @@ -77,6 +100,15 @@ pub enum RaySegmentIntersection {

/// The ray hit the whole segment, as it is parallel to the ray
Parallel,

/// The ray starts on the segment
OnSegment,

/// The ray starts on the first vertex of the segment
OnFirstVertex,

/// The ray starts on the second vertex of the segment
OnSecondVertex,
}

#[cfg(test)]
Expand All @@ -88,7 +120,7 @@ mod tests {
use super::{HorizontalRayToTheRight, RaySegmentIntersection};

#[test]
fn hits_segment_right() {
fn ray_is_left_of_segment() {
let ray = HorizontalRayToTheRight::from([0., 2.]);

let below = Segment::from([[1., 0.], [1., 1.]]);
Expand All @@ -104,15 +136,15 @@ mod tests {
}

#[test]
fn hits_segment_left() {
fn ray_is_right_of_segment() {
let ray = HorizontalRayToTheRight::from([1., 2.]);

let same_level = Segment::from([[0., 1.], [0., 3.]]);
assert!((&ray, &same_level).intersect().is_none());
}

#[test]
fn hits_segment_overlapping() {
fn ray_overlaps_with_segment_along_x_axis() {
let ray = HorizontalRayToTheRight::from([1., 1.]);

let no_hit = Segment::from([[0., 0.], [2., 3.]]);
Expand All @@ -137,7 +169,7 @@ mod tests {
}

#[test]
fn hits_segment_on_segment() {
fn ray_starts_on_segment() {
let ray = HorizontalRayToTheRight::from([1., 1.]);

let hit_segment = Segment::from([[0., 0.], [2., 2.]]);
Expand All @@ -146,34 +178,51 @@ mod tests {

assert!(matches!(
(&ray, &hit_segment).intersect(),
Some(RaySegmentIntersection::Segment)
Some(RaySegmentIntersection::OnSegment)
));
assert!(matches!(
(&ray, &hit_upper).intersect(),
Some(RaySegmentIntersection::UpperVertex),
Some(RaySegmentIntersection::OnSecondVertex),
));
assert!(matches!(
(&ray, &hit_lower).intersect(),
Some(RaySegmentIntersection::LowerVertex),
Some(RaySegmentIntersection::OnFirstVertex),
));
}

#[test]
fn hits_segment_parallel() {
fn ray_and_segment_are_parallel_and_on_same_level() {
let ray = HorizontalRayToTheRight::from([2., 0.]);

let left = Segment::from([[0., 0.], [1., 0.]]);
let overlapping = Segment::from([[1., 0.], [3., 0.]]);
let right = Segment::from([[3., 0.], [4., 0.]]);

assert!((&ray, &left).intersect().is_none());
assert!(matches!(
(&ray, &overlapping).intersect(),
(&ray, &right).intersect(),
Some(RaySegmentIntersection::Parallel)
));
}

#[test]
fn ray_starts_on_parallel_segment() {
let ray = HorizontalRayToTheRight::from([2., 0.]);

let left = Segment::from([[0., 0.], [2., 0.]]);
let overlapping = Segment::from([[1., 0.], [3., 0.]]);
let right = Segment::from([[2., 0.], [4., 0.]]);

assert!(matches!(
(&ray, &left).intersect(),
Some(RaySegmentIntersection::OnSecondVertex)
));
assert!(matches!(
(&ray, &overlapping).intersect(),
Some(RaySegmentIntersection::OnSegment),
));
assert!(matches!(
(&ray, &right).intersect(),
Some(RaySegmentIntersection::Parallel)
Some(RaySegmentIntersection::OnFirstVertex),
));
}
}
14 changes: 14 additions & 0 deletions crates/fj-kernel/src/algorithms/triangulate/polygon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,20 @@ impl Polygon {
let hit = (&ray, &edge).intersect();

let count_hit = match (hit, previous_hit) {
(
Some(
RaySegmentIntersection::OnSegment
| RaySegmentIntersection::OnFirstVertex
| RaySegmentIntersection::OnSecondVertex,
),
_,
) => {
// If the ray starts on the boundary of the polygon,
// there's nothing else to check. By the definition of
// this intersection test, the polygon contains the
// point.
return true;
}
(Some(RaySegmentIntersection::Segment), _) => {
// We're hitting a segment right-on. Clear case.
true
Expand Down

0 comments on commit f536e77

Please sign in to comment.