Skip to content

Commit

Permalink
Merge pull request #949 from hannobraun/ray
Browse files Browse the repository at this point in the history
Merge ray casting code into `intersect` module
  • Loading branch information
hannobraun authored Aug 12, 2022
2 parents 22e1c1f + 36c55d7 commit 4272929
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 137 deletions.
29 changes: 0 additions & 29 deletions crates/fj-kernel/src/algorithms/cast_ray/edge.rs

This file was deleted.

46 changes: 0 additions & 46 deletions crates/fj-kernel/src/algorithms/cast_ray/mod.rs

This file was deleted.

25 changes: 12 additions & 13 deletions crates/fj-kernel/src/algorithms/intersect/face_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
use fj_math::Point;

use crate::{
algorithms::cast_ray::{CastRay, HorizontalRayToTheRight, RaySegmentHit},
objects::Face,
};
use crate::objects::Face;

use super::Intersect;
use super::{
ray_segment::RaySegmentIntersection, HorizontalRayToTheRight, Intersect,
};

impl Intersect for (&Face, &Point<2>) {
type Intersection = FacePointIntersection;
Expand All @@ -29,23 +28,23 @@ impl Intersect for (&Face, &Point<2>) {
.edges()
.last()
.copied()
.and_then(|edge| edge.cast_ray(ray));
.and_then(|edge| (&ray, &edge).intersect());

for edge in cycle.edges() {
let hit = edge.cast_ray(ray);
let hit = (&ray, edge).intersect();

let count_hit = match (hit, previous_hit) {
(Some(RaySegmentHit::Segment), _) => {
(Some(RaySegmentIntersection::Segment), _) => {
// We're hitting a segment right-on. Clear case.
true
}
(
Some(RaySegmentHit::UpperVertex),
Some(RaySegmentHit::LowerVertex),
Some(RaySegmentIntersection::UpperVertex),
Some(RaySegmentIntersection::LowerVertex),
)
| (
Some(RaySegmentHit::LowerVertex),
Some(RaySegmentHit::UpperVertex),
Some(RaySegmentIntersection::LowerVertex),
Some(RaySegmentIntersection::UpperVertex),
) => {
// If we're hitting a vertex, only count it if we've hit
// the other kind of vertex right before.
Expand All @@ -62,7 +61,7 @@ impl Intersect for (&Face, &Point<2>) {
// passing through anything.
true
}
(Some(RaySegmentHit::Parallel), _) => {
(Some(RaySegmentIntersection::Parallel), _) => {
// A parallel edge must be completely ignored. Its
// presence won't change anything, so we can treat it as
// if it wasn't there, and its neighbors were connected
Expand Down
25 changes: 25 additions & 0 deletions crates/fj-kernel/src/algorithms/intersect/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
//! Intersection algorithms
pub mod face_point;
pub mod ray_edge;
pub mod ray_segment;

mod curve_edge;
mod curve_face;
mod face_face;
mod line_segment;
mod surface_surface;

use fj_math::Point;

pub use self::{
curve_edge::CurveEdgeIntersection,
curve_face::{CurveFaceIntersection, CurveFaceIntersectionInterval},
Expand All @@ -29,3 +33,24 @@ pub trait Intersect {
/// Compute the intersection between a tuple of objects
fn intersect(self) -> Option<Self::Intersection>;
}

/// A horizontal ray that goes to the right
///
/// For in-kernel use, we don't need anything more flexible, and being exactly
/// horizontal simplifies some calculations.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct HorizontalRayToTheRight<const D: usize> {
/// The point where the ray originates
pub origin: Point<D>,
}

impl<P, const D: usize> From<P> for HorizontalRayToTheRight<D>
where
P: Into<Point<D>>,
{
fn from(point: P) -> Self {
Self {
origin: point.into(),
}
}
}
33 changes: 33 additions & 0 deletions crates/fj-kernel/src/algorithms/intersect/ray_edge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//! Intersection between a ray and an edge in 2D
use fj_math::Segment;

use crate::{
algorithms::intersect::{HorizontalRayToTheRight, Intersect},
objects::{CurveKind, Edge},
};

use super::ray_segment::RaySegmentIntersection;

impl Intersect for (&HorizontalRayToTheRight<2>, &Edge) {
type Intersection = RaySegmentIntersection;

fn intersect(self) -> Option<Self::Intersection> {
let (ray, edge) = self;

let line = match edge.curve().kind() {
CurveKind::Line(line) => line,
CurveKind::Circle(_) => {
todo!("Casting rays against circles is not supported yet")
}
};

let points = edge.vertices().expect_vertices().map(|vertex| {
let point = vertex.position();
line.point_from_line_coords(point)
});
let segment = Segment::from_points(points);

(ray, &segment).intersect()
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
//! Intersection between a ray and a line segment in 2D
use fj_math::Segment;

use super::{CastRay, HorizontalRayToTheRight};
use super::{HorizontalRayToTheRight, Intersect};

impl Intersect for (&HorizontalRayToTheRight<2>, &Segment<2>) {
type Intersection = RaySegmentIntersection;

impl CastRay<2> for Segment<2> {
type Hit = RaySegmentHit;
fn intersect(self) -> Option<Self::Intersection> {
let (ray, segment) = self;

fn cast_ray(
&self,
ray: HorizontalRayToTheRight<2>,
) -> Option<RaySegmentHit> {
let [a, b] = self.points();
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 };

Expand All @@ -29,7 +30,7 @@ impl CastRay<2> for Segment<2> {
return None;
}

return Some(RaySegmentHit::Parallel);
return Some(RaySegmentIntersection::Parallel);
}

let pa = robust::Coord {
Expand All @@ -49,22 +50,22 @@ impl CastRay<2> for Segment<2> {
// ray starts on the line or left of it

if ray.origin.v == upper.v {
return Some(RaySegmentHit::UpperVertex);
return Some(RaySegmentIntersection::UpperVertex);
}
if ray.origin.v == lower.v {
return Some(RaySegmentHit::LowerVertex);
return Some(RaySegmentIntersection::LowerVertex);
}

return Some(RaySegmentHit::Segment);
return Some(RaySegmentIntersection::Segment);
}

None
}
}

/// A hit between a ray and a line segment
/// An intersection between a ray and a line segment
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RaySegmentHit {
pub enum RaySegmentIntersection {
/// The ray hit the segment itself
Segment,

Expand All @@ -82,9 +83,9 @@ pub enum RaySegmentHit {
mod tests {
use fj_math::Segment;

use crate::algorithms::cast_ray::CastRay;
use crate::algorithms::intersect::Intersect;

use super::{HorizontalRayToTheRight, RaySegmentHit};
use super::{HorizontalRayToTheRight, RaySegmentIntersection};

#[test]
fn hits_segment_right() {
Expand All @@ -94,11 +95,11 @@ mod tests {
let above = Segment::from([[1., 3.], [1., 4.]]);
let same_level = Segment::from([[1., 1.], [1., 3.]]);

assert!(below.cast_ray(ray).is_none());
assert!(above.cast_ray(ray).is_none());
assert!((&ray, &below).intersect().is_none());
assert!((&ray, &above).intersect().is_none());
assert!(matches!(
same_level.cast_ray(ray),
Some(RaySegmentHit::Segment)
(&ray, &same_level).intersect(),
Some(RaySegmentIntersection::Segment)
));
}

Expand All @@ -107,7 +108,7 @@ mod tests {
let ray = HorizontalRayToTheRight::from([1., 2.]);

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

#[test]
Expand All @@ -120,18 +121,18 @@ mod tests {
let hit_upper = Segment::from([[0., 0.], [2., 1.]]);
let hit_lower = Segment::from([[0., 2.], [2., 1.]]);

assert!(no_hit.cast_ray(ray).is_none());
assert!((&ray, &no_hit).intersect().is_none());
assert!(matches!(
hit_segment.cast_ray(ray),
Some(RaySegmentHit::Segment)
(&ray, &hit_segment).intersect(),
Some(RaySegmentIntersection::Segment)
));
assert!(matches!(
hit_upper.cast_ray(ray),
Some(RaySegmentHit::UpperVertex),
(&ray, &hit_upper).intersect(),
Some(RaySegmentIntersection::UpperVertex),
));
assert!(matches!(
hit_lower.cast_ray(ray),
Some(RaySegmentHit::LowerVertex),
(&ray, &hit_lower).intersect(),
Some(RaySegmentIntersection::LowerVertex),
));
}

Expand All @@ -144,16 +145,16 @@ mod tests {
let hit_lower = Segment::from([[1., 1.], [2., 2.]]);

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

Expand All @@ -165,11 +166,14 @@ mod tests {
let overlapping = Segment::from([[1., 0.], [3., 0.]]);
let right = Segment::from([[3., 0.], [4., 0.]]);

assert!(left.cast_ray(ray).is_none());
assert!((&ray, &left).intersect().is_none());
assert!(matches!(
(&ray, &overlapping).intersect(),
Some(RaySegmentIntersection::Parallel)
));
assert!(matches!(
overlapping.cast_ray(ray),
Some(RaySegmentHit::Parallel)
(&ray, &right).intersect(),
Some(RaySegmentIntersection::Parallel)
));
assert!(matches!(right.cast_ray(ray), Some(RaySegmentHit::Parallel)));
}
}
1 change: 0 additions & 1 deletion crates/fj-kernel/src/algorithms/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ mod sweep;
mod transform;
mod triangulate;

pub mod cast_ray;
pub mod intersect;

pub use self::{
Expand Down
Loading

0 comments on commit 4272929

Please sign in to comment.