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

Merge ray casting code into intersect module #949

Merged
merged 7 commits into from
Aug 12, 2022
Merged
Show file tree
Hide file tree
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
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