This bugzilla service is closed. All entries have been migrated to https://gitlab.com/libeigen/eigen

Bug 1244

Summary: quaternion exponential logarithm
Product: Eigen Reporter: Michael Norel <minorlogic>
Component: GeometryAssignee: Nobody <eigen.nobody>
Status: DECISIONNEEDED ---    
Severity: Feature Request CC: chtz, gael.guennebaud, hauke.heibel, jacob.benoit.1, mail
Priority: Normal    
Version: 3.3 (current stable)   
Hardware: All   
OS: All   
Whiteboard:
Bug Depends on: 1312    
Bug Blocks: 814    

Description Michael Norel 2016-06-23 15:20:25 UTC
For me, it can be useful to have conversions to/from rodrigues parameters from/to quaternions. 

Usualy it is called " exponential/logarithm" (from lie algebra). As it can be seen in "Sophus" library built on top of Eigen.
https://github.com/strasdat/Sophus/blob/master/sophus/so3.hpp


My versions of this operations looks like (the SO3 class represent 3 rodrigues params in member m_coeffs ): 

SO3(const QuaternionT& q_)
    {
        // forcing positive "w" to work from 0 to PI
        const QuaternionT& q = q_.w() >= Scalar(0) ? q_ : QuaternionT(-q_.coeffs());

        const Vector3& qv = q.vec();
        
        Scalar sinha = qv.norm();
        if(sinha > Scalar(0))
        {
            Scalar angle = Scalar(2) * atan2(sinha, q.w()); //NOTE: signed
            m_coeffs = qv * (angle/sinha);
        }else{
            // if l is too small, its norm can be equal 0 but norm_inf greater 0
            // probably w is much bigger that vec, use it as length
            m_coeffs = qv * (Scalar(2)/q.w()); ////NOTE: signed
        }
    }

NOTE: it is important to keep rodrigues params inside (0 ...PI) interval for precision. Also all handmade taylor expansions of SINC is not useful and have no better precision than direct computation.

    
    
    QuaternionT getQuaternion() const
    {
        QuaternionT q;
        const Vector3 ha = m_coeffs/Scalar(2); // vector of half angle
        
        Scalar l = ha.norm();
        if( l > Scalar(0) )
        {
            Scalar ss = sin(l)/l;
            q = QuaternionT(cos(l), ha.x()*ss, ha.y()*ss, ha.z()*ss);
        }else{
            // if l is too small, its norm can be equal 0 but norm_inf greater 0
            q = QuaternionT(Scalar(1), ha.x(), ha.y(), ha.z());
        }
        
        return q;
    }
Comment 1 Michael Norel 2016-09-26 09:56:23 UTC
UPD: more compact version of "Lie 2 Quat" conversion, with same precision

 QuaternionT getQuaternion() const
    {
        Scalar a = m_coeffs.norm();
        Scalar ha = a * Scalar(0.5);
        Scalar scale = a > Scalar(0) ? sin(ha) / a : Scalar(0.5);

        return QuaternionT(cos(ha), x() * scale, y() * scale, z() * scale);
    }
Comment 2 Gael Guennebaud 2016-09-27 07:17:35 UTC
Those are essentially variants of the current AngleAxis <-> Quaternion conversion methods where the angle is embedded in the norm of the rotation axis.

The main question is about the API. We could start with: 

QuaternionBase::fromAngleAxisVector(const MatrixBase<Derived>& vec);
Vector3 QuaternionBase::toAngleAxisVector();

and then think about adding a ctor and operator= as aliases to fromAngleAxisVector?
Comment 3 Christoph Hertzberg 2016-09-27 08:05:12 UTC
I usually know it by the name "Scaled Axis", so I'd prefer fromScaledAxis(...), etc. I don't really like adding operator= and a constructor for thi conversion, since it would hide what is happening there (this is not the only possible map from R^3 to S^3).
Comment 4 Michael Norel 2016-09-27 08:48:13 UTC
QuaternionBase::fromAngleAxisVector(const MatrixBase<Derived>& vec);
Vector3 QuaternionBase::toAngleAxisVector();

This sounds for me very confusing. It is not common "term". Common terms (for me) from computer vision is:

1. Exponential map 
https://en.wikipedia.org/wiki/Rotation_matrix#Exponential_map
https://en.wikipedia.org/wiki/Rotation_group_SO(3)#Exponential_map
2. Rodrigues parameters
https://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions#Rodrigues_parameters_and_Gibbs_representation

3. Lie parameters
4. Logarithm/exponent or tangent.  
https://pixhawk.org/_media/dev/know-how/jlblanco2010geometry3d_techrep.pdf
chapter "SE(3) as a Lie group"


For example openCV uses Rodrigues "term", Sophus uses SE3::exp(..) and SE3::log(..) as static member functions. 

Also "AngleAxis" usualy mean exactly Angle + Axis, and it is hard to discover that so named functions works with lie params. 

This operations and representations is common for computer vision, 3d reconstruction. 


Please assume this set of names:

fromRodrigues
toRodrigues

fromExpMap
toExpMap

fromLie
toLie

exp
log

logarithmicMap
exponentialGroup 

logarithm
exponent

fromTangent
toTangent


i prefer: 

log
exp

or 

logarithm
exponent
Comment 5 Michael Norel 2016-09-27 14:46:05 UTC
(In reply to Christoph Hertzberg from comment #3)
> I don't really like adding operator= and a
> constructor for thi conversion, since it would hide what is happening there
> (this is not the only possible map from R^3 to S^3).

I agree, it is not "common" operation for creation of quaternion, and can be mixed up with "Euler angles" etc.

i prefer some similar way that uses "FromTwoVectors" member.
Comment 6 Gael Guennebaud 2016-09-27 22:03:45 UTC
I agree my naming suggestion was pretty bad. Nonetheless, I still think that we should put the emphasis on the *representation* of the input/output using names matching:

FromRepresentationName
fromRepresentationName
toRepresentationName

According to: https://en.wikipedia.org/wiki/Axis%E2%80%93angle_representation, and some other resources, choice for RepresentationName could be:

- RotationVector
- EulerVector

plus the ScaleAxis proposal of Christoph.

Among those three, I would slightly prefer RotationVector:

- ScaleAxis does not convey the idea of a rotation
- EulerVector might be confused with a vector storing Euler angles.
- RotationVector might be confused with RotationAxis, but then fromRotationAxis would make no sense, and toRotationVector does return the rotation axis (it's just that it is not normalized).


See also this old thread for an extensive discussion and proposals for the proper introduction of Lie group and algebra their exp/log maps.
Comment 7 Gael Guennebaud 2016-09-28 13:40:54 UTC
I forgot to paste the link:

https://listengine.tuxfamily.org/lists.tuxfamily.org/eigen/2010/04/msg00109.html
Comment 8 Gael Guennebaud 2016-09-28 13:43:08 UTC
That thread is also related:
https://listengine.tuxfamily.org/lists.tuxfamily.org/eigen/2012/05/msg00028.html
Comment 9 Michael Norel 2016-09-29 13:39:30 UTC
Note: 

- RotationVector 
https://en.wikipedia.org/wiki/Rotation_(mathematics)
- EulerVector
https://en.wikipedia.org/wiki/Axis%E2%80%93angle_representation

Give correct description from google,

 but - ScaleAxis not.
Comment 10 Christoph Hertzberg 2016-09-29 14:44:45 UTC
I did say "Scaled Axis" not "Scale Axis", but admittedly that was mostly the common naming at my former group (however there are several positive google hits for that name as well).
But I don't have strong feelings for that name.

Given the other options I'd prefer RotationVector over EulerVector. I don't think the confusion risk with RotationAxis is too big in contrast to the danger of confusing EulerVector with EulerAngles. The bad thing is that for small angles they agree (with Euler angles in XYZ convention), get slightly different for medium angles and are completely off, when the Euler angles are near their singularities.
Comment 11 Michael Norel 2016-09-29 15:46:50 UTC
(In reply to Christoph Hertzberg from comment #10)
I agree, EulerVector will be mixed up with Euler angles. And RotationVector sound better among 3 versions.
Comment 12 Adrian Haarbach 2016-10-20 10:45:20 UTC
I am using these implementations of quaternion exp and log mapping:
https://github.com/hengli/vmav-ros-pkg/blob/master/calibration/hand_eye_calibration/include/hand_eye_calibration/QuaternionMapping.h

These also work for non-unit quaternions. If bug 560 is solved in 3.3, one could just add them to the API of the GeneralQuaternion interface and, if needed, add the more specialized exp/log implementations for unit quaternions that were discussed above to the UnitQuaternion interface.
Comment 13 Michael Norel 2016-10-21 08:46:36 UTC
(In reply to Adrian Haarbach from comment #12)

Seems it little bit different functionality with additional performance loose. Don't you think it is better to use as overloaded "exp/log" functions for exact "math" interpretation of  "exp/log"?

P.S. did you tried the "boost::quaternion" implementation of their quaternion operations?
Comment 14 Nobody 2019-12-04 15:56:27 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to gitlab.com's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.com/libeigen/eigen/issues/1244.