Re: [eigen] Euler-angles and partial reductions API design

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


On Saturday 19 July 2008 00:04:36 Gael Guennebaud wrote:
> On Fri, Jul 18, 2008 at 11:10 PM, Benoît Jacob <jacob@xxxxxxxxxxxxxxx> 
wrote:
> > I agree with you that operation on the right should be the default, as
> > it's what OpenGL does. Whence the naming used in Eigen1. What I don't
> > understand is how this is any issue in Eigen2 and the draft eulerangles
> > API ? I mean, when you write rotationX(angleX) * m it's obviously
> > multiplying m on the left; in Eigen1 or OpenGL it's more problematic
> > because of the API not using natural math notation.
>
> the issue is if we have a class (or function) which build a rotation
> directly from 3 angles:
>
> EulerAngles<float>(a0, a1, a2)
>
> there might be 24 interpretations !!

OK I understand.

I think it was quite acceptable to force XYZ order but that's just my opinion.

>
> in my second mail, I suggested to create only elementary rotations and
> compose them manually such that there is no ambiguity:
>
> rotationX(a0) * rotationY(a1) * rotationX(a2)

OK.

>
> > The idea that I like best, among the ones you propose, is static
> > MatrixBase::rotation{XYZ} functions. Let's not use functor classes unless
> > needed, and I don't see the need here.
>
> I was not referring to functor, but something like that:
>
> template<typename Scalar>
> class RotationX : public Matrix<Scalar,3,3> {
> public:
>  Rotation(Scalar angle) { *this << .....sin, cos,....; }
> };
>
> anyway, maybe not very good as it creates new types...

Ah OK. Then indeed as you point out it's not too good.

> In that case we indeed build matrices, so the composition of several
> elementary rotations would not be optimal but:
> 1 - not too bad, for 3 rotations (i.e., 2 products) we have 54 ops
> versus 21 ops...
> 2 - I don't see any use case where the perf of euler angles is
> critical,

Same for me. Somehow I was assuming that you had such a use case, but if it's 
not the case then let's do as you say below, ...

> again for me euler angles are not an optimization, 
>       they are just a convenient way to setup the orientation of an object.
>
> So, if you think that:
>
> Matrix3f m2 = AngleAxis<float>(a1, Vector3f(1,0,0))
>              * AngleAxis<float>(a2, Vector3f(0,1,0))
>              * AngleAxis<float>(a3, Vector3f(0,0,1));
>
> is not verbose and as easy to read as the version with RotationX(),
> then let's just forget about Euler angles, and we are done.

Ah then I say exactly that!

In Eigen1 we had matrix.loadRotation(angle, axis) and then 
matrix.rotate(angle, axis) multiplying on the right like OpenGL, and 
matrix.prerotate(angle, axis) multiplying on the left.

In Eigen2 we can have the same thing but with a nicer API,

matrix = Matrix3f::rotation(angle, axis) instead of loadRotation(), although 
we could let loadRotation survive as setRotation(). We could leave rotate() 
and prerotate() unchanged (well actually in Eigen1 they were named rotate3() 
but that's bad).

> But I would prefer to propose a shorter and safer path... IMO, writing
> the basis vectors manually with Vector3f(0,1,0) is quite error prone
> (you know, dyslexia etc.).
>
> So, maybe with two typedef for AngleAxis<float / double>, and more
> general shortcuts to write the basis vectors would be a good option as
> well:
>
>  Vector3f::UnitX();
>  Vector3f::UnitY();
>  Vector3f::UnitZ();
>  Vector4f::UnitW();
> and a generic:
>  VectorXf::Unit(i)
>
>  and they could simply return "identity().col(i)".

Good idea! so

matrix = Matrix3f::rotation(angle, Vector3f::UnitX())

seems explicit enough to me.

Again this is not efficient but since like me you don't see any 
performance-critical use case, and it seemed to be working well for eigen1 
and is of course also what OpenGL does, we can perhaps also live with that in 
eigen2.

Cheers,
Benoit

>
>
> what do you think ?
>
> gael.
>
> > Indeed a EulerAngles class is needed
> > because if rotation{XYZ} returned a matrix then doing
> > rotationX(angleX)*rotationY(angleY)*rotationZ(angleZ)
> > would be terribly inefficient. So rotation{XYZ} returns a EulerAngles
> > object and the actual rotationation matrix is computed in operator= or
> > EulerAngles::operator*(vector) (yes this lends itself very well to
> > optimization and suddenly I think this could be the most useful use case
> > for EulerAngles).
> >
> > I'm not a fan of the last option with typedefs, because "Xf" means
> > dynamic-size-float so at least the naming is misleading (and as I said I
> > prefer functions over short functor classes anyway).
> >
> > There is one thing that needs to be discussed. The whole point of
> > EulerAngles is performance -- otherwise we could do as in Eigen1, i.e. do
> > only a generic rotation(angle,vector) method. In many cases, the user
> > will use only one eulerAngle, i.e.
> > Matrix3f::rotationY(pi/12) * vector
> > We don't want the EulerAngle::operator* to compute three sin/cos pairs
> > when only one is needed! So the EulerAngles class is not so trivial to
> > implement, There are up to 7 cases to handle,
> > X, Y, Z, XY, YZ, XZ, XYZ,
> > it looks a bit tedious. It might be possible to avoid the tediousness at
> > zero overhead using template magic, but that is probably even more
> > cumbersome to write!
> >
> > Cheers,
> >
> > Benoit
> >
> > On Friday 18 July 2008 02:00:15 Gael Guennebaud wrotationatione:
> >> I agree Euler angles are somewhat useless (and might even be dangerous
> >> for the beginners because of their apparent simplicity). Nevertheless
> >> they remain really conveniant to specify/initialize the orientation of
> >> an object as a concatenation of elementary rotationationations. In this
> >
> > context
> >
> >> I think it very important to be able to specify the order, otherwise
> >> we completely miss the convenience point. So if we agree this is the
> >> only use case, then we can drop the EulerAngles class, and provide and
> >> alternative, more explicit and generic API. Actually currently it is
> >> possible to mimic the proposed:
> >>
> >>   Matrix3f m = EulerAngles<float,XYZ>(1,2,3);
> >>
> >> by
> >>
> >>   Matrix3f m2 = AngleAxis<float>(1, Vector3f(1,0,0))
> >>               * AngleAxis<float>(2, Vector3f(0,1,0))
> >>               * AngleAxis<float>(3, Vector3f(0,0,1));
> >>
> >> that is a bit heavy (though quite often 1 or 2 elementary
> >
> > rotationationations
> >
> >> are enough to reach the desired orientation).
> >> So what we could do is to make easier the creation of elementary
> >> rotationationations using either:
> >>
> >> * static functions of Matrix:
> >>   Matrix3f m = Matrix3f::rotationationX(1) * Matrix3f::rotationationY(2)
> >> *
> >
> > Matrix3f::rotationationZ(3);
> >
> >> * super short classes inheriting Matrix<Scalar,3,3> (or global
> >> functions) Matrix3f m = rotationationX<float>(1) *
> >> rotationationY<float>(2) *
> >
> > rotationationZ<float>(3);
> >
> >> * the same with typedef  (or alias):
> >>   Matrix3f m = rotationationXf(1) * rotationationYf(2) *
> >> rotationationZf(3);
> >>
> >> I have to say I like this last option, though someones might find the
> >> names not explicit enough ? it might also be confusing with
> >
> > the "rotationation"
> >
> >> vector operator (curl) ?
> >>
> >> gael.
> >>
> >> On Thu, Jul 17, 2008 at 8:00 PM, Christian Mayer
> >> <mail@xxxxxxxxxxxxxxxxx>
> >
> > wrotationatione:
> >> > -----BEGIN PGP SIGNED MESSAGE-----
> >> > Hash: SHA256
> >> >
> >> > Gael Guennebaud schrieb:
> >> >> Let's start with the EulerAngles class of the geometry module. [...]
> >> >
> >> > Apart from the fact that EulerAngles are quite useless for real work I
> >> > can understand that beginners usually want them to get a quick
> >> > start...
> >> >
> >> > Generally it's best to keep the libaray as small and generic as
> >> > possible.
> >> >
> >> > So I'd offer only one function that generates the rotationationation
> >
> > matrix. This
> >
> >> > function should have a fixed order (that's identical to OpenGL -
> >> > although I didn't find a gl, glu or glut function that uses euler
> >> > angles...).
> >> >
> >> > If the user wants a left or a right multiplication is totally up to
> >> > him, so the library should try to be smarter :)
> >> >
> >> > CU,
> >> > Christian
> >> > -----BEGIN PGP SIGNATURE-----
> >> > Version: GnuPG v1.4.6 (GNU/Linux)
> >> >
> >> > iD8DBQFIf4itoWM1JLkHou0RCD8LAJ0fLw/XfnBezR5i43q4Izln9Hy0VgCfZGDr
> >> > dXdk5TfQ8eSvSDRjtxzFuWU=
> >> > =JZq/
> >> > -----END PGP SIGNATURE-----


Attachment: signature.asc
Description: This is a digitally signed message part.



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