Affine transforms - matrix algebra

Jim Graham james.graham at
Thu Aug 16 15:52:44 PDT 2012

On 8/16/2012 10:38 AM, Pavel Safrata wrote:
> On 16.8.2012 16:29, Richard Bair wrote:
>>> New NoninvertibleTransformException
>> I believe it should be NonInvertibleTransformException with a capital
>> "I".
> Both in J2D and in our internal geom packages the "i" is lower-case. But
> I have no problem changing it.

In particular, Non isn't a word so why should it be separated (via 
capitalization) from the word to which it is a prefix?

>>> public Point3D deltaTransform(Point3D point)
>>> public Point2D deltaTransform(Point2D point)
>>> // transformation without translation (transformation of a vector)
>>> public Point3D inverseDeltaTransform(Point3D point)
>>> public Point2D inverseDeltaTransform(Point2D point)
>>> // inverse transformation without translation
>> I haven't followed the entire thread, but this was the first part of
>> the API who's meaning wasn't immediately obvious. What is a delta
>> transform, and what is it used for?
> It is transformation without translation. In another words, it is
> transformation of a vector. Unfortunately we have point and vector both
> represented by a single class (PointND), but point is transformed
> differently than vector. So deltaTransform transforms PointND as if it
> was a vector. This approach is copied from J2D.

It is also used for transforming dimensions.  You may transform the 
origin of a rectangle using an absolute transform, but if you transform 
the width and height (assuming that it is not a rotated transform 
otherwise you can't use this shortcut), then you need a delta transform 
otherwise the size is affected by where the rectangle is.

It's not really a different usage since one could consider w,h as a 
vector from the origin of the rect and so Pavel's use case is really the 
same case, but "transforming dimensions" might make better sense to 
someone who hasn't fully grasped what "this vector thing" is.  In 
particular, J2D has delta transforms and we don't even mention vectors 
or have any such objects anywhere in that API.

>>> public double determinant()
>> Why isn't this a getter?
> Because currently it is not a property.

I'm not sure one would want to track it or bind to it either.

>>> public boolean is2D()
>>> public boolean is3D()
>>> public boolean isIdentity()
>> All four of these, determinant, is2D, is3D, and isIdentity can all (in
>> theory) change their value as the Transform is changed, is that right?
>> In that case, they should be read only properties.
> Ah, they probably should. So:

Or should they?  What is the use case for tracking or binding to these? 
  You can already listen for events to know when things change.  These 
are all more for "I want to know how to most quickly handle this 
transform" and are only useful for optimization cases where you still 
need to write the general case.  Since you always need the general case 
and since these attributes are only needed when you actually get to the 
"I'm dealing with the transform values now" code, why do they need to be 

I think properties should be things that are independently specifiable. 
  Values that you calculate from other properties shouldn't necessarily 
be properties themselves (though it might make sense in some cases - you 
should provide a use case to argue for that rather than just have a 
"wouldn't it be great if everything were a property" default approach).

Why don't we make hashcode a property?  ;)

>> with the array as the last parameter, it also means it could be a
>> double... if you wanted to, but I'm not sure it matters.

With regard to using the varargs notation for the setters:

I think that would be interesting and fun.  On the other hand, we might 
be better served by having methods that explicitly take the N parameters 
since we then avoid unnecessary object creation.  Also, these methods do 
not take an arbitrary number of doubles, they take a very explicit 
number of doubles based on the matrix type they are considering so the 
flexibility of the varargs notation is a little overkill when it is 
really just a lower performing way to allow inline argument list syntax.

> First, this is not only issue of the constructor, but of all the methods
> that accept the array of doubles. I was thinking about the order too. I
> chose this one because the beginIndex is insignificant and in a vast
> majority of cases it will be 0, so it seemed strange to have it before
> the actual important data. Also all the methods where the type is first
> are kind of getters, you just pass in what you want to get, whereas to
> the kind of setters you pass the data and than tell how to interpret
> them, so it is not really inconsistent. So your order takes a bit of
> peace from my heart, but I don't insist on the proposed order. Any other
> opinions?

Unfortunately I don't have a strong opinion there either, but if 
potential varargs usage is one of the key reasons for moving the array 
to the end, then I think I've given some good counter-reasons above...


More information about the openjfx-dev mailing list