forked from M-Labs/nalgebra
Uniformly distributed random rotations, unit vectors
This commit is contained in:
parent
c9be27abb5
commit
352e71656d
@ -5,8 +5,11 @@ documented here.
|
|||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
## [0.16.0] - WIP
|
## [0.16.0] - WIP
|
||||||
|
## Modified
|
||||||
|
* Adjust `UnitQuaternion`s and `Rotation3`s generated from the `Standard` distribution to be uniformly distributed.
|
||||||
### Added
|
### Added
|
||||||
* Add construction of a `Point` from an array by implementing the `From` trait.
|
* Add construction of a `Point` from an array by implementing the `From` trait.
|
||||||
|
* Add support for generating uniformly distributed random unit column vectors using the `Standard` distribution.
|
||||||
|
|
||||||
## [0.15.0]
|
## [0.15.0]
|
||||||
The most notable change of this release is the support for using part of the library without the rust standard
|
The most notable change of this release is the support for using part of the library without the rust standard
|
||||||
|
@ -6,12 +6,12 @@ use quickcheck::{Arbitrary, Gen};
|
|||||||
use num::{Bounded, One, Zero};
|
use num::{Bounded, One, Zero};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use rand;
|
use rand;
|
||||||
use rand::distributions::{Distribution, Standard};
|
use rand::distributions::{Distribution, Standard, StandardNormal};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use typenum::{self, Cmp, Greater};
|
use typenum::{self, Cmp, Greater};
|
||||||
|
|
||||||
use alga::general::{ClosedAdd, ClosedMul};
|
use alga::general::{ClosedAdd, ClosedMul, Real};
|
||||||
|
|
||||||
use base::allocator::Allocator;
|
use base::allocator::Allocator;
|
||||||
use base::dimension::{Dim, DimName, Dynamic, U1, U2, U3, U4, U5, U6};
|
use base::dimension::{Dim, DimName, Dynamic, U1, U2, U3, U4, U5, U6};
|
||||||
@ -501,6 +501,19 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl<N: Real, D: DimName> Distribution<Unit<VectorN<N, D>>> for Standard
|
||||||
|
where
|
||||||
|
DefaultAllocator: Allocator<N, D>,
|
||||||
|
StandardNormal: Distribution<N>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> Unit<VectorN<N, D>> {
|
||||||
|
Unit::new_normalize(VectorN::from_distribution_generic(D::name(), U1, &mut StandardNormal, rng))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Constructors for small matrices and vectors.
|
* Constructors for small matrices and vectors.
|
||||||
|
@ -6,7 +6,7 @@ use base::storage::Owned;
|
|||||||
use quickcheck::{Arbitrary, Gen};
|
use quickcheck::{Arbitrary, Gen};
|
||||||
|
|
||||||
use num::{One, Zero};
|
use num::{One, Zero};
|
||||||
use rand::distributions::{Distribution, Standard};
|
use rand::distributions::{Distribution, Standard, OpenClosed01};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use alga::general::Real;
|
use alga::general::Real;
|
||||||
@ -413,11 +413,25 @@ impl<N: Real> One for UnitQuaternion<N> {
|
|||||||
|
|
||||||
impl<N: Real> Distribution<UnitQuaternion<N>> for Standard
|
impl<N: Real> Distribution<UnitQuaternion<N>> for Standard
|
||||||
where
|
where
|
||||||
Standard: Distribution<N>,
|
OpenClosed01: Distribution<N>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sample<'a, R: Rng + ?Sized>(&self, rng: &'a mut R) -> UnitQuaternion<N> {
|
fn sample<'a, R: Rng + ?Sized>(&self, rng: &'a mut R) -> UnitQuaternion<N> {
|
||||||
UnitQuaternion::from_scaled_axis(rng.gen::<Vector3<N>>() * N::two_pi())
|
// Ken Shoemake's Subgroup Algorithm
|
||||||
|
// Uniform random rotations.
|
||||||
|
// In D. Kirk, editor, Graphics Gems III, pages 124-132. Academic, New York, 1992.
|
||||||
|
let x0 = rng.sample(OpenClosed01);
|
||||||
|
let x1 = rng.sample(OpenClosed01);
|
||||||
|
let x2 = rng.sample(OpenClosed01);
|
||||||
|
let theta1 = N::two_pi() * x1;
|
||||||
|
let theta2 = N::two_pi() * x2;
|
||||||
|
let s1 = theta1.sin();
|
||||||
|
let c1 = theta1.cos();
|
||||||
|
let s2 = theta2.sin();
|
||||||
|
let c2 = theta2.cos();
|
||||||
|
let r1 = (N::one() - x0).sqrt();
|
||||||
|
let r2 = x0.sqrt();
|
||||||
|
Unit::new_unchecked(Quaternion::new(s1 * r1, c1 * r1, s2 * r2, c2 * r2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,3 +447,18 @@ where
|
|||||||
UnitQuaternion::from_scaled_axis(axisangle)
|
UnitQuaternion::from_scaled_axis(axisangle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use rand::{self, SeedableRng};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn random_unit_quats_are_unit() {
|
||||||
|
let mut rng = rand::prng::XorShiftRng::from_seed([0xAB; 16]);
|
||||||
|
for _ in 0..1000 {
|
||||||
|
let x = rng.gen::<UnitQuaternion<f32>>();
|
||||||
|
assert!(relative_eq!(x.unwrap().norm(), 1.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,7 +5,7 @@ use quickcheck::{Arbitrary, Gen};
|
|||||||
|
|
||||||
use alga::general::Real;
|
use alga::general::Real;
|
||||||
use num::Zero;
|
use num::Zero;
|
||||||
use rand::distributions::{Distribution, Standard};
|
use rand::distributions::{Distribution, Standard, OpenClosed01};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::ops::Neg;
|
use std::ops::Neg;
|
||||||
|
|
||||||
@ -384,11 +384,34 @@ impl<N: Real> Rotation3<N> {
|
|||||||
|
|
||||||
impl<N: Real> Distribution<Rotation3<N>> for Standard
|
impl<N: Real> Distribution<Rotation3<N>> for Standard
|
||||||
where
|
where
|
||||||
Standard: Distribution<N>,
|
OpenClosed01: Distribution<N>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sample<'a, R: Rng + ?Sized>(&self, rng: &mut R) -> Rotation3<N> {
|
fn sample<'a, R: Rng + ?Sized>(&self, rng: &mut R) -> Rotation3<N> {
|
||||||
Rotation3::new(rng.gen::<Vector3<N>>() * N::two_pi())
|
// James Arvo.
|
||||||
|
// Fast random rotation matrices.
|
||||||
|
// In D. Kirk, editor, Graphics Gems III, pages 117-120. Academic, New York, 1992.
|
||||||
|
|
||||||
|
// Compute a random rotation around Z
|
||||||
|
let theta = N::two_pi() * rng.sample(OpenClosed01);
|
||||||
|
let (ts, tc) = theta.sin_cos();
|
||||||
|
let a = MatrixN::<N, U3>::new(
|
||||||
|
tc, ts, N::zero(),
|
||||||
|
-ts, tc, N::zero(),
|
||||||
|
N::zero(), N::zero(), N::one()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Compute a random rotation *of* Z
|
||||||
|
let phi = N::two_pi() * rng.sample(OpenClosed01);
|
||||||
|
let z = rng.sample(OpenClosed01);
|
||||||
|
let (ps, pc) = phi.sin_cos();
|
||||||
|
let sqrt_z = z.sqrt();
|
||||||
|
let v = Vector3::new(pc * sqrt_z, ps * sqrt_z, (N::one() - z).sqrt());
|
||||||
|
let mut b = v * v.transpose();
|
||||||
|
b += b;
|
||||||
|
b -= MatrixN::<N, U3>::identity();
|
||||||
|
|
||||||
|
Rotation3::from_matrix_unchecked(b * a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user