Skip to content

Commit

Permalink
make module v3 public (behind feature flag)
Browse files Browse the repository at this point in the history
  • Loading branch information
jcornaz committed Aug 11, 2023
1 parent 71ac667 commit ab3d0d0
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 48 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [Unreleased]

### Added

* `unstable-v3` feature flag and related `v3` module: an exploration of how could look like the next major version


## [2.0.0] - 2023-08-03

Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ all-features = true
[features]
default = ["std"]
std = ["glam/std", "bvh-arena?/std"]
unstable-v3 = []

[dependencies]
# Public
bvh-arena = { version = "1.1.3", default-features = false, optional = true }

# Private
glam = { version = "0.24.1", default-features = false, features = ["libm"] }
sealed = "0.5.0"
smallvec = { version = "1.11.0", default-features = false }

[dev-dependencies]
Expand Down
11 changes: 9 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,16 @@
//! * `std` (enabled by default) Allow to use rust the standard library (need to be disabled for `no_std` apps)
//! * `bvh-arena` Integration with [bvh-arena](https://crates.io/crates/bvh-arena) bounding volumes
//!
//!
//! ## Unstable feature flags
//!
//! The following features may receive breaking changes or be removed in a patch release.
//!
//! * `unstable-v3` `v3` module, an exploration of what could be the next major version of the API
//!

mod v2;
#[cfg(test)]
mod v3;
#[cfg(feature = "unstable-v3")]
pub mod v3;

pub use v2::*;
22 changes: 16 additions & 6 deletions src/v3/math.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};

#[derive(Debug, Copy, Clone, Default, PartialEq)]
pub(crate) struct Vec2 {
pub struct Vec2 {
pub(super) x: f32,
pub(super) y: f32,
}
Expand All @@ -11,31 +11,41 @@ impl Vec2 {
pub const X: Self = Self::new(1.0, 0.0);
pub const Y: Self = Self::new(0.0, 1.0);

#[must_use]
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}

pub fn dot(self, other: Self) -> f32 {
#[must_use]
pub(super) fn dot(self, other: Self) -> f32 {
(self.x * other.x) + (self.y * other.y)
}

pub fn magnitude_squared(self) -> f32 {
#[must_use]
#[cfg(test)]
pub(super) fn magnitude_squared(self) -> f32 {
self.x * self.x + self.y * self.y
}

pub fn magnitude(self) -> f32 {
#[must_use]
#[cfg(test)]
pub(super) fn magnitude(self) -> f32 {
self.magnitude_squared().sqrt()
}

pub fn normalize(self) -> Option<Self> {
#[must_use]
#[cfg(test)]
pub(super) fn normalize(self) -> Option<Self> {
let normal = self / self.magnitude();
if !normal.x.is_finite() {
return None;
}
Some(normal)
}

pub fn perp(self) -> Self {
#[must_use]
#[cfg(test)]
pub(super) fn perp(self) -> Self {
Self {
x: -self.y,
y: self.x,
Expand Down
53 changes: 29 additions & 24 deletions src/v3/mod.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
#![allow(missing_docs)]

mod math;
mod range;
mod shapes;

use math::Vec2;
pub use math::Vec2;
use range::Range;
use shapes::Point;
use sealed::sealed;
pub use shapes::{Aabb, Point};

trait SatShape {
#[sealed]
pub trait Shape {
type AxisIter: Iterator<Item = Vec2>;

fn axes(&self) -> Self::AxisIter;
fn project_on(&self, axis: Vec2) -> Range;
}

#[derive(Debug, Clone, PartialEq)]
struct Contact {
point: Point,
#[non_exhaustive]
pub struct Contact {
pub point: Point,
}

/// Given ranges of projected shapes,
Expand Down Expand Up @@ -47,7 +52,7 @@ fn cast_projection(mut source: Range, mut vector: f32, mut target: Range) -> Opt
})
}

fn cast_ray(origin: Point, vector: Vec2, target: &impl SatShape) -> Option<Contact> {
pub fn cast_ray(origin: Point, vector: Vec2, target: &impl Shape) -> Option<Contact> {
let mut max_t1 = f32::MIN;
let mut min_t2 = f32::MAX;
for axis in target.axes() {
Expand Down Expand Up @@ -78,79 +83,79 @@ mod tests {
#[case(
Vec2::ZERO,
Vec2::X,
Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(1.9, 0.0)),
Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(1.9, 0.0)),
Vec2::new(0.9, 0.0)
)]
#[case(
Vec2::ZERO,
-Vec2::X,
Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(-1.9, 0.0)),
Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(-1.9, 0.0)),
Vec2::new(-0.9, 0.0)
)]
#[case(
Vec2::X,
Vec2::X,
Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(2.9, 0.0)),
Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(2.9, 0.0)),
Vec2::new(1.9, 0.0)
)]
#[case(
Vec2::ZERO,
Vec2::X * 2.0,
Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(2.9, 0.0)),
Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(2.9, 0.0)),
Vec2::new(1.9, 0.0)
)]
#[case(
Vec2::ZERO,
Vec2::Y,
Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(0.0, 1.9)),
Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(0.0, 1.9)),
Vec2::new(0.0, 0.9)
)]
#[case(
Vec2::Y,
Vec2::Y,
Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(0.0, 2.9)),
Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(0.0, 2.9)),
Vec2::new(0.0, 1.9)
)]
#[case(
Vec2::ZERO,
Vec2::Y * 2.0,
Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(0.0, 2.9)),
Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(0.0, 2.9)),
Vec2::new(0.0, 1.9)
)]
#[case(
Vec2::ZERO,
Vec2::new(1.0, 1.0),
Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(1.9, 1.9)),
Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(1.9, 1.9)),
Vec2::new(0.9, 0.9),
)]
#[case(
Vec2::ZERO,
Vec2::new(1.0, 1.0),
Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(0.5, 1.9)),
Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(0.5, 1.9)),
Vec2::new(0.9, 0.9),
)]
fn ray_cast_should_find_contact_point(
#[case] origin: impl Into<Point>,
#[case] vector: Vec2,
#[case] target: impl SatShape,
#[case] target: impl Shape,
#[case] expected_point: impl Into<Point>,
) {
let point = cast_ray(origin.into(), vector, &target).unwrap().point;
assert_abs_diff_eq!(point, expected_point.into());
}

#[rstest]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(2.1, 0.0)))]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(-2.1, 0.0)))]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::ZERO))]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(1.0, 1.0)).with_position(Vec2::ZERO))]
#[case(-Vec2::X, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(1.1, 0.0)))]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(1.9, 5.0)))]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_position(Vec2::new(1.9, -5.0)))]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(2.1, 0.0)))]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(-2.1, 0.0)))]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::ZERO))]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(1.0, 1.0)).with_center_at(Vec2::ZERO))]
#[case(-Vec2::X, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(1.1, 0.0)))]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(1.9, 5.0)))]
#[case(Vec2::ZERO, Vec2::X, Aabb::from_size(Vec2::new(2.0, 2.0)).with_center_at(Vec2::new(1.9, -5.0)))]
fn ray_cast_should_return_none_when_there_is_no_hit(
#[case] origin: impl Into<Point>,
#[case] vector: Vec2,
#[case] target: impl SatShape,
#[case] target: impl Shape,
) {
let result = cast_ray(origin.into(), vector, &target);
assert_eq!(result, None);
Expand Down
3 changes: 2 additions & 1 deletion src/v3/range.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#[derive(Debug, Copy, Clone, PartialEq)]
pub(super) struct Range {
pub struct Range {
pub(super) min: f32,
pub(super) max: f32,
}
Expand All @@ -14,6 +14,7 @@ impl Range {
self.min <= other.max && self.max >= other.min
}

#[cfg(test)]
pub(super) fn contains(self, point: f32) -> bool {
point >= self.min && point <= self.max
}
Expand Down
38 changes: 23 additions & 15 deletions src/v3/shapes.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
mod point {
use core::ops::Add;

use crate::v3::{math::Vec2, Range, SatShape};
use sealed::sealed;

use crate::v3::{math::Vec2, Range, Shape, __seal_shape};

#[derive(Debug, Copy, Clone, PartialEq)]
pub(crate) struct Point(Vec2);
pub struct Point(Vec2);

impl From<Vec2> for Point {
fn from(value: Vec2) -> Self {
Expand All @@ -18,7 +20,8 @@ mod point {
}
}

impl SatShape for Point {
#[sealed]
impl Shape for Point {
type AxisIter = core::iter::Empty<Vec2>;
fn axes(&self) -> Self::AxisIter {
core::iter::empty()
Expand Down Expand Up @@ -82,28 +85,33 @@ mod point {
}

mod aabb {
use crate::v3::{math::Vec2, Range, SatShape};
use sealed::sealed;

use crate::v3::{math::Vec2, Range, Shape, __seal_shape};

pub(crate) struct Aabb {
pub struct Aabb {
center: Vec2,
half_size: Vec2,
}

impl Aabb {
pub(crate) fn from_size(size: Vec2) -> Self {
#[must_use]
pub fn from_size(size: Vec2) -> Self {
Self {
center: Vec2::default(),
half_size: size / 2.0,
}
}

pub(crate) fn with_position(mut self, center: Vec2) -> Self {
#[must_use]
pub fn with_center_at(mut self, center: Vec2) -> Self {
self.center = center;
self
}
}

impl SatShape for Aabb {
#[sealed]
impl Shape for Aabb {
type AxisIter = core::array::IntoIter<Vec2, 2>;

fn axes(&self) -> Self::AxisIter {
Expand Down Expand Up @@ -138,10 +146,10 @@ mod aabb {
#[case(Aabb::from_size(Vec2::new(3.0, 4.0)), Vec2::new(1.5, 2.0), -6.25, 6.25)]
#[case(Aabb::from_size(Vec2::new(3.0, 4.0)), Vec2::new(1.5, -2.0), -6.25, 6.25)]
#[case(Aabb::from_size(Vec2::new(3.0, 4.0)), Vec2::new(-1.5, 2.0), -6.25, 6.25)]
#[case(Aabb::from_size(Vec2::new(3.0, 4.0)).with_position(Vec2::new(0.0, 0.0)), Vec2::new(1.0, 0.0), -1.5, 1.5)]
#[case(Aabb::from_size(Vec2::new(3.0, 4.0)).with_position(Vec2::new(1.0, 0.0)), Vec2::new(1.0, 0.0), -0.5, 2.5)]
#[case(Aabb::from_size(Vec2::new(3.0, 4.0)).with_position(Vec2::new(0.0, 1.0)), Vec2::new(1.0, 0.0), -1.5, 1.5)]
#[case(Aabb::from_size(Vec2::new(3.0, 4.0)).with_position(Vec2::new(0.0, 1.0)), Vec2::new(0.0, 1.0), -1.0, 3.0)]
#[case(Aabb::from_size(Vec2::new(3.0, 4.0)).with_center_at(Vec2::new(0.0, 0.0)), Vec2::new(1.0, 0.0), -1.5, 1.5)]
#[case(Aabb::from_size(Vec2::new(3.0, 4.0)).with_center_at(Vec2::new(1.0, 0.0)), Vec2::new(1.0, 0.0), -0.5, 2.5)]
#[case(Aabb::from_size(Vec2::new(3.0, 4.0)).with_center_at(Vec2::new(0.0, 1.0)), Vec2::new(1.0, 0.0), -1.5, 1.5)]
#[case(Aabb::from_size(Vec2::new(3.0, 4.0)).with_center_at(Vec2::new(0.0, 1.0)), Vec2::new(0.0, 1.0), -1.0, 3.0)]
fn test_axis_project(
#[case] shape: Aabb,
#[case] axis: Vec2,
Expand All @@ -157,7 +165,7 @@ mod aabb {
fn test_polygon_axes(
#[values(
Aabb::from_size(Vec2::ZERO),
Aabb::from_size(Vec2::new(2.0, 3.0)).with_position(Vec2::new(4.0, 5.0))
Aabb::from_size(Vec2::new(2.0, 3.0)).with_center_at(Vec2::new(4.0, 5.0))
)]
shape: Aabb,
) {
Expand All @@ -169,5 +177,5 @@ mod aabb {
}
}

pub(super) use aabb::Aabb;
pub(super) use point::Point;
pub use aabb::Aabb;
pub use point::Point;

0 comments on commit ab3d0d0

Please sign in to comment.