1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
use crate::math::{Isometry, Point, Real, Translation, Vector};
/// A nonlinear motion from a starting isometry traveling at constant translational and rotational velocity.
#[derive(Debug, Copy, Clone)]
pub struct NonlinearRigidMotion {
/// The starting isometry at `t = 0`.
pub start: Isometry<Real>,
/// The local-space point at which the rotational part of this motion is applied.
pub local_center: Point<Real>,
/// The translational velocity of this motion.
pub linvel: Vector<Real>,
/// The angular velocity of this motion.
#[cfg(feature = "dim2")]
pub angvel: Real,
/// The angular velocity of this motion.
#[cfg(feature = "dim3")]
pub angvel: Vector<Real>,
}
impl NonlinearRigidMotion {
/// Initialize a motion from a starting isometry and linear and angular velocities.
#[cfg(feature = "dim2")]
pub fn new(
start: Isometry<Real>,
local_center: Point<Real>,
linvel: Vector<Real>,
angvel: Real,
) -> Self {
NonlinearRigidMotion {
start,
local_center,
linvel,
angvel,
}
}
/// Initialize a motion from a starting isometry and linear and angular velocities.
#[cfg(feature = "dim3")]
pub fn new(
start: Isometry<Real>,
local_center: Point<Real>,
linvel: Vector<Real>,
angvel: Vector<Real>,
) -> Self {
NonlinearRigidMotion {
start,
local_center,
linvel,
angvel,
}
}
/// Create a `NonlinearRigidMotion` that always returns the identity matrix.
pub fn identity() -> Self {
Self::constant_position(Isometry::identity())
}
/// Create a `NonlinearRigidMotion` that always return `pos`.
pub fn constant_position(pos: Isometry<Real>) -> Self {
Self {
start: pos,
linvel: na::zero(),
angvel: na::zero(),
local_center: Point::origin(),
}
}
fn set_start(&mut self, new_start: Isometry<Real>) {
// NOTE: we need to adjust the local_center so that the angular
// velocity is still expressed wrt. the original center.
self.local_center = new_start.inverse_transform_point(&(self.start * self.local_center));
self.start = new_start;
}
/// Freezes this motion at the time `t`.
///
/// After calling this, any further calls to `self.position_at_time`
/// will always return `self.position_at_time(t)` (where `t` is the value given
/// to this method). This sets the linear velocity and angular velocity
/// of `self` to zero.
pub fn freeze(&mut self, t: Real) {
self.start = self.position_at_time(t);
self.linvel = na::zero();
self.angvel = na::zero();
}
/// Appends a constant translation to this rigid-motion.
#[must_use]
pub fn append_translation(&self, tra: Vector<Real>) -> Self {
let mut result = *self;
result.set_start(Translation::from(tra) * result.start);
result
}
/// Prepends a constant translation to this rigid-motion.
#[must_use]
pub fn prepend_translation(&self, tra: Vector<Real>) -> Self {
let mut result = *self;
result.set_start(result.start * Translation::from(tra));
result
}
/// Appends a constant isometry to this rigid-motion.
#[must_use]
pub fn append(&self, iso: Isometry<Real>) -> Self {
let mut result = *self;
result.set_start(iso * result.start);
result
}
/// Prepends a constant translation to this rigid-motion.
#[must_use]
pub fn prepend(&self, iso: Isometry<Real>) -> Self {
let mut result = *self;
result.set_start(result.start * iso);
result
}
/// Computes the position at time `t` of a rigid-body following the motion described by `self`.
pub fn position_at_time(&self, t: Real) -> Isometry<Real> {
let center = self.start * self.local_center;
let shift = Translation::from(center.coords);
(shift * Isometry::new(self.linvel * t, self.angvel * t)) * (shift.inverse() * self.start)
}
}