Skip to content

Commit

Permalink
reorganize code in preparation for working on version 3
Browse files Browse the repository at this point in the history
  • Loading branch information
jcornaz committed Aug 3, 2023
1 parent 88182b6 commit 34607ad
Show file tree
Hide file tree
Showing 14 changed files with 157 additions and 152 deletions.
147 changes: 3 additions & 144 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,148 +56,7 @@
//! * `bvh-arena` Integration with [bvh-arena](https://crates.io/crates/bvh-arena) bounding volumes
//!

use crate::shapes::ShapeData;
pub use crate::transform::Transform;
mod v2;
mod v3;

mod broad_phase_interop;
mod epa;
mod gjk;
mod math;
mod minkowski;
#[cfg(test)]
mod ray;
pub mod shapes;
mod transform;

/// A collision shape
///
/// This is the entry point for collision detection.
///
/// See [crate](crate) level documentation for more info and examples.
#[derive(Debug, Clone)]
pub struct CollisionShape {
transform: Transform,
data: ShapeData,
}

impl<S: Into<ShapeData>> From<S> for CollisionShape {
fn from(shape: S) -> Self {
Self {
transform: Transform::default(),
data: shape.into(),
}
}
}

impl CollisionShape {
/// Create a circle from its radius
///
/// The origin is in the center of the circle
#[inline]
#[must_use]
pub fn new_circle(radius: f32) -> Self {
shapes::Circle::new(radius).into()
}

/// Create a rectangle from its width and height
///
/// The origin is in the center of the rectangle
#[inline]
#[must_use]
pub fn new_rectangle(width: f32, height: f32) -> Self {
shapes::Rectangle::new(width, height).into()
}

/// Create a segment from two points
#[inline]
#[must_use]
pub fn new_segment(p1: impl Into<[f32; 2]>, p2: impl Into<[f32; 2]>) -> Self {
shapes::Segment::new(p1, p2).into()
}

/// Set the transform (translation, rotation and scale)
///
/// This is equivalent to [`set_transform`](Self::set_transform), but in a builder style,
/// useful to set the transform directly at creation
#[inline]
#[must_use]
pub fn with_transform(mut self, transform: impl Into<Transform>) -> Self {
self.set_transform(transform);
self
}

/// Set the transform (translation, rotation and scale)
#[inline]
pub fn set_transform(&mut self, transform: impl Into<Transform>) {
self.transform = transform.into();
}

/// Returns true if the two convex shapes geometries are overlapping
#[must_use]
pub fn is_collided_with(&self, other: &Self) -> bool {
let difference = minkowski::Difference {
shape1: self,
shape2: other,
};
let initial_axis = other.transform.position() - self.transform.position();
gjk::find_simplex_enclosing_origin(&difference, initial_axis).is_some()
}

/// Returns contact data with the other shape if they collide. Returns `None` if they don't collide.
///
/// The normal of the contact data is pointing toward this shape.
/// In other words, ff this shape is moved by `contact.normal * contact.penetration`
/// the two shapes will no longer be inter-penetrating.
#[must_use]
pub fn contact_with(&self, other: &Self) -> Option<Contact> {
let difference = minkowski::Difference {
shape1: self,
shape2: other,
};
let initial_axis = other.transform.position() - self.transform.position();
let simplex = gjk::find_simplex_enclosing_origin(&difference, initial_axis)?;
let Contact {
normal,
penetration,
} = epa::generate_contact(&difference, simplex);
Some(Contact::<f32, [f32; 2]> {
normal: normal.into(),
penetration,
})
}

/// Returns the shape data of the collider
#[must_use]
pub fn shape_data(&self) -> &ShapeData {
&self.data
}
}

/// Contact data between two shapes
///
/// See [`CollisionShape::contact_with`]
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub struct Contact<S = f32, V = [S; 2]> {
/// Contact normal
///
/// This is the direction on which the first shape should be moved to resolve inter-penetration
/// This is also on that direction that impulse should be applied to the first shape to resolve velocities
pub normal: V,
/// Penetration
///
/// This is "how much" the two shapes are inter-penetrating
pub penetration: S,
}

trait Support<V> {
/// Returns the farthest point of the shape in the given direction.
///
/// More formaly: For a direction `v` return the point `p` of the shape that maximize the dot product `p . v`
///
/// If many points are equaly far in the given direction (have the same dot product `p . v`),
/// then one of the is choosen arbitrarily.
///
/// Note the direction may not be normalized, and may have a magnitude of zero.
fn support(&self, direction: V) -> V;
}
pub use v2::*;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bvh_arena::volumes::Aabb;
use glam::Vec2;

use crate::{CollisionShape, Support};
use crate::v2::{CollisionShape, Support};

impl From<&CollisionShape> for Aabb<2> {
fn from(shape: &CollisionShape) -> Self {
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions src/epa.rs → src/v2/epa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use core::{

use smallvec::{smallvec, SmallVec};

use crate::{gjk, math::*, Contact, Support};
use super::{gjk, math::*, Contact, Support};

pub(crate) fn generate_contact<S, V>(
pub(super) fn generate_contact<S, V>(
difference: &impl Support<V>,
simplex: gjk::Simplex<V>,
) -> Contact<S, V>
Expand Down
4 changes: 2 additions & 2 deletions src/gjk.rs → src/v2/gjk.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use core::ops::{Neg, Sub};

use crate::{math::*, Support};
use super::{math::*, Support};

pub(crate) fn find_simplex_enclosing_origin<V>(
pub(super) fn find_simplex_enclosing_origin<V>(
shape: &impl Support<V>,
initial_direction: V,
) -> Option<Simplex<V>>
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion src/minkowski.rs → src/v2/minkowski.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::ops::{Neg, Sub};

use crate::Support;
use super::Support;

pub(crate) struct Difference<'a, S1, S2> {
pub(crate) shape1: &'a S1,
Expand Down
145 changes: 145 additions & 0 deletions src/v2/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
mod broad_phase_interop;
mod epa;
mod gjk;
mod math;
mod minkowski;
#[cfg(test)]
mod ray;
pub mod shapes;
mod transform;

use shapes::ShapeData;
pub use transform::Transform;

/// A collision shape
///
/// This is the entry point for collision detection.
///
/// See [crate](crate) level documentation for more info and examples.
#[derive(Debug, Clone)]
pub struct CollisionShape {
transform: Transform,
data: ShapeData,
}

impl<S: Into<ShapeData>> From<S> for CollisionShape {
fn from(shape: S) -> Self {
Self {
transform: Transform::default(),
data: shape.into(),
}
}
}

impl CollisionShape {
/// Create a circle from its radius
///
/// The origin is in the center of the circle
#[inline]
#[must_use]
pub fn new_circle(radius: f32) -> Self {
shapes::Circle::new(radius).into()
}

/// Create a rectangle from its width and height
///
/// The origin is in the center of the rectangle
#[inline]
#[must_use]
pub fn new_rectangle(width: f32, height: f32) -> Self {
shapes::Rectangle::new(width, height).into()
}

/// Create a segment from two points
#[inline]
#[must_use]
pub fn new_segment(p1: impl Into<[f32; 2]>, p2: impl Into<[f32; 2]>) -> Self {
shapes::Segment::new(p1, p2).into()
}

/// Set the transform (translation, rotation and scale)
///
/// This is equivalent to [`set_transform`](Self::set_transform), but in a builder style,
/// useful to set the transform directly at creation
#[inline]
#[must_use]
pub fn with_transform(mut self, transform: impl Into<Transform>) -> Self {
self.set_transform(transform);
self
}

/// Set the transform (translation, rotation and scale)
#[inline]
pub fn set_transform(&mut self, transform: impl Into<Transform>) {
self.transform = transform.into();
}

/// Returns true if the two convex shapes geometries are overlapping
#[must_use]
pub fn is_collided_with(&self, other: &Self) -> bool {
let difference = minkowski::Difference {
shape1: self,
shape2: other,
};
let initial_axis = other.transform.position() - self.transform.position();
gjk::find_simplex_enclosing_origin(&difference, initial_axis).is_some()
}

/// Returns contact data with the other shape if they collide. Returns `None` if they don't collide.
///
/// The normal of the contact data is pointing toward this shape.
/// In other words, ff this shape is moved by `contact.normal * contact.penetration`
/// the two shapes will no longer be inter-penetrating.
#[must_use]
pub fn contact_with(&self, other: &Self) -> Option<Contact> {
let difference = minkowski::Difference {
shape1: self,
shape2: other,
};
let initial_axis = other.transform.position() - self.transform.position();
let simplex = gjk::find_simplex_enclosing_origin(&difference, initial_axis)?;
let Contact {
normal,
penetration,
} = epa::generate_contact(&difference, simplex);
Some(Contact::<f32, [f32; 2]> {
normal: normal.into(),
penetration,
})
}

/// Returns the shape data of the collider
#[must_use]
pub fn shape_data(&self) -> &ShapeData {
&self.data
}
}

/// Contact data between two shapes
///
/// See [`CollisionShape::contact_with`]
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub struct Contact<S = f32, V = [S; 2]> {
/// Contact normal
///
/// This is the direction on which the first shape should be moved to resolve inter-penetration
/// This is also on that direction that impulse should be applied to the first shape to resolve velocities
pub normal: V,
/// Penetration
///
/// This is "how much" the two shapes are inter-penetrating
pub penetration: S,
}

trait Support<V> {
/// Returns the farthest point of the shape in the given direction.
///
/// More formaly: For a direction `v` return the point `p` of the shape that maximize the dot product `p . v`
///
/// If many points are equaly far in the given direction (have the same dot product `p . v`),
/// then one of the is choosen arbitrarily.
///
/// Note the direction may not be normalized, and may have a magnitude of zero.
fn support(&self, direction: V) -> V;
}
File renamed without changes.
2 changes: 1 addition & 1 deletion src/shapes.rs → src/v2/shapes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use glam::Vec2;

use crate::Support;
use super::Support;

/// Geometric information about a shape
#[non_exhaustive]
Expand Down
2 changes: 1 addition & 1 deletion src/transform/mod.rs → src/v2/transform/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use glam::{Affine2, Mat2, Vec2};

use crate::{CollisionShape, Support};
use super::{CollisionShape, Support};

/// Transform that can be used for a [`CollisionShape`]
#[derive(Debug, Clone)]
Expand Down
1 change: 1 addition & 0 deletions src/v3/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

0 comments on commit 34607ad

Please sign in to comment.