# Affine transforms - matrix algebra

Pavel Safrata pavel.safrata at oracle.com
Mon Jul 16 12:49:35 PDT 2012

```Hello,
Ok,  Richard, thanks.

I have one more question that I asked earlier but that has not been
addressed in this discussion: do we want to use Point3D for rotation
axis? It would be consistent with Rotate and it would be convenient to
use the Rotate.*_AXIS constants. In the other hand, it would often force
users to create unnecessary Point3D instances. Or do we want both?
Currently it means
public void appendRotation(double theta,
double pivotX, double pivotY, double pivotZ,
double axisX, double axisY, double axisZ)
vs.
public void appendRotation(double theta,
double pivotX, double pivotY, double pivotZ,
Point3D axis)
and similarly for prepend.

Here is once more the complete proposal with a few minor issues fixed
(added 3x3 matrix handling, fixed row/col parameter order, fixed
pivot/axis parameter order):

On Transform class:
public Transform createConcatenation(Transform transform)
// Creates new concatenated transform that is equivalent to
// this transform applied first and the given transform second
// Means multiplication on the left by the given transform
public Transform createInverse() throws NoninvertibleTransformException
// Creates a negated transform
public double get(int row, int col)
// Convenience getter for the individual elements
// Accepts both params in range 0..3, throws IllegalArgument
otherwise
public double[] toArray(MatrixArrayType type)
// Transform.MatrixArrayType is an enum { MAT_2x3, MAT_3x3,
MAT_3x4, MAT_4x4 }
// Returns array of length 6, 9, 12, 16, respectively
// Throws IllegalArgument if 2x3 or 3x3 is requested for a 3D
transform
public double[] toArray(MatrixArrayType type, double[] array)
// Similar to the above, just uses the passed array if it is
big enough
public Transform clone()
// Of course Transform implementing Cloneable

// in subclasses the methods returning Transform will be overridden
and will return more specific types where possible.

On Affine class:

Constructors:
public Affine(Transform transform)
public Affine(double mxx, double mxy, double tx,
double myx, double myy, double ty)
public Affine(double mxx, double mxy, double mxz, double tx,
double myx, double myy, double myz, double ty,
double mzx, double mzy, double mzz, double tz)
public Affine(double[] matrix)
// accepts arrays of length 6, 9, 12 and 16.
// In case of 9 members the last three numbers must be 0, 0, 1
// In case of 16 members the last four numbers must be 0, 0, 0, 1
// throws IllegalArgument if the above conditions are not met

Setters of the entire matrix:
public void setToTransform(Transform t)
public void setToTransform(double mxx, double mxy, double tx,
double myx, double myy, double ty)
public void setToTransform(double mxx, double mxy, double mxz,
double mxt,
double myx, double myy, double myz,
double myt,
double mzx, double mzy, double mzz,
double mzt)
public void setToTransform(double[] matrix)
// the same acceptance criteria as the constructor
public void setToIdentity()

Operations on the matrix (modifying it in place):
public void invert() throws NoninvertibleTransformException
public void append(Transform t)
public void append(double mxx, double mxy, double tx,
double myx, double myy, double ty)
public void append(double Txx, double Txy, double Txz, double Txt,
double Tyx, double Tyy, double Tyz, double Tyt,
double Tzx, double Tzy, double Tzz, double Tzt)
public void append(double[] matrix)

public void appendTranslation(double tx, double ty)
public void appendTranslation(double tx, double ty, double tz)
public void appendScale(double sx, double sy)
public void appendScale(double sx, double sy, double pivotX, double
pivotY)
public void appendScale(double sx, double sy, double sz)
public void appendScale(double sx, double sy, double sz,
double pivotX, double pivotY, double pivotZ)
public void appendRotation(double theta)
public void appendRotation(double theta, double pivotX, double pivotY)
public void appendRotation(double theta,
double pivotX, double pivotY, double pivotZ,
double axisX, double axisY, double axisZ)
public void appendShear(double shx, double shy)
public void appendShear(double shx, double shy, double pivotX,
double pivotY)

// "append" means "add the transformation after the existing one", so
// "append" means multiply this matrix on the left by the given matrix

public void prepend* // 15 methods
// Every append* method has its prepend* companion,
// adding the transformation before the existing one,
// multiplying on the right

Other methods:
public void set(int row, int col, double value)
// convenience setter for the individual elements
// accepts row and col in range 0..3
// allows to set the last row only to 0, 0, 0, 1
// throws IllegalArgument if the above conditions are not met

public double getDeterminant()

Thanks,
Pavel

On 16.7.2012 20:25, Richard Bair wrote:
> Hi Pavel,
>
> Before approving I want Jim Graham to have a look. He's been on vacation, I think he either gets back today or next week.
>
> Thanks!
> Richard
>
> On Jul 16, 2012, at 4:37 AM, Pavel Safrata wrote:
>
>> Hi Kirill,
>> it is just for convenience. The point is that if you have algorithms or other libraries that use the fourth row, you can work with the array right away.
>> Regards,
>> Pavel
>>
>> On 16.7.2012 13:28, Kirill.Prazdnikov wrote:
>>> Hi Pavel,
>>>
>>>>     public Affine(double[] matrix)
>>>>         // accepts arrays of length 6, 12 and 16.
>>>>         // In case of 16 members the last four numbers must be 0, 0, 0, 1
>>>>         // throws IllegalArgument if the above conditions are not met
>>> What is the point of setting 4x4 matrix of the last row must be 0,0,0,1 ?
>>> Should we remove 4x4 case at all ?
>>>
>>> Thanks
>>>
>>>
>>

```