# Affine transforms - matrix algebra

Jim Graham james.graham at oracle.com
Mon Jul 23 15:02:25 PDT 2012

```On 7/23/2012 5:01 AM, Pavel Safrata wrote:
>> I think that the following one is very important for performance reasons:
>>
>> void transform(double[] srcPts, int srcOffset, double[] dstPts, int
>> dstOffset, int numPts);
>>
>> with semantic identical to the one currently in the Java2D
>> AffineTransform.
>
> Unlike in J2D our Pts will have three coordinates, right? Or do we want
> transform2D and transform3D?

I'm fine with double-only for now given the rest of the FX APIs.

As far as whether the array is 2D or 3D, I'll leave that up to the
engineers who are planning to use it.  Would 3D-only be confusing to
them?  I could live with it either way, but it may be a culture shock
coming from J2D.

> To me this sounds a bit frightening. I may be wrong but I believe that
> the "ulps" are there to deal with representability of certain numbers in
> floating-point types but not with different math engines producing
> different results - I believe the results may be up to one ulp wrong but
> are reliably stable among all platforms. I'm a bit afraid that providing
> unstable results would violate at least some unwritten conventions. But
> I'm not an expert here, I might be wrong.

ulp is a unit representing the minimal difference in values.  It's
simply the only way you can realistically state errors in a floating
point world given its sliding scale of how many bits past the decimal
point it offers.

Stating the error should be within 1E-N is wrong because the nearest
representable value may not be within that error bound from the true
result depending on the magnitude of the result.  You might be able to
guarantee that if the result is around 10, but not if the result is
around a billion since numbers of that magnitude have fewer bits to
devote to the fractional part.  So errors are typically stated as
multiples of ulp.  So, saying "within 2^N ulp is the same as saying that
the lowest N bits might be wrong".

>>> Rename the MatrixArrayType constants to MAT_2D_3x2, MAT_2D_3x3,
>>> MAT_3D_3x4, MAT_3D_4x4, do you agree?
>> I don't really have better idea at this time... I wonder if we could
>> find a way to merge with the VAT_* constants...
>
> We may use MAT for the getRow/getCol - it would specify from what matrix
> the col/row will be taken (each pair of values would provide similar
> behavior except for one of them allowing to read the last line).

Also, I don't think you can accurately determine which values to read
without the full MAT since the 3rd row (index == 2?) of a matrix with Z
is different from the same index row of a matrix that doesn't have Z.
So, I think it makes sense to use the MAT types for both methods (the
matrix and the row/col methods).

With respect to methods that don't take a MAT type - I think we should
simply say that the default is MAT_4x4 rather than infer it from the
size of the array - that is cleaner and avoids mistakes where they
forgot how big their array was (as in, they allocated a temp array and
left it around for future use and some other programmer came in and
decided that the array should be bigger without noticing that it affects
the values that the former code would get)...

...jim
```