[eigen] Mapping array of scalars into quaternions

[ Thread Index | Date Index | More lists.tuxfamily.org/eigen Archives ]


Hi,

I want to implement a class which hold both a quaternion and a vector3 to discribe a position of a frame in respect to an other frame (Something similar to Frame in KDL). For some historic reason, the memory layout must be a continuous array of scalar (Scalar[7]), the 3 first scalars are the vector3 and the other are the quaternion. Besides I have to interface this structure with other libraries which return an array of 7 scalars. I also have to map array of 4 scalars into the Quaternion class.

I though of something like that :

template<typename _Scalars>
struct Frame {
    _Scalars[7] data;
    Map<Matrix<3,1,_Scalars>> v;
    Map<Quaternion<_Scalars>> q;
};

and setting the Map accordingly. However, there's no such concept of Map for the Quaternion class or RotationBase.

So, I modified the Quaternion class to use either a Matrix<Scalar,4,1> to store the quaternion coefficients or a Map<Matrix<Scalar,4,1>> to map an array of scalars. I added a argument to the template prototype of the quaternion class which I call StorageType which is either the Matrix or Map<Matrix>. Since I have almost no experience with Eigen, I don't know if it's the better choice and if it could cause alignement issues. I have attached my modifications as a patch. This implementation may be incomplete.

So, to summarize, the Frame class would be:

template<typename _Scalars>
struct Frame {
    _Scalars[7] data;
    Map<Matrix<3,1,_Scalars>> v;
    QuaternionMap<_Scalars> q;
};

where v is a mapping of data and q a mapping of data+3.

--
Mathieu Gautier
# HG changeset patch
# User Mathieu Gautier <mathieu.gautier@xxxxxx>
# Date 1256125668 -7200
# Node ID bae1fcae32256eb29a7e1af8286816df8b98e284
# Parent  754dfef12c186fb259e088dc5a6a58e06445d3bd
* Quaternion could now map an array of scalars

diff -r 754dfef12c18 -r bae1fcae3225 Eigen/src/Core/util/ForwardDeclarations.h
--- a/Eigen/src/Core/util/ForwardDeclarations.h	Tue Oct 20 23:25:49 2009 -0400
+++ b/Eigen/src/Core/util/ForwardDeclarations.h	Wed Oct 21 13:47:48 2009 +0200
@@ -129,7 +129,7 @@
 // Geometry module:
 template<typename Derived, int _Dim> class RotationBase;
 template<typename Lhs, typename Rhs> class Cross;
-template<typename Scalar> class Quaternion;
+template<typename Scalar, class StorageType> class Quaternion;
 template<typename Scalar> class Rotation2D;
 template<typename Scalar> class AngleAxis;
 template<typename Scalar,int Dim,int Mode=Affine> class Transform;
diff -r 754dfef12c18 -r bae1fcae3225 Eigen/src/Geometry/Quaternion.h
--- a/Eigen/src/Geometry/Quaternion.h	Tue Oct 20 23:25:49 2009 -0400
+++ b/Eigen/src/Geometry/Quaternion.h	Wed Oct 21 13:47:48 2009 +0200
@@ -52,15 +52,15 @@
   * \sa  class AngleAxis, class Transform
   */
 
-template<typename _Scalar> struct ei_traits<Quaternion<_Scalar> >
+template<typename _Scalar, class StorageType> struct ei_traits<Quaternion<_Scalar, StorageType> >
 {
   typedef _Scalar Scalar;
 };
 
-template<typename _Scalar>
-class Quaternion : public RotationBase<Quaternion<_Scalar>,3>
+template<typename _Scalar, class StorageType = Matrix<_Scalar, 4, 1>> 
+class Quaternion : public RotationBase<Quaternion<_Scalar, StorageType>,3>
 {
-  typedef RotationBase<Quaternion<_Scalar>,3> Base;
+  typedef RotationBase<Quaternion<_Scalar, StorageType>,3> Base;
 
 
 
@@ -72,8 +72,11 @@
   /** the scalar type of the coefficients */
   typedef _Scalar Scalar;
 
+  typedef Quaternion<Scalar, Map<Matrix<Scalar, 4, 1>>> QuaternionMap;
+
   /** the type of the Coefficients 4-vector */
-  typedef Matrix<Scalar, 4, 1> Coefficients;
+//  typedef Matrix<Scalar, 4, 1> Coefficients; 
+  typedef StorageType Coefficients;
   /** the type of a 3D vector */
   typedef Matrix<Scalar,3,1> Vector3;
   /** the equivalent rotation matrix type */
@@ -124,8 +127,12 @@
   inline Quaternion(Scalar w, Scalar x, Scalar y, Scalar z)
   { m_coeffs << x, y, z, w; }
 
+  /** Constructs and initialize a quaternion from the array data
+    * This constructor is also used to map an array */
+  inline Quaternion(const Scalar* data) : m_coeffs(data) {}
+
   /** Copy constructor */
-  inline Quaternion(const Quaternion& other) { m_coeffs = other.m_coeffs; }
+  template<class OtherStorageType> inline Quaternion(const Quaternion<Scalar, OtherStorageType>& other) { m_coeffs = other.coeffs(); }
 
   /** Constructs and initializes a quaternion from the angle-axis \a aa */
   explicit inline Quaternion(const AngleAxisType& aa) { *this = aa; }
@@ -146,7 +153,7 @@
   /** \returns a quaternion representing an identity rotation
     * \sa MatrixBase::Identity()
     */
-  inline static Quaternion Identity() { return Quaternion(1, 0, 0, 0); }
+  inline static Quaternion<Scalar> Identity() { return Quaternion<Scalar>(1, 0, 0, 0); }
 
   /** \sa Quaternion::Identity(), MatrixBase::setIdentity()
     */
@@ -167,29 +174,29 @@
   inline void normalize() { m_coeffs.normalize(); }
   /** \returns a normalized version of \c *this
     * \sa normalize(), MatrixBase::normalized() */
-  inline Quaternion normalized() const { return Quaternion(m_coeffs.normalized()); }
+  inline Quaternion<Scalar> normalized() const { return Quaternion<Scalar>(m_coeffs.normalized()); }
 
   /** \returns the dot product of \c *this and \a other
     * Geometrically speaking, the dot product of two unit quaternions
     * corresponds to the cosine of half the angle between the two rotations.
     * \sa angularDistance()
     */
-  inline Scalar dot(const Quaternion& other) const { return m_coeffs.dot(other.m_coeffs); }
+  template<class OtherStorageType> inline Scalar dot(const Quaternion<Scalar, OtherStorageType>& other) const { return m_coeffs.dot(other.coeffs()); }
 
-  inline Scalar angularDistance(const Quaternion& other) const;
+  template<class OtherStorageType> inline Scalar angularDistance(const Quaternion<Scalar, OtherStorageType>& other) const;
 
   Matrix3 toRotationMatrix(void) const;
 
   template<typename Derived1, typename Derived2>
   Quaternion& setFromTwoVectors(const MatrixBase<Derived1>& a, const MatrixBase<Derived2>& b);
 
-  inline Quaternion operator* (const Quaternion& q) const;
-  inline Quaternion& operator*= (const Quaternion& q);
+  template<class OtherStorageType> inline Quaternion<Scalar> operator* (const Quaternion<Scalar, OtherStorageType>& q) const;
+  template<class OtherStorageType> inline Quaternion& operator*= (const Quaternion<Scalar, OtherStorageType>& q);
 
-  Quaternion inverse(void) const;
-  Quaternion conjugate(void) const;
+  Quaternion<Scalar> inverse(void) const;
+  Quaternion<Scalar> conjugate(void) const;
 
-  Quaternion slerp(Scalar t, const Quaternion& other) const;
+  template<class OtherStorageType> Quaternion<Scalar> slerp(Scalar t, const Quaternion<Scalar, OtherStorageType>& other) const;
 
   /** \returns \c *this with scalar type casted to \a NewScalarType
     *
@@ -201,8 +208,8 @@
   { return typename ei_cast_return_type<Quaternion,Quaternion<NewScalarType> >::type(*this); }
 
   /** Copy constructor with scalar type conversion */
-  template<typename OtherScalarType>
-  inline explicit Quaternion(const Quaternion<OtherScalarType>& other)
+  template<typename OtherScalarType, class OtherStorageType>
+  inline explicit Quaternion(const Quaternion<OtherScalarType, OtherStorageType>& other)
   { m_coeffs = other.coeffs().template cast<Scalar>(); }
 
   /** \returns \c true if \c *this is approximately equal to \a other, within the precision
@@ -225,9 +232,16 @@
   * double precision quaternion type */
 typedef Quaternion<double> Quaterniond;
 
+/** \ingroup Geometry_Module
+  * double precision quaternion type */
+typedef Quaternion<float>::QuaternionMap QuaternionMapf;
+/** \ingroup Geometry_Module
+  * double precision quaternion type */
+typedef Quaternion<double>::QuaternionMap QuaternionMapd;
+
 // Generic Quaternion * Quaternion product
-template<int Arch,typename Scalar> inline Quaternion<Scalar>
-ei_quaternion_product(const Quaternion<Scalar>& a, const Quaternion<Scalar>& b)
+template<int Arch,typename Scalar, class StorageType, class OtherStorageType> inline Quaternion<Scalar>
+ei_quaternion_product(const Quaternion<Scalar, StorageType>& a, const Quaternion<Scalar, OtherStorageType>& b)
 {
   return Quaternion<Scalar>
   (
@@ -239,15 +253,17 @@
 }
 
 /** \returns the concatenation of two rotations as a quaternion-quaternion product */
-template <typename Scalar>
-inline Quaternion<Scalar> Quaternion<Scalar>::operator* (const Quaternion& other) const
+template <typename Scalar, class StorageType>
+template <class OtherStorageType>
+inline Quaternion<Scalar> Quaternion<Scalar, StorageType>::operator* (const Quaternion<Scalar, OtherStorageType>& other) const
 {
-  return ei_quaternion_product<EiArch>(*this,other);
+  return ei_quaternion_product<EiArch, Scalar, StorageType, OtherStorageType>(*this, other);
 }
 
 /** \sa operator*(Quaternion) */
-template <typename Scalar>
-inline Quaternion<Scalar>& Quaternion<Scalar>::operator*= (const Quaternion& other)
+template <typename Scalar, class StorageType>
+template <class OtherStorageType>
+inline Quaternion<Scalar, StorageType>& Quaternion<Scalar, StorageType>::operator*= (const Quaternion<Scalar, OtherStorageType>& other)
 {
   return (*this = *this * other);
 }
@@ -259,9 +275,9 @@
   *   - Quaternion:    30n
   *   - Via a Matrix3: 24 + 15n
   */
-template <typename Scalar>
-inline typename Quaternion<Scalar>::Vector3
-Quaternion<Scalar>::_transformVector(Vector3 v) const
+template <typename Scalar, class StorageType>
+inline typename Quaternion<Scalar, StorageType>::Vector3
+Quaternion<Scalar, StorageType>::_transformVector(Vector3 v) const
 {
     // Note that this algorithm comes from the optimization by hand
     // of the conversion to a Matrix followed by a Matrix/Vector product.
@@ -272,8 +288,8 @@
     return v + this->w() * uv + this->vec().cross(uv);
 }
 
-template<typename Scalar>
-inline Quaternion<Scalar>& Quaternion<Scalar>::operator=(const Quaternion& other)
+template<typename Scalar, class StorageType>
+inline Quaternion<Scalar, StorageType>& Quaternion<Scalar, StorageType>::operator=(const Quaternion& other)
 {
   m_coeffs = other.m_coeffs;
   return *this;
@@ -281,8 +297,8 @@
 
 /** Set \c *this from an angle-axis \a aa and returns a reference to \c *this
   */
-template<typename Scalar>
-inline Quaternion<Scalar>& Quaternion<Scalar>::operator=(const AngleAxisType& aa)
+template<typename Scalar, class StorageType>
+inline Quaternion<Scalar, StorageType>& Quaternion<Scalar, StorageType>::operator=(const AngleAxisType& aa)
 {
   Scalar ha = Scalar(0.5)*aa.angle(); // Scalar(0.5) to suppress precision loss warnings
   this->w() = ei_cos(ha);
@@ -295,9 +311,9 @@
   *   - if \a xpr is a 3x3 matrix, then \a xpr is assumed to be rotation matrix
   *     and \a xpr is converted to a quaternion
   */
-template<typename Scalar>
+template<typename Scalar, class StorageType>
 template<typename Derived>
-inline Quaternion<Scalar>& Quaternion<Scalar>::operator=(const MatrixBase<Derived>& xpr)
+inline Quaternion<Scalar, StorageType>& Quaternion<Scalar, StorageType>::operator=(const MatrixBase<Derived>& xpr)
 {
   ei_quaternion_assign_impl<Derived>::run(*this, xpr.derived());
   return *this;
@@ -306,9 +322,9 @@
 /** Convert the quaternion to a 3x3 rotation matrix. The quaternion is required to
   * be normalized, otherwise the result is undefined.
   */
-template<typename Scalar>
-inline typename Quaternion<Scalar>::Matrix3
-Quaternion<Scalar>::toRotationMatrix(void) const
+template<typename Scalar, class StorageType>
+inline typename Quaternion<Scalar, StorageType>::Matrix3
+Quaternion<Scalar, StorageType>::toRotationMatrix(void) const
 {
   // NOTE if inlined, then gcc 4.2 and 4.4 get rid of the temporary (not gcc 4.3 !!)
   // if not inlined then the cost of the return by value is huge ~ +35%,
@@ -352,9 +368,9 @@
   * Note that the two input vectors do \b not have to be normalized, and
   * do not need to have the same norm.
   */
-template<typename Scalar>
+template<typename Scalar, class StorageType>
 template<typename Derived1, typename Derived2>
-inline Quaternion<Scalar>& Quaternion<Scalar>::setFromTwoVectors(const MatrixBase<Derived1>& a, const MatrixBase<Derived2>& b)
+inline Quaternion<Scalar, StorageType>& Quaternion<Scalar, StorageType>::setFromTwoVectors(const MatrixBase<Derived1>& a, const MatrixBase<Derived2>& b)
 {
   Vector3 v0 = a.normalized();
   Vector3 v1 = b.normalized();
@@ -395,17 +411,17 @@
   *
   * \sa Quaternion::conjugate()
   */
-template <typename Scalar>
-inline Quaternion<Scalar> Quaternion<Scalar>::inverse() const
+template <typename Scalar, class StorageType>
+inline Quaternion<Scalar> Quaternion<Scalar, StorageType>::inverse() const
 {
   // FIXME should this function be called multiplicativeInverse and conjugate() be called inverse() or opposite()  ??
   Scalar n2 = this->squaredNorm();
   if (n2 > 0)
-    return Quaternion(conjugate().coeffs() / n2);
+    return Quaternion<Scalar>(conjugate().coeffs() / n2);
   else
   {
     // return an invalid result to flag the error
-    return Quaternion(Coefficients::Zero());
+    return Quaternion<Scalar>(Coefficients::Zero());
   }
 }
 
@@ -415,17 +431,18 @@
   *
   * \sa Quaternion::inverse()
   */
-template <typename Scalar>
-inline Quaternion<Scalar> Quaternion<Scalar>::conjugate() const
+template <typename Scalar, class StorageType>
+inline Quaternion<Scalar> Quaternion<Scalar, StorageType>::conjugate() const
 {
-  return Quaternion(this->w(),-this->x(),-this->y(),-this->z());
+  return Quaternion<Scalar>(this->w(),-this->x(),-this->y(),-this->z());
 }
 
 /** \returns the angle (in radian) between two rotations
   * \sa dot()
   */
-template <typename Scalar>
-inline Scalar Quaternion<Scalar>::angularDistance(const Quaternion& other) const
+template <typename Scalar, class StorageType>
+template <class OtherStorageType>
+inline Scalar Quaternion<Scalar, StorageType>::angularDistance(const Quaternion<Scalar, OtherStorageType>& other) const
 {
   double d = ei_abs(this->dot(other));
   if (d>=1.0)
@@ -436,14 +453,15 @@
 /** \returns the spherical linear interpolation between the two quaternions
   * \c *this and \a other at the parameter \a t
   */
-template <typename Scalar>
-Quaternion<Scalar> Quaternion<Scalar>::slerp(Scalar t, const Quaternion& other) const
+template <typename Scalar, class StorageType>
+template <class OtherStorageType>
+Quaternion<Scalar> Quaternion<Scalar, StorageType>::slerp(Scalar t, const Quaternion<Scalar, OtherStorageType>& other) const
 {
   static const Scalar one = Scalar(1) - precision<Scalar>();
   Scalar d = this->dot(other);
   Scalar absD = ei_abs(d);
   if (absD>=one)
-    return *this;
+    return Quaternion<Scalar>(*this);
 
   // theta is the angle between the 2 quaternions
   Scalar theta = std::acos(absD);
@@ -454,7 +472,7 @@
   if (d<0)
     scale1 = -scale1;
 
-  return Quaternion(scale0 * m_coeffs + scale1 * other.m_coeffs);
+  return Quaternion<Scalar>(scale0 * m_coeffs + scale1 * other.coeffs());
 }
 
 // set from a rotation matrix


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/