# Affine transforms - matrix algebra

Pavel Safrata pavel.safrata at oracle.com
Tue Aug 14 00:41:21 PDT 2012

```Hi Jim,

On 14.8.2012 1:49, Jim Graham wrote:
> Hi Pavel,
>
> Thanks for the revisions!
>
> I am working on the assumption that all of the following are useful
> and (not sure what word to use) ?sensical? operations:
>
> p + v = p
> v + p = p
> v + v = v
>
> p - p = v
> p - v = p
> v - v = v  (?)
>
> And some which don't really make much sense:
>
> p + p = ?
> v - p = ?
>
> On 8/13/2012 7:48 AM, Pavel Safrata wrote:
>> // Creates a point with distances from origin added (adds two vectors)
>
> or point+vector is also a common operation, no?
>
>> public Point3D subtract(Point3D point)
>> // Creates a point with the given point's distances from origin
>> subtracted
>> // (subtracts two vectors)
>
> It is also viable to subtract a vector from a point, no?

I agree with all of the above. As the proposal doesn't distinguish point
from vector, it is only a matter of documentation.

>
>> ? should the above three methods be named getSomething to stress that
>> the operation doesn't modify the object?
>
> getSubtractedSomething?
>
> I can't think of any really good name using "get" there, anyone else?
>
> In my taxonomy "getFoo" doesn't make any guarantees about the
> uniqueness of foo, so if we plan to return "this" if the argument is
> an identity operand, then getFoo() makes sense, but since Point3D is
> modifiable I don't think we should have that philosophy.
>
> "createFoo" always promises a new object.

As Richard said we shouldn't use the 'get' prefix here.

>
> Also, in many cases we provide:
>
> Foo Foo.operate(Foo_operand, Foo_result_container)
>
> so that code can reuse objects.  I think that makes sense here as well.

I generally agree but Point3D is immutable so it's not possible here.

>
>> public Point3D getCenter(Point3D)
>> // Gets center between the two points
>
> Or "midpoint"?

Sounds good!

>
>> public double getAngle(Point3D)
>> // Gets angle between the two points when observed from the origin
>> // (angle between vectors)
>
> What about the static variant "getAngle(po, p1, p2)"?

Again the immutable point..

>
>> public double getLength()
>> // Gets distance from the origin (lenght of a vector)
>> ? should it be named getDistance() not to look that weird on Point?
>
> getMagnitude?  I've heard that a vector has "direction and magnitude"
> and this would be measuring that property (though I'm not sure we want
> to call the angle method "getDirection"?)

Ok, let it be magnitude().

>
>> public Point3D crossProduct(Point3D point)
>> public double dotProduct(Point3D point)
>> // Compute product of the two vectors (I don't think we can reasonably
>> document those as point operations)
>
> If we document that a Point3D can be considered either as a point with
> its location specified in 3-space as well as a vector with its
> direction and magnitude specified by its relative location from the
> origin, then we can document any vector-oriented operations as "the
> vector represented by this Point3D object"...

Yes. I will do that. I just tried to find a point-based explanation for
the operations to ensure the API is as meaningful as possible.

>
>> public Point3D transform(Point3D point)
>> // Transforms the point
>> public Point2D transform(Point2D point)
>> // throws IllegalArgument for 3D transform
>
> I think we discussed it before, but do we want "void transform(p1,
> presult)"?

I don't think we discussed this before, but you know by now, point is
immutable :-)

>
>> public Bounds transform(Bounds bounds)
>> // Transforms the bounds
>> public void transform2D(double[] srcPts, int srcOffset, double[] dstPts,
>> int dstOffset, int numPts)
>> // similar to J2D
>> public void transform3D(double[] srcPts, int srcOffset, double[] dstPts,
>> int dstOffset, int numPts)
>> // similar to the above but with tree coordinates per point
>
> Perhaps call them "transformNDpoints" to disambiguate from "transform
> these points as if this were a 2D or 3D transform"?

Good idea!

>
>> public double getDeterminant()
>> public boolean is2D()
>> public boolean is3D()
>
> isIdentity()?

Why not.

>
> Also, I'm assuming that "is2D()" returns based on the current elements
> of the transform's matrix and not the "class type"?

Yes.

>
>> public double[] toArray(MatrixType type)
>> // Returns flattened matrix specified by type
>> public double[] toArray(MatrixType type, double[] array)
>> // Similar to the above, just uses the passed array if it is big enough
>> public double[] getRow(MatrixType type, int row)
>> public double[] getRow(MatrixType type, int row, double[] array)
>> public double[] getColumn(MatrixType type, int column)
>> public double[] getColumn(MatrixType type, int column, double[] array)
>> // Similar to toAarray returning the particular tuples
>> // throw IndexOutOfBounds if index out of the range specified by type
>
> Would there be a "getMatrixType"?

The transform has no matrix type. You can request any matrix type from
any transform.

>
>> // Support for the transform changed event:
>> // Transform will implement EventTarget interface
>> protected void transformChanged()
>> // for the subclasses to call when the transform changes
>> public <T extends Event> void addEventFilter(EventType<T> eventType,
>> EventHandler<? super T> eventHandler)
>> public <T extends Event> void removeEventFilter(EventType<T> eventType,
>> EventHandler<? super T> eventHandler)
>> public <T extends Event> void addEventHandler(final EventType<T>
>> eventType,
>> final EventHandler<? super T> eventHandler)
>> public <T extends Event> void removeEventHandler(EventType<T> eventType,
>> EventHandler<? super T> eventHandler)
>> public final void setOnTransformChanged(EventHandler<? super
>> TransformChangedEvent> value)
>
> I hope someone involved more in FX events can review this.

I discussed this with Lubo who is our greatest event expert :-)

>
>> public void appendScale(double sx, double sy, double pivotX, double
>> pivotY)
>
> I wish we had called it "anchor".  "Pivot" is a bizarre name for the
> origin of a scale - in retrospect.
>
>> 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 appendRotation(double theta,
>> double pivotX, double pivotY, double pivotZ,
>> Point3D axis)
>> public void appendShear(double shx, double shy)
>> public void appendShear(double shx, double shy, double pivotX, double
>> pivotY)
>
> The appendRotation(... Point3D axis) stands out.  Should we have
> variants for all of the pivotXYZ methods that take a Point2D/3D?

Pivot is always represented as three doubles, even with rotation.
Point3D can be used only for the axis (which is unique property to
rotation) and the reason is that for the orthogonal rotations you can
use Rotate's X_AXIS, Y_AXIS and Z_AXIS.

Thanks,
Pavel

>
>             ...jim

```