Add the `RotationTo` trait to compute the delta rotation between two elements.

Use `::angle_between` or `.angle_to`  to compute the rotation angle between two vectors/rotation
matrices/unit quaternions.
Use `::rotation_between` or `.rotation_to` to compute the rotation matrix/unit quaternion to
transform a vector/rotation matrix/uniq quaternion to another.

Fix #130.
This commit is contained in:
Sébastien Crozet 2015-05-31 22:52:18 +02:00
parent 11bbf0ff11
commit ea86890647
7 changed files with 132 additions and 10 deletions

View File

@ -133,7 +133,7 @@ pub use traits::{
POrdering,
PntAsVec,
Repeat,
Rotate, Rotation, RotationMatrix, RotationWithTranslation,
Rotate, Rotation, RotationMatrix, RotationWithTranslation, RotationTo,
Row,
Shape,
SquareMat,
@ -569,6 +569,21 @@ pub fn append_rotation_wrt_center<LV: Neg<Output = LV> + Copy,
RotationWithTranslation::append_rotation_wrt_center(m, amount)
}
/*
* RotationTo
*/
/// Computes the angle of the rotation needed to transfom `a` to `b`.
#[inline(always)]
pub fn angle_between<V: RotationTo>(a: &V, b: &V) -> V::AngleType {
a.angle_to(b)
}
/// Computes the rotation needed to transform `a` to `b`.
#[inline(always)]
pub fn rotation_between<V: RotationTo>(a: &V, b: &V) -> V::DeltaRotationType {
a.rotation_to(b)
}
/*
* RotationMatrix<LV, AV, R>
*/

View File

@ -12,7 +12,7 @@ use structs::{Vec3, Pnt3, Rot3, Mat3};
use traits::operations::{ApproxEq, Inv, POrd, POrdering, Axpy};
use traits::structure::{Cast, Indexable, Iterable, IterableMut, Dim, Shape, BaseFloat, BaseNum,
Bounded, Repeat};
use traits::geometry::{Norm, Rotation, Rotate, Transform};
use traits::geometry::{Norm, Rotation, Rotate, RotationTo, Transform};
#[cfg(feature="arbitrary")]
use quickcheck::{Arbitrary, Gen};
@ -456,6 +456,24 @@ impl<N: BaseNum + Neg<Output = N>> Rotate<Pnt3<N>> for UnitQuat<N> {
}
}
impl<N: BaseFloat + ApproxEq<N>> RotationTo for UnitQuat<N> {
type AngleType = N;
type DeltaRotationType = UnitQuat<N>;
#[inline]
fn angle_to(&self, other: &Self) -> N {
let delta = self.rotation_to(other);
let _2 = ::one::<N>() + ::one();
_2 * delta.q.vector().norm().atan2(delta.q.w)
}
#[inline]
fn rotation_to(&self, other: &Self) -> UnitQuat<N> {
*other / *self
}
}
impl<N: BaseNum + Neg<Output = N>> Transform<Vec3<N>> for UnitQuat<N> {
#[inline]
fn transform(&self, v: &Vec3<N>) -> Vec3<N> {

View File

@ -5,8 +5,8 @@
use std::ops::{Mul, Neg, Index};
use rand::{Rand, Rng};
use num::{Zero, One};
use traits::geometry::{Rotate, Rotation, AbsoluteRotate, RotationMatrix, Transform, ToHomogeneous,
Norm, Cross};
use traits::geometry::{Rotate, Rotation, AbsoluteRotate, RotationMatrix, RotationTo, Transform,
ToHomogeneous, Norm, Cross};
use traits::structure::{Cast, Dim, Row, Col, BaseFloat, BaseNum, Eye, Diag};
use traits::operations::{Absolute, Inv, Transpose, ApproxEq};
use structs::vec::{Vec1, Vec2, Vec3, Vec4};
@ -71,6 +71,21 @@ impl<N: BaseFloat + Clone> Rotation<Vec1<N>> for Rot2<N> {
}
}
impl<N: BaseFloat> RotationTo for Rot2<N> {
type AngleType = N;
type DeltaRotationType = Rot2<N>;
#[inline]
fn angle_to(&self, other: &Self) -> N {
self.rotation_to(other).rotation().norm()
}
#[inline]
fn rotation_to(&self, other: &Self) -> Rot2<N> {
*other * ::inv(self).unwrap()
}
}
impl<N: Rand + BaseFloat> Rand for Rot2<N> {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> Rot2<N> {
@ -283,6 +298,22 @@ Rotation<Vec3<N>> for Rot3<N> {
}
}
impl<N: BaseFloat> RotationTo for Rot3<N> {
type AngleType = N;
type DeltaRotationType = Rot3<N>;
#[inline]
fn angle_to(&self, other: &Self) -> N {
// FIXME: refactor to avoid the normalization of the rotation axisangle vector.
self.rotation_to(other).rotation().norm()
}
#[inline]
fn rotation_to(&self, other: &Self) -> Rot3<N> {
*other * ::inv(self).unwrap()
}
}
impl<N: Clone + Rand + BaseFloat> Rand for Rot3<N> {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> Rot3<N> {

View File

@ -1,9 +1,50 @@
use std::ops::{Sub, Mul, Neg};
use num::{Zero, One};
use traits::structure::{Cast, Row, Basis, BaseFloat};
use traits::geometry::{Norm, Cross, CrossMatrix, UniformSphereSample};
use traits::geometry::{Norm, Cross, CrossMatrix, RotationTo, UniformSphereSample};
use structs::vec::{Vec1, Vec2, Vec3, Vec4};
use structs::mat::Mat3;
use structs::rot::{Rot2, Rot3};
impl<N: BaseFloat> RotationTo for Vec2<N> {
type AngleType = N;
type DeltaRotationType = Rot2<N>;
#[inline]
fn angle_to(&self, other: &Self) -> N {
::cross(self, other).x.atan2(::dot(self, other))
}
#[inline]
fn rotation_to(&self, other: &Self) -> Rot2<N> {
Rot2::new(Vec1::new(self.angle_to(other)))
}
}
impl<N: BaseFloat> RotationTo for Vec3<N> {
type AngleType = N;
type DeltaRotationType = Rot3<N>;
#[inline]
fn angle_to(&self, other: &Self) -> N {
::cross(self, other).norm().atan2(::dot(self, other))
}
#[inline]
fn rotation_to(&self, other: &Self) -> Rot3<N> {
let mut axis = ::cross(self, other);
let norm = axis.normalize_mut();
if ::is_zero(&norm) {
::one()
}
else {
let axis_angle = axis * norm.atan2(::dot(self, other));
Rot3::new(axis_angle)
}
}
}
impl<N: Copy + Mul<N, Output = N> + Sub<N, Output = N>> Cross for Vec2<N> {
type CrossProductType = Vec1<N>;

View File

@ -79,7 +79,7 @@ macro_rules! at_fast_impl(
// However, f32/f64 does not implement Ord…
macro_rules! ord_impl(
($t: ident, $comp0: ident, $($compN: ident),*) => (
impl<N: BaseFloat + Copy> POrd for $t<N> {
impl<N: BaseFloat> POrd for $t<N> {
#[inline]
fn inf(&self, other: &$t<N>) -> $t<N> {
$t::new(self.$comp0.min(other.$comp0)
@ -291,7 +291,7 @@ macro_rules! container_impl(
macro_rules! basis_impl(
($t: ident, $dim: expr) => (
impl<N: Copy + BaseFloat + ApproxEq<N>> Basis for $t<N> {
impl<N: BaseFloat + ApproxEq<N>> Basis for $t<N> {
#[inline]
fn canonical_basis<F: FnMut($t<N>) -> bool>(mut f: F) {
for i in 0..$dim {
@ -547,7 +547,7 @@ macro_rules! translation_impl(
macro_rules! norm_impl(
($t: ident, $($compN: ident),+) => (
impl<N: Copy + BaseFloat> Norm<N> for $t<N> {
impl<N: BaseFloat> Norm<N> for $t<N> {
#[inline]
fn sqnorm(&self) -> N {
Dot::dot(self, self)

View File

@ -64,6 +64,22 @@ pub trait Rotation<V> {
fn set_rotation(&mut self, V);
}
/// Trait of object that can be rotated to be superimposed with another one of the same nature.
pub trait RotationTo {
/// Type of the angle between two elements.
type AngleType;
/// Type of the rotation between two elements.
type DeltaRotationType;
/// Computes an angle nedded to transform the first element to the second one using a
/// rotation.
fn angle_to(&self, other: &Self) -> Self::AngleType;
/// Computes the smallest rotation needed to transform the first element to the second one.
fn rotation_to(&self, other: &Self) -> Self::DeltaRotationType;
}
/// Trait of objects able to rotate other objects.
///
/// This is typically implemented by matrices which rotate vectors.

View File

@ -1,8 +1,9 @@
//! Mathematical traits.
pub use traits::geometry::{AbsoluteRotate, Cross, CrossMatrix, Dot, FromHomogeneous, Norm, Orig,
Rotate, Rotation, RotationMatrix, RotationWithTranslation, ToHomogeneous,
Transform, Transformation, Translate, Translation, UniformSphereSample};
Rotate, Rotation, RotationMatrix, RotationWithTranslation, RotationTo,
ToHomogeneous, Transform, Transformation, Translate, Translation,
UniformSphereSample};
pub use traits::structure::{FloatVec, FloatPnt, Basis, Cast, Col, Dim, Indexable, Iterable,
IterableMut, Mat, SquareMat, Row, NumVec, NumPnt, PntAsVec, ColSlice,