Skip to content

Commit

Permalink
v3: return normal for ray cast
Browse files Browse the repository at this point in the history
  • Loading branch information
jcornaz committed Aug 23, 2023
1 parent dfb9339 commit b828de0
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 3 deletions.
14 changes: 13 additions & 1 deletion src/v3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,26 +64,38 @@ where
fn cast(&self, vector: Vec2, target: &B) -> Option<CastHit> {
let mut max_t1 = f32::MIN;
let mut min_t2 = f32::MAX;
let mut normal = Vec2::ZERO;
for axis in sat_axes(self, target) {
let Some((t1, t2)) = cast_projection(
self.project_on(axis),
vector.dot(axis),
target.project_on(axis),
) else { return None };
if t1 > max_t1 {
max_t1 = t1;
normal = axis;
}
max_t1 = max_t1.max(t1);
min_t2 = min_t2.min(t2);
}
if min_t2 < max_t1 || max_t1 > 1.0 || max_t1 <= 0.0 {
return None;
}
Some(CastHit { time: max_t1 })
if normal.dot(vector) > 0.0 {
normal = -normal;
}
Some(CastHit {
time: max_t1,
normal,
})
}
}

#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub struct CastHit {
pub time: f32,
pub normal: Vec2,
}

pub fn ray_cast(origin: Point, vector: Vec2, target: &impl Shape) -> Option<CastHit> {
Expand Down
10 changes: 10 additions & 0 deletions src/v3/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ impl Vec2 {
Self::new(value, value)
}

#[must_use]
pub fn x(self) -> f32 {
self.x
}

#[must_use]
pub fn y(self) -> f32 {
self.y
}

#[must_use]
pub(super) fn dot(self, other: Self) -> f32 {
(self.x * other.x) + (self.y * other.y)
Expand Down
22 changes: 20 additions & 2 deletions tests/v3_ray_cast_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rstest::rstest;
Vec2::ZERO,
Vec2::X,
Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Point::new(1.9, 0.0)),
Vec2::new(0.9, 0.0)
Vec2::new(0.9, 0.0),
)]
#[case(
Vec2::ZERO,
Expand Down Expand Up @@ -59,7 +59,7 @@ use rstest::rstest;
Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Point::new(0.5, 1.9)),
Vec2::new(0.9, 0.9),
)]
fn should_find_contact_point(
fn should_find_contact_time(
#[case] origin: impl Into<Point>,
#[case] vector: Vec2,
#[case] target: impl Shape,
Expand All @@ -73,6 +73,24 @@ fn should_find_contact_point(
assert_abs_diff_eq!(point.y(), expected_point.y());
}

#[rstest]
#[case(Point::ORIGIN, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Point::new(1.9, 0.0)), -Vec2::X)]
#[case(Point::ORIGIN, -Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Point::new(-1.9, 0.0)), Vec2::X)]
#[case(Point::ORIGIN, Vec2::Y, Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Point::new(0.0, 1.9)), -Vec2::Y)]
#[case(Point::ORIGIN, -Vec2::Y, Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Point::new(0.0, -1.9)), Vec2::Y)]
#[case(Point::ORIGIN, Vec2::new(1.0, 1.0), Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Point::new(1.9, 0.0)), -Vec2::X)]
fn should_find_contact_normal(
#[case] origin: impl Into<Point>,
#[case] vector: Vec2,
#[case] target: impl Shape,
#[case] expected_normal: Vec2,
) {
let origin = origin.into();
let normal = ray_cast(origin, vector, &target).unwrap().normal;
assert_abs_diff_eq!(normal.x(), expected_normal.x());
assert_abs_diff_eq!(normal.y(), expected_normal.y());
}

#[rstest]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Point::new(2.1, 0.0)))]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Point::new(-2.1, 0.0)))]
Expand Down

0 comments on commit b828de0

Please sign in to comment.