You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Conception/drake-master/math/hopf_coordinate.h

82 lines
3.0 KiB

/// @file
/// Hopf coordinates parametrizes SO(3) locally as the Cartesian product of a
/// one-sphere and a two-sphere S¹ x S². Computationally, each rotation in the
/// Hopf coordinates can be written as (θ, φ, ψ), in which ψ parametrizes the
/// circle S¹ and has a range of 2π, and θ, φ represent the spherical
/// coordinates for S², with the range of π and 2π respectively.
#pragma once
#include <cmath>
#include <Eigen/Dense>
#include <Eigen/Geometry>
#include "drake/common/drake_assert.h"
#include "drake/common/eigen_types.h"
namespace drake {
namespace math {
/**
* Transforms Hopf coordinates to a quaternion w, x, y, z as
* w = cos(θ/2)cos(ψ/2)
* x = cos(θ/2)sin(ψ/2)
* y = sin(θ/2)cos(φ+ψ/2)
* z = sin(θ/2)sin(φ+ψ/2)
* The user can refer to equation 5 of
* Generating Uniform Incremental Grids on SO(3) Using the Hopf Fibration
* by Anna Yershova, Steven LaValle and Julie Mitchell, 2008
* @param theta The θ angle.
* @param phi The φ angle.
* @param psi The ψ angle.
*/
template <typename T>
const Eigen::Quaternion<T> HopfCoordinateToQuaternion(const T& theta,
const T& phi,
const T& psi) {
using std::cos;
using std::sin;
const T cos_half_theta = cos(theta / 2);
const T sin_half_theta = sin(theta / 2);
const T phi_plus_half_psi = phi + psi / 2;
return Eigen::Quaternion(cos_half_theta * cos(psi / 2),
cos_half_theta * sin(psi / 2),
sin_half_theta * cos(phi_plus_half_psi),
sin_half_theta * sin(phi_plus_half_psi));
}
/**
* Convert a unit-length quaternion (w, x, y, z) (with the requirement w >= 0)
* to Hopf coordinate as
* ψ = 2*atan2(x, w)
* φ = mod(atan2(z, y) - ψ/2, 2pi)
* θ = 2*atan2(√(y²+z²), √(w²+x²))
* ψ is in the range of [-pi, pi].
* φ is in the range of [0, 2pi].
* θ is in the range of [0, pi].
* If the given quaternion has w < 0, then we reverse the signs of (w, x, y, z),
* and compute the Hopf coordinate of (-w, -x, -y, -z).
* @param quaternion A unit length quaternion.
* @return hopf_coordinate (θ, φ, ψ) as an Eigen vector.
*/
template <typename T>
Vector3<T> QuaternionToHopfCoordinate(const Eigen::Quaternion<T>& quaternion) {
if (quaternion.w() < 0) {
return QuaternionToHopfCoordinate(Eigen::Quaternion<T>(
-quaternion.w(), -quaternion.x(), -quaternion.y(), -quaternion.z()));
}
using std::atan2;
const T psi = 2 * atan2(quaternion.x(), quaternion.w());
const T phi_unwrapped = atan2(quaternion.z(), quaternion.y()) - psi / 2;
// The range of phi_unwrapped is [-1.5pi, 1.5pi]
const T phi = phi_unwrapped >= 0 ? phi_unwrapped : phi_unwrapped + 2 * M_PI;
using std::pow;
using std::sqrt;
const T theta =
2 * atan2(sqrt(pow(quaternion.y(), 2) + pow(quaternion.z(), 2)),
sqrt(pow(quaternion.w(), 2) + pow(quaternion.x(), 2)));
return Vector3<T>(theta, phi, psi);
}
} // namespace math.
} // namespace drake