org.eclipse.swt.graphics.Transform.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.swt.graphics.Transform.java

Source

/*******************************************************************************
 * Copyright (c) 2015 EclipseSource and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    EclipseSource - initial API and implementation
 ******************************************************************************/
package org.eclipse.swt.graphics;

import java.util.Arrays;

import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;

/**
 * Instances of this class represent transformation matrices for
 * points expressed as (x, y) pairs of floating point numbers.
 * <p>
 * Application code must explicitly invoke the <code>Transform.dispose()</code>
 * method to release the operating system resources managed by each instance
 * when those instances are no longer required.
 * </p>
 *
 * @since 3.1
 */
public class Transform extends Resource {

    private final static float[] IDENTITY_MATRIX = { 1, 0, 0, 1, 0, 0 };

    private float[] elements;

    /**
     * Constructs a new identity Transform.
     * <p>
     * This operation requires the operating system's advanced
     * graphics subsystem which may not be available on some
     * platforms.
     * </p>
     *
     * @param device the device on which to allocate the Transform
     *
     * @exception IllegalArgumentException <ul>
     *    <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
     * </ul>
     *
     * @see #dispose()
     */
    public Transform(Device device) {
        this(device, IDENTITY_MATRIX);
    }

    /**
     * Constructs a new Transform given an array of elements that represent the matrix that describes
     * the transformation.
     * <p>
     * This operation requires the operating system's advanced graphics subsystem which may not be
     * available on some platforms.
     * </p>
     *
     * @param device the device on which to allocate the Transform
     * @param elements an array of floats that describe the transformation matrix
     * @exception IllegalArgumentException
     *              <ul>
     *              <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device, or the
     *              elements array is null</li>
     *              <li>ERROR_INVALID_ARGUMENT - if the elements array is too small to hold the matrix
     *              values</li>
     *              </ul>
     * @see #dispose()
     */
    public Transform(Device device, float[] elements) {
        this(device, checkTransform(elements)[0], elements[1], elements[2], elements[3], elements[4], elements[5]);
    }

    /**
     * Constructs a new Transform given all of the elements that represent the matrix that describes
     * the transformation.
     * <p>
     * This operation requires the operating system's advanced graphics subsystem which may not be
     * available on some platforms.
     * </p>
     *
     * @param device the device on which to allocate the Transform
     * @param m11 the first element of the first row of the matrix
     * @param m12 the second element of the first row of the matrix
     * @param m21 the first element of the second row of the matrix
     * @param m22 the second element of the second row of the matrix
     * @param dx the third element of the first row of the matrix
     * @param dy the third element of the second row of the matrix
     * @exception IllegalArgumentException
     *              <ul>
     *              <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
     *              </ul>
     * @see #dispose()
     */
    public Transform(Device device, float m11, float m12, float m21, float m22, float dx, float dy) {
        super(device);
        elements = new float[] { m11, m12, m21, m22, dx, dy };
    }

    static float[] checkTransform(float[] elements) {
        if (elements == null) {
            SWT.error(SWT.ERROR_NULL_ARGUMENT);
        }
        if (elements.length < 6) {
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        }
        return elements;
    }

    @Override
    void destroy() {
        elements = null;
    }

    /**
     * Fills the parameter with the values of the transformation matrix that the receiver represents,
     * in the order {m11, m12, m21, m22, dx, dy}.
     *
     * @param elements array to hold the matrix values
     * @exception SWTException
     *              <ul>
     *              <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
     *              </ul>
     * @exception IllegalArgumentException
     *              <ul>
     *              <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
     *              <li>ERROR_INVALID_ARGUMENT - if the parameter is too small to hold the matrix
     *              values</li>
     *              </ul>
     */
    public void getElements(float[] elements) {
        if (isDisposed()) {
            SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
        }
        if (elements == null) {
            SWT.error(SWT.ERROR_NULL_ARGUMENT);
        }
        if (elements.length < 6) {
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        }
        System.arraycopy(this.elements, 0, elements, 0, 6);
    }

    /**
     * Modifies the receiver to represent a new transformation given all of the elements that
     * represent the matrix that describes that transformation.
     *
     * @param m11 the first element of the first row of the matrix
     * @param m12 the second element of the first row of the matrix
     * @param m21 the first element of the second row of the matrix
     * @param m22 the second element of the second row of the matrix
     * @param dx the third element of the first row of the matrix
     * @param dy the third element of the second row of the matrix
     * @exception SWTException
     *              <ul>
     *              <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
     *              </ul>
     */
    public void setElements(float m11, float m12, float m21, float m22, float dx, float dy) {
        if (isDisposed()) {
            SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
        }
        elements = new float[] { m11, m12, m21, m22, dx, dy };
    }

    /**
     * Modifies the receiver such that the matrix it represents becomes the identity matrix.
     *
     * @exception SWTException
     *              <ul>
     *              <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
     *              </ul>
     */
    public void identity() {
        if (isDisposed()) {
            SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
        }
        System.arraycopy(IDENTITY_MATRIX, 0, elements, 0, 6);
    }

    /**
     * Returns <code>true</code> if the Transform represents the identity matrix and false otherwise.
     *
     * @return <code>true</code> if the receiver is an identity Transform, and <code>false</code>
     *         otherwise
     */
    public boolean isIdentity() {
        if (isDisposed()) {
            SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
        }
        return Arrays.equals(elements, IDENTITY_MATRIX);
    }

    /**
     * Modifies the receiver such that the matrix it represents becomes the mathematical inverse of
     * the matrix it previously represented.
     *
     * @exception SWTException
     *              <ul>
     *              <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
     *              <li>ERROR_CANNOT_INVERT_MATRIX - if the matrix is not invertible</li>
     *              </ul>
     */
    public void invert() {
        if (isDisposed()) {
            SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
        }
        float d = elements[0] * elements[3] - elements[1] * elements[2];
        elements = new float[] { elements[3] / d, -elements[1] / d, -elements[2] / d, elements[0] / d,
                (elements[2] * elements[5] - elements[4] * elements[3]) / d,
                (elements[4] * elements[1] - elements[5] * elements[0]) / d };
    }

    /**
     * Modifies the receiver such that the matrix it represents becomes the the result of multiplying
     * the matrix it previously represented by the argument.
     *
     * @param matrix the matrix to multiply the receiver by
     * @exception SWTException
     *              <ul>
     *              <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
     *              </ul>
     * @exception IllegalArgumentException
     *              <ul>
     *              <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
     *              <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
     *              </ul>
     */
    public void multiply(Transform matrix) {
        if (isDisposed()) {
            SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
        }
        if (matrix == null) {
            SWT.error(SWT.ERROR_NULL_ARGUMENT);
        }
        if (matrix.isDisposed()) {
            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
        }
        float[] elements = new float[6];
        matrix.getElements(elements);
        multiply(elements[0], elements[1], elements[2], elements[3], elements[4], elements[5]);
    }

    /**
     * Modifies the receiver so that it represents a transformation that is equivalent to its previous
     * transformation translated by (offsetX, offsetY).
     *
     * @param offsetX the distance to translate in the X direction
     * @param offsetY the distance to translate in the Y direction
     * @exception SWTException
     *              <ul>
     *              <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
     *              </ul>
     */
    public void translate(float offsetX, float offsetY) {
        if (isDisposed()) {
            SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
        }
        multiply(1, 0, 0, 1, offsetX, offsetY);
    }

    /**
     * Modifies the receiver so that it represents a transformation that is equivalent to its previous
     * transformation scaled by (scaleX, scaleY).
     *
     * @param scaleX the amount to scale in the X direction
     * @param scaleY the amount to scale in the Y direction
     * @exception SWTException
     *              <ul>
     *              <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
     *              </ul>
     */
    public void scale(float scaleX, float scaleY) {
        if (isDisposed()) {
            SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
        }
        multiply(scaleX, 0, 0, scaleY, 0, 0);
    }

    /**
     * Modifies the receiver so that it represents a transformation that is equivalent to its previous
     * transformation rotated by the specified angle. The angle is specified in degrees and for the
     * identity transform 0 degrees is at the 3 o'clock position. A positive value indicates a
     * clockwise rotation while a negative value indicates a counter-clockwise rotation.
     *
     * @param angle the angle to rotate the transformation by
     * @exception SWTException
     *              <ul>
     *              <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
     *              </ul>
     */
    public void rotate(float angle) {
        if (isDisposed()) {
            SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
        }
        double radians = Math.toRadians(angle);
        float m11 = (float) Math.cos(radians);
        float m12 = (float) Math.sin(radians);
        float m21 = -(float) Math.sin(radians);
        float m22 = (float) Math.cos(radians);
        multiply(m11, m12, m21, m22, 0, 0);
    }

    /**
     * Modifies the receiver so that it represents a transformation that is equivalent to its previous
     * transformation sheared by (shearX, shearY).
     *
     * @param shearX the shear factor in the X direction
     * @param shearY the shear factor in the Y direction
     * @exception SWTException
     *              <ul>
     *              <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
     *              </ul>
     */
    public void shear(float shearX, float shearY) {
        if (isDisposed()) {
            SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
        }
        multiply(1, shearY, shearX, 1, 0, 0);
    }

    /**
     * Given an array containing points described by alternating x and y values, modify that array
     * such that each point has been replaced with the result of applying the transformation
     * represented by the receiver to that point.
     *
     * @param pointArray an array of alternating x and y values to be transformed
     * @exception IllegalArgumentException
     *              <ul>
     *              <li>ERROR_NULL_ARGUMENT - if the point array is null</li>
     *              </ul>
     * @exception SWTException
     *              <ul>
     *              <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
     *              </ul>
     */
    public void transform(float[] pointArray) {
        if (isDisposed()) {
            SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
        }
        if (pointArray == null) {
            SWT.error(SWT.ERROR_NULL_ARGUMENT);
        }
        for (int i = 1; i < pointArray.length; i += 2) {
            float dx = pointArray[i - 1];
            float dy = pointArray[i];
            pointArray[i - 1] = elements[0] * dx + elements[2] * dy + elements[4];
            pointArray[i] = elements[1] * dx + elements[3] * dy + elements[5];
        }
    }

    /**
     * Returns a string containing a concise, human-readable description of the receiver.
     *
     * @return a string representation of the receiver
     */
    @Override
    public String toString() {
        if (isDisposed()) {
            return "Transform {*DISPOSED*}";
        }
        return "Transform {" + elements[0] + "," + elements[1] + "," + elements[2] + "," + elements[3] + ","
                + elements[4] + "," + elements[5] + "}";
    }

    private void multiply(float m11, float m12, float m21, float m22, float dx, float dy) {
        elements = new float[] { elements[0] * m11 + elements[2] * m12, elements[1] * m11 + elements[3] * m12,
                elements[0] * m21 + elements[2] * m22, elements[1] * m21 + elements[3] * m22,
                elements[0] * dx + elements[2] * dy + elements[4],
                elements[1] * dx + elements[3] * dy + elements[5] };
    }

}