Re: [eigen] Eigen appears to rock.
• To: eigen@xxxxxxxxxxxxxxxxxxx
• Subject: Re: [eigen] Eigen appears to rock.
• From: "Thomas Vaughan" <tevaughan@xxxxxxxxx>
• Date: Thu, 21 Aug 2008 22:55:55 -0600
• Domainkey-signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:to:subject:in-reply-to:mime-version :content-type:content-transfer-encoding:content-disposition :references; b=nL1m2Lu/OyJy2KXRcy0YT9Nhbco6bJgiCcrgAhQfEXbrhex9UaZl/ieW+4Oe2QKy+X 7ZY/2J/KPsYA6S9AlUOVfuLH443XUYigAI3P/ss6ZzarBtmzVPW9kb0SiDqkyke9C7qR fpATFRjtds0h8SHflpbR6TJUhmf8zEHX3SGGA=

```On Thu, Aug 21, 2008 at 3:38 AM, Gael Guennebaud
<gael.guennebaud@xxxxxxxxx> wrote:
>
> thanks for your interest in Eigen.

Thanks for your thoughtful response.  :^)

> Transform3f T;
> Vector3f p;
> Vector4f h;
>
> "T * p"  returns a 3 components vector equal to "T.affine() * p +
> T.translation()"
>
> "T * h"  returns a 4 components vector equal to "T.matrix() * h"
>
> T.matrix() is the internal 4x4 transformation matrix.
>
> T.affine() is the 3x3 affine part of the above 4x4 matrix (it
> represents the rotation + scale + shear)

This is a bit confusing because an affine transformation in general
combines a linear transformation and a translation.  Perhaps it might be
better to make "T*p" be equal to "T.linear()*p + T.translation()", where
"T.linear()" returns the appropriate 3x3 block of the 4x4 inside T.

In any event, it would seem that "T*p" promotes p to a 4-vector with 1
as the fourth element, then multiplies the 4x4 inside T by the promoted
version of p, and then returns three of the components of the resultant
4-vector.  Or something like that.

> So if you want to transform a vector you can still write "T.affine() *
> v" (or, as you suggested, use homogeneous vectors).

I think that I understand.

> Now what about distinguishing Point and Vector types ? I have to say
> that I've already used a couple of libraries making such a type
> difference, and every time I ended up with spending my time to convert
> Point to Vector (remove zero) and Vector to Point (add zero), and I
> disliked that a lot.

I must admit that I'm not following you completely.  Clearly, the Point
class would need to have an autoconversion operator to Scalar* so that
it could be passed to a C library function that expects a C-style array
of coordinates.  However, at least in my experience (which is probably
less than yours), I want my Points to be Points, and I hardly ever want
to convert a Point to a Vector.  Of course, it does often make sense to
calculate a Vector as the difference between two Points, but that's why
I define "Vector operator-(const Point&, const Point&)".

I am not advocating that you change your API to suit my tastes, but I am
interested in understanding why my taste on this matter might not be
well developed, and I appreciate your patient and thoughtful replies.

> From a practical point of view the only difference between Points and
> Vectors happens when you apply a transformation.

In my opinion, this thinking is a bit sloppy.

The addition of two vectors is well defined; after all, vectors are
elements of a linear vector space.  Although one can define an
isomorphism from the points in a three-dimensional Euclidean space to
the set of vectors in a three-dimensional vector space, there is no
unique such mapping, and so the addition of points in general is not
well defined.  So a proper Point class will *not* have operator+(const
Point&, const Point&).  If you try to add two Points, then you should
get a compiler error.  Similarly, a simple rotation that can transform a
vector is not defined for a point because the *location* of the axis of
rotation must also be specified.

There is a load of differences.

> Therefore, I prefer to have these conversions implicit (by using only
> Vectors) and give the specific semantic when I apply a transformation.

I understand your preference.  It requires that the programmer keep
track of the real type by way of a variable-naming scheme and/or
otherwise in his head.  What bothers me is that we have this nice way of
doing strong typing, but we don't take advantage of it, and we compound
the confusion in our minds by incessantly referring to a point as though
it were a vector, at least in its type name.  I admit that these might
be small hindrances in the grand scheme of things, but for some reason
they really bother me.

> Moreover, if your vectors represent differential quantities of an
> object (gradient, normal, tangents) then you need to transform them by
> the Jacobian of your transformation, which is for an affine
> transformation matrix the transpose of the inverse, e.g.:
>
> T.affine().inverse().transpose() * normal;
>
> (of course if your affine transformation is a pure rotation then you
> can use T.affine() right away).
>
> That means you would not need only 2 different types (Point and
> Vector) but also a third one: DifferentialVector. I cannot imagine the
> nightmare to use a lib which would do that !!

That's a really interesting point.  I did not spend the time to work
through the math, but the idea, presumably, is that the differential
quantity is *not* a vector because it doesn't transform as a vector
transforms.  (Also, a tensor of rank two transforms differently from a
vector, which is a tensor of rank one.)  In my opinion, we should not
call it a vector if it is not, in fact, a vector.  Just as a point is
not a vector.

I don't see why this would be a nightmare to implement.  I think that
the Point class, for example, would not be a nightmare to implement.
It's really rather simple.  In my toy version, I just aggregate a
Vector3d and provide the few functions that I've talked about for an
interface.

It would be wonderful to make all of the proper distinctions, and it
would be didactic.

In fact, your system as it stands is beautiful to me in large part
because the underlying mathematical forms are clearly expressed in the
library.  To stop short on this point seems to me a kind of unnecessary
incompleteness.

But I hope that I could come to understand the necessity, if my
distinctions were

(a) truly impractical to make,
(b) abhorrent to your aesthetic sensibilities, or
(c) just plain misconceptions on my part.  :^)

> So really, I think using only Vector is the best way to go, and if you
> really want to distinguish Point and Vector, the elegant solution
> would be to use homogeneous vectors, but 1) this requires an
> additional component 2) this increases computation time 3) this
> requires very great care from the user and might yields very hard to
> find bugs. So again, IMO, using only Vector is not bad !

Indeed, having a Vector3f to model a point is better than keeping track
of a separate variable for each coordinate.

Nevertheless, in my naive imagination, I should like something like
this:

Transform3f T;
Vector3f v;
Point3f p;

"T * v"  returns a Vector3f corresponding to just the linear
transformation.  This is different from what you do now, which is to
assume that v is a point.

"T * p"  returns a Point3f corresponding to the whole affine
transformation (linear transformation plus translation).

In this way, one could put all of one's information about a coordinate
transformation into an object of type T and then use that same object
conveniently on vectors and on points without worrying about any
details.

Point3f should probably aggregate a descendant of (instead of inheriting
from) MatrixBase.  Because a point is not a vector (matrix), there is
not an "is a" relationship with the base class.  Anyway, the interface
for Point is much, much smaller.

In the end, I hope that you are at the very least entertained by this
discussion.  :^)

--
Thomas E. Vaughan

There are only two kinds of people; those who accept dogma and know it,
and those who accept dogma and don't know it. - G.K. Chesterton

```

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