ncollide2d 0.33.0

2 and 3-dimensional collision detection library in Rust. Will be superseded by the parry2d crate.
Documentation
use na::RealField;

use crate::math::{Isometry, Point, Translation, Vector};

/// A continuous rigid motion.
///
/// This is a function, assumed to be continuous, that, given a parameter `t` returns a direct isometry.
/// Mathematically speaking this is a one-parameter curve on the space of direct isometries. This curve
/// should have a continuity of at least `C0`.
pub trait RigidMotion<N: RealField + Copy> {
    /// Get a position at the time `t`.
    fn position_at_time(&self, t: N) -> Isometry<N>;
}

impl<N: RealField + Copy> RigidMotion<N> for Isometry<N> {
    fn position_at_time(&self, _: N) -> Isometry<N> {
        *self
    }
}

/// Interpolation between two isometries using LERP for the translation part and SLERP for the rotation.
pub struct InterpolatedRigidMotion<N: RealField + Copy> {
    /// The transformation at `t = 0.0`.
    pub start: Isometry<N>,
    /// The transformation at `t = 1.0`.
    pub end: Isometry<N>,
}

impl<N: RealField + Copy> InterpolatedRigidMotion<N> {
    /// Initialize a lerp-slerp interpolation with the given start and end transformations.
    ///
    /// The `start` is the transformation at the time `t = 0.0` and `end` is the transformation at
    /// the time `t = 1.0`.
    pub fn new(start: Isometry<N>, end: Isometry<N>) -> Self {
        InterpolatedRigidMotion { start, end }
    }
}

impl<N: RealField + Copy> RigidMotion<N> for InterpolatedRigidMotion<N> {
    fn position_at_time(&self, t: N) -> Isometry<N> {
        self.start.lerp_slerp(&self.end, t)
    }
}

/// A linear motion from a starting isometry traveling at constant translational velocity.
pub struct ConstantLinearVelocityRigidMotion<N: RealField + Copy> {
    /// The time at which this parametrization begins. Can be negative.
    pub t0: N,
    /// The starting isometry at `t = self.t0`.
    pub start: Isometry<N>,
    /// The translational velocity of this motion.
    pub velocity: Vector<N>,
}

impl<N: RealField + Copy> ConstantLinearVelocityRigidMotion<N> {
    /// Initialize a linear motion from a starting isometry and a translational velocity.
    pub fn new(t0: N, start: Isometry<N>, velocity: Vector<N>) -> Self {
        ConstantLinearVelocityRigidMotion {
            t0,
            start,
            velocity,
        }
    }
}

impl<N: RealField + Copy> RigidMotion<N> for ConstantLinearVelocityRigidMotion<N> {
    fn position_at_time(&self, t: N) -> Isometry<N> {
        Isometry::from_parts(
            (self.start.translation.vector + self.velocity * (t - self.t0)).into(),
            self.start.rotation,
        )
    }
}

/// A linear motion from a starting isometry traveling at constant translational velocity.
#[derive(Debug)]
pub struct ConstantVelocityRigidMotion<N: RealField + Copy> {
    /// The time at which this parametrization begins. Can be negative.
    pub t0: N,
    /// The starting isometry at `t = self.t0`.
    pub start: Isometry<N>,
    /// The local-space point at which the rotational part of this motion is applied.
    pub local_center: Point<N>,
    /// The translational velocity of this motion.
    pub linvel: Vector<N>,
    /// The angular velocity of this motion.
    #[cfg(feature = "dim2")]
    pub angvel: N,
    /// The angular velocity of this motion.
    #[cfg(feature = "dim3")]
    pub angvel: Vector<N>,
}

impl<N: RealField + Copy> ConstantVelocityRigidMotion<N> {
    /// Initialize a motion from a starting isometry and linear and angular velocities.
    #[cfg(feature = "dim2")]
    pub fn new(
        t0: N,
        start: Isometry<N>,
        local_center: Point<N>,
        linvel: Vector<N>,
        angvel: N,
    ) -> Self {
        ConstantVelocityRigidMotion {
            t0,
            start,
            local_center,
            linvel,
            angvel,
        }
    }

    /// Initialize a motion from a starting isometry and linear and angular velocities.
    #[cfg(feature = "dim3")]
    pub fn new(
        t0: N,
        start: Isometry<N>,
        local_center: Point<N>,
        linvel: Vector<N>,
        angvel: Vector<N>,
    ) -> Self {
        ConstantVelocityRigidMotion {
            t0,
            start,
            local_center,
            linvel,
            angvel,
        }
    }
}

impl<N: RealField + Copy> RigidMotion<N> for ConstantVelocityRigidMotion<N> {
    fn position_at_time(&self, t: N) -> Isometry<N> {
        let scaled_linvel = self.linvel * (t - self.t0);
        let scaled_angvel = self.angvel * (t - self.t0);

        let center = self.start.rotation * self.local_center.coords;
        let lhs = self.start.translation * Translation::from(center);
        let rhs = Translation::from(-center) * self.start.rotation;

        lhs * Isometry::new(scaled_linvel, scaled_angvel) * rhs
    }
}

/*
 * For composition.
 */

/// Trait for composing some rigid motions.
pub trait RigidMotionComposition<N: RealField + Copy>: RigidMotion<N> {
    /// Prepend a translation to the rigid motion `self`.
    fn prepend_translation(&self, translation: Vector<N>) -> PrependTranslation<N, Self> {
        PrependTranslation {
            motion: self,
            translation,
        }
    }

    /// Prepend a transformation to the rigid motion `self`.
    fn prepend_transformation(
        &self,
        transformation: Isometry<N>,
    ) -> PrependTransformation<N, Self> {
        PrependTransformation {
            motion: self,
            transformation,
        }
    }
}

impl<N: RealField + Copy, M: ?Sized + RigidMotion<N>> RigidMotionComposition<N> for M {}

/// The result of prepending a translation to a rigid motion.
pub struct PrependTranslation<'a, N: RealField + Copy, M: ?Sized> {
    motion: &'a M,
    translation: Vector<N>,
}

impl<'a, N: RealField + Copy, M: ?Sized + RigidMotion<N>> RigidMotion<N>
    for PrependTranslation<'a, N, M>
{
    fn position_at_time(&self, t: N) -> Isometry<N> {
        let m = self.motion.position_at_time(t);
        m * Translation::from(self.translation)
    }
}

/// The result of prepending an isometric transformation to a rigid motion.
pub struct PrependTransformation<'a, N: RealField + Copy, M: ?Sized> {
    motion: &'a M,
    transformation: Isometry<N>,
}

impl<'a, N: RealField + Copy, M: ?Sized + RigidMotion<N>> RigidMotion<N>
    for PrependTransformation<'a, N, M>
{
    fn position_at_time(&self, t: N) -> Isometry<N> {
        let m = self.motion.position_at_time(t);
        m * self.transformation
    }
}