Affine transforms - matrix algebra

Jim Graham james.graham at
Tue Jul 17 11:20:04 PDT 2012

I think we disagree as to what "translate then scale" means.  To me, it 
is ambiguously referring to two totally different outcomes which depend 
on your perspective as "translate me and then scale me" or "translate 
that thing and then scale it".  There is no "right and wrong" and any 
discussion that uses those words is simply burying their head in their 
own default interpretation and ignoring that people see things differently.

Similarly with append and prepend - they do not remove the ambiguity, 
they simply provide a name for it.  If you think the "translate" and 
"scale" names from 2D worked opposite from your default view (which you 
may not realize was just one of 2 possible views, there is no right or 
wrong), then append does not explicitly resolve the issue - it is just 
as ambiguous as your existing "my view was right and someone else got it 
wrong" mistaken impression.

The only way that "append" can be interpreted unambiguously from the 
current FX context is if it works as if one appended some Transform 
nodes to the list in Node's "getTransforms()" List<Transform>, but even 
that may not match another engineer's default interpretation.  That is 
the only definition we currently have of append in the current set of 
APIs.  If your append* methods will work differently than that 
interpretation then you are creating an inconsistency.  (Note that 
ObservableList.add is consistent with List.add which defines the 
operation as "append" so the order implied by that term has already been 
spoken for.)

Note that Java2D didn't invent its interpretation of what it means to 
"translate(), then scale()" - we are doing the same thing that 
PostScript did which predates any of this by a few years.  We also 
happen to be doing the same thing that the latest transform standard for 
the web is doing - HTML5 Canvas/GraphicsContext...


On 7/17/2012 2:28 AM, Martin Desruisseaux wrote:
> Hello Jim
> Just a my 2 cents:
> Le 17/07/12 06:08, Jim Graham a écrit :
>> - We already have GraphicsContext in 2.2 that has "translate, scale,
>> etc." I would hope that the "appendFoo()" methods would work like
>> those, but I have the sneaky suspicion that I read in the discussion
>> that actually the prepend methods are closer to those. Consider how a
>> developer that was used to "I scaled then I translated" would view
>> append/prepend? That sounds to me like the scale happened and then the
>> translate was "appended to the list of operations as if one called it
>> after scale in some Canvas code". Also, append should probably reflect
>> what happens when you get the list of Transform objects from a Node
>> and then append some new Transform objects to the end of that list.
>> Prepend should match what happens when you place new Transform objects
>> at the head of that same Node.getTransforms() list.
> I think that this operation order matches the proposal. In the proposal,
> "append" and "prepend" are from an operation order point of views rather
> than matrix multiplication order point of view.
> The Java2D methods have the behaviour of "prepend" in the proposal. In
> Java2D, AffineTransform.scale(...) followed by
> AffineTransform.translate(...) mean "first translate, then scale" from
> an operation order point of view.
> Nevertheless, I would have been comfortable with keeping the "translate"
> and "scale" method names with Java2D behaviour, if those names weren't
> already used by the static methods in the parent class... The "append"
> and "prepend" prefixes were one workaround we found; an earlier proposal
> was using longer method names...
>> - append might mean a matrix operation with the math going one way,
>> but it might also mean "then after you step into that coordinate
>> system, you do this operation from that perspective", and it might
>> also mean "after you move everything around and you are staring at the
>> transformed objects from outside (i.e. the point of view of the
>> universe), you then move it again like this" and all of those will
>> result in different math.
> I think that the above "coordinate system" perspective matches the
> current proposal.
>> - 2x3, 3x4, etc - I would make those explicit in the method name
>> rather than side effected from the array length
> The current proposal uses an enum. Would many methods be preferable to
> an enum in this case?
>> - what about getRow(row, array) and getColumn(col, array) which can be
>> combined with vector methods to do fast custom matrix operations?
> At this point, given the increasing amount of methods and the enum, I
> wonder if we should replace all those variants by a single method:
> double[] getSubMatrix(int firstRow, int firstColumn, int numRows, int
> numColumns, double[] array);
> This single method would provide the functionalities of getRow,
> getColumn, getMatrix with enum 2x3, 3x4 and 4x4 (we lost 3x3, but it it
> probably not a big deal). The enum would not be needed anymore.
>> - what about classification methods so they can special case "uniform
>> scaling", "unrotated", "translation-only", etc. matrix cases?
> Do you mean something similar to AffineTransform.getType() in Java2D? On
> my side, I didn't found lot of situations were I used this method.
> However in the JavaFX world, maybe an alternative could be some method
> returning the most specific subclass of Transform that can represent the
> Affine. For example if the Affine have only translation terms, then that
> method would return an instance of Translate. An "instanceof" check
> would allow the user to get the classification.
> Martin

More information about the openjfx-dev mailing list