Struct NonlinearRigidMotion

Source
pub struct NonlinearRigidMotion {
    pub start: Isometry<f32>,
    pub local_center: Point<f32>,
    pub linvel: Vector<f32>,
    pub angvel: Vector<f32>,
}
Expand description

Describes the complete motion of a rigid body with both translation and rotation.

This type represents the 6 degrees of freedom motion of a rigid body:

  • 3 translational (linear velocity in x, y, z)
  • 3 rotational (angular velocity around x, y, z axes)

The motion is assumed to have constant velocities over the time interval, meaning:

  • Linear velocity doesn’t change (no acceleration)
  • Angular velocity doesn’t change (no angular acceleration)

This is used with cast_shapes_nonlinear to perform continuous collision detection for rotating objects.

§Physics Model

At any time t, the object’s position is computed as:

  1. Rotate around local_center by angvel * t
  2. Translate by linvel * t
  3. Apply to the starting position start

This creates a helical trajectory (螺旋軌跡) when both velocities are non-zero:

  • Pure translation: straight line
  • Pure rotation: circular arc
  • Both: helix/spiral path

§Fields

  • start - The initial position and orientation at time t = 0
  • local_center - The point (in the shape’s local coordinate system) around which rotation occurs. For most cases, use the center of mass or Point::origin().
  • linvel - Linear velocity vector (units per second). Direction is the direction of motion, magnitude is speed.
  • angvel - Angular velocity:
    • 2D: Scalar rotation rate in radians/second (positive = counter-clockwise)
    • 3D: Axis-angle vector (direction = rotation axis, magnitude = rotation rate in radians/second)

§Example: Simple Translation

use parry3d::query::NonlinearRigidMotion;
use nalgebra::{Isometry3, Point3, Vector3};

// Object moving right at 5 units/second, no rotation
let motion = NonlinearRigidMotion::new(
    Isometry3::translation(0.0, 0.0, 0.0), // start at origin
    Point3::origin(),                      // rotation center (irrelevant here)
    Vector3::new(5.0, 0.0, 0.0),          // moving right
    Vector3::zeros(),                      // not rotating
);

// At t=2.0 seconds, object has moved 10 units right
let pos_at_2 = motion.position_at_time(2.0);
assert_eq!(pos_at_2.translation.vector.x, 10.0);

§Example: Pure Rotation (3D)

use parry3d::query::NonlinearRigidMotion;
use nalgebra::{Isometry3, Point3, Vector3};
use std::f32::consts::PI;

// Object spinning around Y axis, no translation
let motion = NonlinearRigidMotion::new(
    Isometry3::translation(0.0, 0.0, 0.0),
    Point3::origin(),                // rotate around origin
    Vector3::zeros(),                // not translating
    Vector3::new(0.0, PI, 0.0),      // rotating around Y at π rad/s (180°/s)
);

// At t=1.0 second, object has rotated 180 degrees
let pos_at_1 = motion.position_at_time(1.0);
// Object is now rotated 180° around Y axis

§Example: Combined Translation and Rotation (Helical Path)

use parry3d::query::NonlinearRigidMotion;
use nalgebra::{Isometry3, Point3, Vector3};

// Spinning projectile moving forward
let motion = NonlinearRigidMotion::new(
    Isometry3::translation(0.0, 0.0, 0.0),
    Point3::origin(),
    Vector3::new(10.0, 0.0, 0.0),     // moving forward at 10 units/s
    Vector3::new(20.0, 0.0, 0.0),     // spinning around its movement axis
);

// The object traces a helical path (like a bullet with rifling)
let pos_at_half = motion.position_at_time(0.5);
// Moved 5 units forward AND rotated 10 radians

§Example: Rotation Around Off-Center Point

use parry3d::query::NonlinearRigidMotion;
use nalgebra::{Isometry3, Point3, Vector3};

// Object rotating around a point that's NOT its center
// Useful for: swinging weapons, rotating around pivot point, etc.
let motion = NonlinearRigidMotion::new(
    Isometry3::translation(5.0, 0.0, 0.0), // object is at x=5
    Point3::new(-5.0, 0.0, 0.0),           // rotate around x=0 (in local space)
    Vector3::zeros(),
    Vector3::new(0.0, 1.0, 0.0),           // rotate around Y axis at 1 rad/s
);

// The object orbits in a circle around the world origin
// Like a hammer being swung around

§Common Use Cases

  1. Spinning Projectiles: Bullets, thrown objects with spin
let bullet = NonlinearRigidMotion::new(
    Isometry3::translation(0.0, 1.5, 0.0),
    Point3::origin(),
    Vector3::new(100.0, -2.0, 0.0),  // fast forward, slight drop
    Vector3::new(50.0, 0.0, 0.0),    // high spin rate
);
  1. Tumbling Debris: Objects affected by explosion or impact
let debris = NonlinearRigidMotion::new(
    Isometry3::translation(0.0, 2.0, 0.0),
    Point3::origin(),
    Vector3::new(3.0, 5.0, -2.0),    // chaotic velocity
    Vector3::new(2.0, -3.0, 1.5),    // chaotic rotation
);
  1. Rotating Machinery: Blades, gears, rotating parts
let blade = NonlinearRigidMotion::new(
    Isometry3::translation(0.0, 1.0, 0.0),
    Point3::origin(),           // spin around center
    Vector3::zeros(),           // blade doesn't translate
    Vector3::new(0.0, 10.0, 0.0), // fast rotation
);
  1. Stationary Objects: Use constant_position() for non-moving obstacles
let wall = NonlinearRigidMotion::constant_position(
    Isometry3::translation(10.0, 0.0, 0.0)
);

§2D vs 3D Angular Velocity

The representation of angvel differs between 2D and 3D:

2D (scalar):

  • Positive value: counter-clockwise rotation
  • Negative value: clockwise rotation
  • Magnitude: rotation rate in radians/second
use parry2d::query::NonlinearRigidMotion;
use nalgebra::{Isometry2, Point2, Vector2};

let motion = NonlinearRigidMotion::new(
    Isometry2::translation(0.0, 0.0),
    Point2::origin(),
    Vector2::zeros(),
    3.14,  // rotating counter-clockwise at π rad/s
);

3D (axis-angle vector):

  • Direction: axis of rotation (right-hand rule)
  • Magnitude: rotation rate in radians/second
  • Zero vector: no rotation
use parry3d::query::NonlinearRigidMotion;
use nalgebra::{Isometry3, Point3, Vector3};

let motion = NonlinearRigidMotion::new(
    Isometry3::translation(0.0, 0.0, 0.0),
    Point3::origin(),
    Vector3::zeros(),
    Vector3::new(0.0, 3.14, 0.0),  // rotate around Y axis at π rad/s
);

§Important Notes

  1. Local vs World Space: The local_center must be in the shape’s local coordinate system, not world space. For a shape centered at origin, use Point::origin().

  2. Angular Velocity Units: Always use radians per second, not degrees!

    • To convert: degrees * (PI / 180.0) = radians
    • Example: 90°/s = 90.0 * (PI / 180.0) ≈ 1.571 rad/s
  3. Constant Velocities: This assumes velocities don’t change over time. For physics simulations with acceleration/forces, you typically:

    • Compute motion for a single small timestep (e.g., 1/60 second)
    • Update velocities after each step
    • Create new NonlinearRigidMotion for next timestep
  4. Center of Mass: For realistic physics, local_center should be the shape’s center of mass. For simple cases, Point::origin() often works.

§See Also

Fields§

§start: Isometry<f32>

The starting isometry at t = 0.

§local_center: Point<f32>

The local-space point at which the rotational part of this motion is applied.

§linvel: Vector<f32>

The translational velocity of this motion.

§angvel: Vector<f32>

The angular velocity of this motion.

Implementations§

Source§

impl NonlinearRigidMotion

Source

pub fn new( start: Isometry<f32>, local_center: Point<f32>, linvel: Vector<f32>, angvel: Vector<f32>, ) -> Self

Creates a new rigid motion from a starting position and velocities.

§Arguments
  • start - Initial position and orientation at time t = 0
  • local_center - Point (in local coordinates) around which rotation occurs
  • linvel - Linear velocity vector (units per second)
  • angvel - Angular velocity as axis-angle vector (radians per second)
§Example
use parry3d::query::NonlinearRigidMotion;
use nalgebra::{Isometry3, Point3, Vector3};

// Object moving forward and spinning around its movement axis
let motion = NonlinearRigidMotion::new(
    Isometry3::translation(0.0, 0.0, 0.0),
    Point3::origin(),
    Vector3::new(10.0, 0.0, 0.0),    // moving forward
    Vector3::new(5.0, 0.0, 0.0),     // spinning around X axis
);
Source

pub fn identity() -> Self

Creates a stationary motion at the origin (identity transformation).

Equivalent to constant_position(Isometry::identity()).

§Example
use parry3d::query::NonlinearRigidMotion;

let stationary = NonlinearRigidMotion::identity();
// Object stays at origin with no rotation, forever
Source

pub fn constant_position(pos: Isometry<f32>) -> Self

Creates a motion that stays at a constant position (no translation, no rotation).

Useful for representing static/stationary objects in collision queries. Both linear and angular velocities are set to zero.

§Arguments
  • pos - The fixed position and orientation
§Example
use parry3d::query::NonlinearRigidMotion;
use nalgebra::Isometry3;

// A wall that never moves
let wall_motion = NonlinearRigidMotion::constant_position(
    Isometry3::translation(10.0, 0.0, 0.0)
);

// At any time t, position is always (10, 0, 0)
let pos_at_5 = wall_motion.position_at_time(5.0);
assert_eq!(pos_at_5.translation.vector.x, 10.0);
Source

pub fn freeze(&mut self, t: f32)

Freezes this motion at a specific time, making it stationary from that point forward.

After calling this method:

  • self.start is updated to the position at time t
  • Both velocities are set to zero
  • All future calls to position_at_time() return the same frozen position

This is useful for “stopping” an object mid-motion, or capturing a specific moment in a motion trajectory.

§Arguments
  • t - The time at which to freeze the motion
§Example
use parry3d::query::NonlinearRigidMotion;
use nalgebra::{Isometry3, Point3, Vector3};

let mut motion = NonlinearRigidMotion::new(
    Isometry3::translation(0.0, 0.0, 0.0),
    Point3::origin(),
    Vector3::new(5.0, 0.0, 0.0),  // moving right
    Vector3::zeros(),
);

// Freeze at t=2.0 (when object is at x=10)
motion.freeze(2.0);

// Now position is constant at x=10, regardless of time
let pos_at_100 = motion.position_at_time(100.0);
assert_eq!(pos_at_100.translation.vector.x, 10.0);
Source

pub fn append_translation(&self, tra: Vector<f32>) -> Self

Appends a constant translation to this rigid-motion.

Source

pub fn prepend_translation(&self, tra: Vector<f32>) -> Self

Prepends a constant translation to this rigid-motion.

Source

pub fn append(&self, iso: Isometry<f32>) -> Self

Appends a constant isometry to this rigid-motion.

Source

pub fn prepend(&self, iso: Isometry<f32>) -> Self

Prepends a constant translation to this rigid-motion.

Source

pub fn position_at_time(&self, t: f32) -> Isometry<f32>

Computes the position and orientation at a given time.

Returns the full isometry (position + orientation) of the rigid body at time t, accounting for both translation and rotation from the starting position.

The computation follows this sequence:

  1. Rotate around local_center by angle angvel * t
  2. Translate by displacement linvel * t
  3. Apply to the starting position start
§Arguments
  • t - Time value (typically in seconds, matching your velocity units)
§Returns

The complete transformation (position and orientation) at time t.

§Example: Tracking a Moving Object
use parry3d::query::NonlinearRigidMotion;
use nalgebra::{Isometry3, Point3, Vector3};

let motion = NonlinearRigidMotion::new(
    Isometry3::translation(0.0, 0.0, 0.0),
    Point3::origin(),
    Vector3::new(3.0, 0.0, 0.0),     // 3 units/sec to the right
    Vector3::new(0.0, 1.0, 0.0),     // 1 radian/sec around Y axis
);

// Position at t=0
let pos_0 = motion.position_at_time(0.0);
assert_eq!(pos_0.translation.vector.x, 0.0);

// Position at t=2.0 seconds
let pos_2 = motion.position_at_time(2.0);
// Object has moved 6 units to the right
assert!((pos_2.translation.vector.x - 6.0).abs() < 0.01);
// And rotated 2 radians around Y
§Example: Animation Frame
use parry3d::query::NonlinearRigidMotion;
use nalgebra::{Isometry3, Point3, Vector3};

let motion = NonlinearRigidMotion::new(
    Isometry3::translation(0.0, 5.0, 0.0),
    Point3::origin(),
    Vector3::new(0.0, -9.8, 0.0),    // falling (gravity)
    Vector3::new(1.0, 2.0, 0.5),     // tumbling
);

// Render at 60 FPS
let dt = 1.0 / 60.0;
for frame in 0..60 {
    let t = frame as f32 * dt;
    let pos = motion.position_at_time(t);
    // Use `pos` to render object at this frame
}

Trait Implementations§

Source§

impl Clone for NonlinearRigidMotion

Source§

fn clone(&self) -> NonlinearRigidMotion

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for NonlinearRigidMotion

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Copy for NonlinearRigidMotion

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_sync(self: Box<T>) -> Box<dyn Any + Sync + Send>

Converts Box<Trait> (where Trait: DowncastSync) to Box<dyn Any + Send + Sync>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Converts Arc<Trait> (where Trait: DowncastSync) to Arc<Any>, which can then be downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.