All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vividsolutions.jts.geom.util.AffineTransformation Maven / Gradle / Ivy

There is a newer version: 0.1.4
Show newest version
/*
* The JTS Topology Suite is a collection of Java classes that
* implement the fundamental operations required to validate a given
* geo-spatial data set to a known topological specification.
*
* Copyright (C) 2001 Vivid Solutions
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* For more information, contact:
*
*     Vivid Solutions
*     Suite #1A
*     2328 Government Street
*     Victoria BC  V8T 5G5
*     Canada
*
*     (250)385-6040
*     www.vividsolutions.com
*/

package com.vividsolutions.jts.geom.util;

import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.util.*;
/**
 * Represents an affine transformation on the 2D Cartesian plane. 
 * It can be used to transform a {@link Coordinate} or {@link Geometry}.
 * An affine transformation is a mapping of the 2D plane into itself
 * via a series of transformations of the following basic types:
 * 
    *
  • reflection (through a line) *
  • rotation (around the origin) *
  • scaling (relative to the origin) *
  • shearing (in both the X and Y directions) *
  • translation *
* In general, affine transformations preserve straightness and parallel lines, * but do not preserve distance or shape. *

* An affine transformation can be represented by a 3x3 * matrix in the following form: *

 * T = | m00 m01 m02 |
 *     | m10 m11 m12 |
 *     |  0   0   1  |
 * 
* A coordinate P = (x, y) can be transformed to a new coordinate P' = (x', y') * by representing it as a 3x1 matrix and using matrix multiplication to compute: *
 * | x' |  = T x | x |
 * | y' |        | y |
 * | 1  |        | 1 |
 * 
*

Transformation Composition

* Affine transformations can be composed using the {@link #compose} method. * Composition is computed via multiplication of the * transformation matrices, and is defined as: *
 * A.compose(B) = TB x TA
 * 
* This produces a transformation whose effect is that of A followed by B. * The methods {@link #reflect}, {@link #rotate}, * {@link #scale}, {@link #shear}, and {@link #translate} * have the effect of composing a transformation of that type with * the transformation they are invoked on. *

* The composition of transformations is in general not commutative. * *

Transformation Inversion

* Affine transformations may be invertible or non-invertible. * If a transformation is invertible, then there exists * an inverse transformation which when composed produces * the identity transformation. * The {@link #getInverse} method * computes the inverse of a transformation, if one exists. * * @author Martin Davis * */ public class AffineTransformation implements Cloneable, CoordinateSequenceFilter { /** * Creates a transformation for a reflection about the * line (x0,y0) - (x1,y1). * * @param x0 the x-ordinate of a point on the reflection line * @param y0 the y-ordinate of a point on the reflection line * @param x1 the x-ordinate of a another point on the reflection line * @param y1 the y-ordinate of a another point on the reflection line * @return a transformation for the reflection */ public static AffineTransformation reflectionInstance(double x0, double y0, double x1, double y1) { AffineTransformation trans = new AffineTransformation(); trans.setToReflection(x0, y0, x1, y1); return trans; } /** * Creates a transformation for a reflection about the * line (0,0) - (x,y). * * @param x the x-ordinate of a point on the reflection line * @param y the y-ordinate of a point on the reflection line * @return a transformation for the reflection */ public static AffineTransformation reflectionInstance(double x, double y) { AffineTransformation trans = new AffineTransformation(); trans.setToReflection(x, y); return trans; } /** * Creates a transformation for a rotation * about the origin * by an angle theta. * Positive angles correspond to a rotation * in the counter-clockwise direction. * * @param theta the rotation angle, in radians * @return a transformation for the rotation */ public static AffineTransformation rotationInstance(double theta) { return rotationInstance(Math.sin(theta), Math.cos(theta)); } /** * Creates a transformation for a rotation * by an angle theta, * specified by the sine and cosine of the angle. * This allows providing exact values for sin(theta) and cos(theta) * for the common case of rotations of multiples of quarter-circles. * * @param sinTheta the sine of the rotation angle * @param cosTheta the cosine of the rotation angle * @return a transformation for the rotation */ public static AffineTransformation rotationInstance(double sinTheta, double cosTheta) { AffineTransformation trans = new AffineTransformation(); trans.setToRotation(sinTheta, cosTheta); return trans; } /** * Creates a transformation for a rotation * about the point (x,y) by an angle theta. * Positive angles correspond to a rotation * in the counter-clockwise direction. * * @param theta the rotation angle, in radians * @param x the x-ordinate of the rotation point * @param y the y-ordinate of the rotation point * @return a transformation for the rotation */ public static AffineTransformation rotationInstance(double theta, double x, double y) { return rotationInstance(Math.sin(theta), Math.cos(theta), x, y); } /** * Creates a transformation for a rotation * about the point (x,y) by an angle theta, * specified by the sine and cosine of the angle. * This allows providing exact values for sin(theta) and cos(theta) * for the common case of rotations of multiples of quarter-circles. * * @param sinTheta the sine of the rotation angle * @param cosTheta the cosine of the rotation angle * @param x the x-ordinate of the rotation point * @param y the y-ordinate of the rotation point * @return a transformation for the rotation */ public static AffineTransformation rotationInstance(double sinTheta, double cosTheta, double x, double y) { AffineTransformation trans = new AffineTransformation(); trans.setToRotation(sinTheta, cosTheta, x, y); return trans; } /** * Creates a transformation for a scaling relative to the origin. * * @param xScale the value to scale by in the x direction * @param yScale the value to scale by in the y direction * @return a transformation for the scaling */ public static AffineTransformation scaleInstance(double xScale, double yScale) { AffineTransformation trans = new AffineTransformation(); trans.setToScale(xScale, yScale); return trans; } /** * Creates a transformation for a scaling relative to the point (x,y). * * @param xScale the value to scale by in the x direction * @param yScale the value to scale by in the y direction * @param x the x-ordinate of the point to scale around * @param y the y-ordinate of the point to scale around * @return a transformation for the scaling */ public static AffineTransformation scaleInstance(double xScale, double yScale, double x, double y) { AffineTransformation trans = new AffineTransformation(); trans.translate(-x, -y); trans.scale(xScale, yScale); trans.translate(x, y); return trans; } /** * Creates a transformation for a shear. * * @param xShear the value to shear by in the x direction * @param yShear the value to shear by in the y direction * @return a tranformation for the shear */ public static AffineTransformation shearInstance(double xShear, double yShear) { AffineTransformation trans = new AffineTransformation(); trans.setToShear(xShear, yShear); return trans; } /** * Creates a transformation for a translation. * * @param x the value to translate by in the x direction * @param y the value to translate by in the y direction * @return a tranformation for the translation */ public static AffineTransformation translationInstance(double x, double y) { AffineTransformation trans = new AffineTransformation(); trans.setToTranslation(x, y); return trans; } // affine matrix entries // (bottom row is always [ 0 0 1 ]) private double m00; private double m01; private double m02; private double m10; private double m11; private double m12; /** * Constructs a new identity transformation */ public AffineTransformation() { setToIdentity(); } /** * Constructs a new transformation whose * matrix has the specified values. * * @param matrix an array containing the 6 values { m00, m01, m02, m10, m11, m12 } * @throws NullPointerException if matrix is null * @throws ArrayIndexOutOfBoundsException if matrix is too small */ public AffineTransformation(double[] matrix) { m00 = matrix[0]; m01 = matrix[1]; m02 = matrix[2]; m10 = matrix[3]; m11 = matrix[4]; m12 = matrix[5]; } /** * Constructs a new transformation whose * matrix has the specified values. * * @param m00 the entry for the [0, 0] element in the transformation matrix * @param m01 the entry for the [0, 1] element in the transformation matrix * @param m02 the entry for the [0, 2] element in the transformation matrix * @param m10 the entry for the [1, 0] element in the transformation matrix * @param m11 the entry for the [1, 1] element in the transformation matrix * @param m12 the entry for the [1, 2] element in the transformation matrix */ public AffineTransformation(double m00, double m01, double m02, double m10, double m11, double m12) { setTransformation(m00, m01, m02, m10, m11, m12); } /** * Constructs a transformation which is * a copy of the given one. * * @param trans the transformation to copy */ public AffineTransformation(AffineTransformation trans) { setTransformation(trans); } /** * Constructs a transformation * which maps the given source * points into the given destination points. * * @param src0 source point 0 * @param src1 source point 1 * @param src2 source point 2 * @param dest0 the mapped point for source point 0 * @param dest1 the mapped point for source point 1 * @param dest2 the mapped point for source point 2 * */ public AffineTransformation(Coordinate src0, Coordinate src1, Coordinate src2, Coordinate dest0, Coordinate dest1, Coordinate dest2) { } /** * Sets this transformation to be the identity transformation. * The identity transformation has the matrix: *
   * | 1 0 0 |
   * | 0 1 0 |
   * | 0 0 1 |
   * 
* @return this transformation, with an updated matrix */ public AffineTransformation setToIdentity() { m00 = 1.0; m01 = 0.0; m02 = 0.0; m10 = 0.0; m11 = 1.0; m12 = 0.0; return this; } /** * Sets this transformation's matrix to have the given values. * * @param m00 the entry for the [0, 0] element in the transformation matrix * @param m01 the entry for the [0, 1] element in the transformation matrix * @param m02 the entry for the [0, 2] element in the transformation matrix * @param m10 the entry for the [1, 0] element in the transformation matrix * @param m11 the entry for the [1, 1] element in the transformation matrix * @param m12 the entry for the [1, 2] element in the transformation matrix * @return this transformation, with an updated matrix */ public AffineTransformation setTransformation(double m00, double m01, double m02, double m10, double m11, double m12) { this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m10 = m10; this.m11 = m11; this.m12 = m12; return this; } /** * Sets this transformation to be a copy of the given one * * @param trans a transformation to copy * @return this transformation, with an updated matrix */ public AffineTransformation setTransformation(AffineTransformation trans) { m00 = trans.m00; m01 = trans.m01; m02 = trans.m02; m10 = trans.m10; m11 = trans.m11; m12 = trans.m12; return this; } /** * Gets an array containing the entries * of the transformation matrix. * Only the 6 non-trivial entries are returned, * in the sequence: *
   * m00, m01, m02, m10, m11, m12
   * 
* * @return an array of length 6 */ public double[] getMatrixEntries() { return new double[] { m00, m01, m02, m10, m11, m12 }; } /** * Computes the determinant of the transformation matrix. * The determinant is computed as: *
  * | m00 m01 m02 |
  * | m10 m11 m12 | = m00 * m11 - m01 * m10
  * |  0   0   1  |
  * 
* If the determinant is zero, * the transform is singular (not invertible), * and operations which attempt to compute * an inverse will throw a NoninvertibleTransformException. * @return the determinant of the transformation * @see #getInverse() */ public double getDeterminant() { return m00 * m11 - m01 * m10; } /** * Computes the inverse of this transformation, if one * exists. * The inverse is the transformation which when * composed with this one produces the identity * transformation. * A transformation has an inverse if and only if it * is not singular (i.e. its * determinant is non-zero). * Geometrically, an transformation is non-invertible * if it maps the plane to a line or a point. * If no inverse exists this method * will throw a NoninvertibleTransformationException. *

* The matrix of the inverse is equal to the * inverse of the matrix for the transformation. * It is computed as follows: *

  
   *                 1    
   * inverse(A)  =  ---   x  adjoint(A) 
   *                det 
   *
   *
   *             =   1       |  m11  -m01   m01*m12-m02*m11  |
   *                ---   x  | -m10   m00  -m00*m12+m10*m02  |
   *                det      |  0     0     m00*m11-m10*m01  |
   *
   *
   *
   *             = |  m11/det  -m01/det   m01*m12-m02*m11/det |
   *               | -m10/det   m00/det  -m00*m12+m10*m02/det |
   *               |   0           0          1               |
   *
   * 
* * @return a new inverse transformation * @throws NoninvertibleTransformationException * @see #getDeterminant() */ public AffineTransformation getInverse() throws NoninvertibleTransformationException { double det = getDeterminant(); if (det == 0) throw new NoninvertibleTransformationException("Transformation is non-invertible"); double im00 = m11 / det; double im10 = -m10 / det; double im01 = -m01 / det; double im11 = m00 / det; double im02 = (m01 * m12 - m02 * m11) / det; double im12 = (-m00 * m12 + m10 * m02) / det; return new AffineTransformation(im00, im01, im02, im10, im11, im12); } /** * Explicitly computes the math for a reflection. May not work. * @param x0 the X ordinate of one point on the reflection line * @param y0 the Y ordinate of one point on the reflection line * @param x1 the X ordinate of another point on the reflection line * @param y1 the Y ordinate of another point on the reflection line * @return this transformation, with an updated matrix */ public AffineTransformation setToReflectionBasic(double x0, double y0, double x1, double y1) { if (x0 == x1 && y0 == y1) { throw new IllegalArgumentException("Reflection line points must be distinct"); } double dx = x1 - x0; double dy = y1 - y0; double d = Math.sqrt(dx * dx + dy * dy); double sin = dy / d; double cos = dx / d; double cs2 = 2 * sin * cos; double c2s2 = cos * cos - sin * sin; m00 = c2s2; m01 = cs2; m02 = 0.0; m10 = cs2; m11 = -c2s2; m12 = 0.0; return this; } /** * Sets this transformation to be a reflection * about the line defined by a line (x0,y0) - (x1,y1). * * @param x0 the X ordinate of one point on the reflection line * @param y0 the Y ordinate of one point on the reflection line * @param x1 the X ordinate of another point on the reflection line * @param y1 the Y ordinate of another point on the reflection line * @return this transformation, with an updated matrix */ public AffineTransformation setToReflection(double x0, double y0, double x1, double y1) { if (x0 == x1 && y0 == y1) { throw new IllegalArgumentException("Reflection line points must be distinct"); } // translate line vector to origin setToTranslation(-x0, -y0); // rotate vector to positive x axis direction double dx = x1 - x0; double dy = y1 - y0; double d = Math.sqrt(dx * dx + dy * dy); double sin = dy / d; double cos = dx / d; rotate(-sin, cos); // reflect about the x axis scale(1, -1); // rotate back rotate(sin, cos); // translate back translate(x0, y0); return this; } /** * Sets this transformation to be a reflection * about the line defined by vector (x,y). * The transformation for a reflection * is computed by: *
   * d = sqrt(x2 + y2)  
   * sin = y / d;
   * cos = x / d;
   * 
   * Tref = Trot(sin, cos) x Tscale(1, -1) x Trot(-sin, cos)
* * @param x the x-component of the reflection line vector * @param y the y-component of the reflection line vector * @return this transformation, with an updated matrix */ public AffineTransformation setToReflection(double x, double y) { if (x == 0.0 && y == 0.0) { throw new IllegalArgumentException("Reflection vector must be non-zero"); } /** * Handle special case - x = y. * This case is specified explicitly to avoid roundoff error. */ if (x == y) { m00 = 0.0; m01 = 1.0; m02 = 0.0; m10 = 1.0; m11 = 0.0; m12 = 0.0; return this; } // rotate vector to positive x axis direction double d = Math.sqrt(x * x + y * y); double sin = y / d; double cos = x / d; rotate(-sin, cos); // reflect about the x-axis scale(1, -1); // rotate back rotate(sin, cos); return this; } /** * Sets this transformation to be a rotation around the origin. * A positive rotation angle corresponds * to a counter-clockwise rotation. * The transformation matrix for a rotation * by an angle theta * has the value: *
  
   * |  cos(theta)  -sin(theta)   0 |
   * |  sin(theta)   cos(theta)   0 |
   * |           0            0   1 |
   * 
* * @param theta the rotation angle, in radians * @return this transformation, with an updated matrix */ public AffineTransformation setToRotation(double theta) { setToRotation(Math.sin(theta), Math.cos(theta)); return this; } /** * Sets this transformation to be a rotation around the origin * by specifying the sin and cos of the rotation angle directly. * The transformation matrix for the rotation * has the value: *
  
   * |  cosTheta  -sinTheta   0 |
   * |  sinTheta   cosTheta   0 |
   * |         0          0   1 |
   * 
* * @param sinTheta the sine of the rotation angle * @param cosTheta the cosine of the rotation angle * @return this transformation, with an updated matrix */ public AffineTransformation setToRotation(double sinTheta, double cosTheta) { m00 = cosTheta; m01 = -sinTheta; m02 = 0.0; m10 = sinTheta; m11 = cosTheta; m12 = 0.0; return this; } /** * Sets this transformation to be a rotation * around a given point (x,y). * A positive rotation angle corresponds * to a counter-clockwise rotation. * The transformation matrix for a rotation * by an angle theta * has the value: *
  
   * |  cosTheta  -sinTheta   x-x*cos+y*sin |
   * |  sinTheta   cosTheta   y-x*sin-y*cos |
   * |           0            0   1 |
   * 
* * @param theta the rotation angle, in radians * @param x the x-ordinate of the rotation point * @param y the y-ordinate of the rotation point * @return this transformation, with an updated matrix */ public AffineTransformation setToRotation(double theta, double x, double y) { setToRotation(Math.sin(theta), Math.cos(theta), x, y); return this; } /** * Sets this transformation to be a rotation * around a given point (x,y) * by specifying the sin and cos of the rotation angle directly. * The transformation matrix for the rotation * has the value: *
  
   * |  cosTheta  -sinTheta   x-x*cos+y*sin |
   * |  sinTheta   cosTheta   y-x*sin-y*cos |
   * |         0          0         1       |
   * 
* * @param sinTheta the sine of the rotation angle * @param cosTheta the cosine of the rotation angle * @param x the x-ordinate of the rotation point * @param y the y-ordinate of the rotation point * @return this transformation, with an updated matrix */ public AffineTransformation setToRotation(double sinTheta, double cosTheta, double x, double y) { m00 = cosTheta; m01 = -sinTheta; m02 = x - x * cosTheta + y * sinTheta; m10 = sinTheta; m11 = cosTheta; m12 = y - x * sinTheta - y * cosTheta; return this; } /** * Sets this transformation to be a scaling. * The transformation matrix for a scale * has the value: *
  
   * |  xScale      0  dx |
   * |  1      yScale  dy |
   * |  0           0   1 |
   * 
* * @param xScale the amount to scale x-ordinates by * @param yScale the amount to scale y-ordinates by * @return this transformation, with an updated matrix */ public AffineTransformation setToScale(double xScale, double yScale) { m00 = xScale; m01 = 0.0; m02 = 0.0; m10 = 0.0; m11 = yScale; m12 = 0.0; return this; } /** * Sets this transformation to be a shear. * The transformation matrix for a shear * has the value: *
  
   * |  1      xShear  0 |
   * |  yShear      1  0 |
   * |  0           0  1 |
   * 
* Note that a shear of (1, 1) is not * equal to shear(1, 0) composed with shear(0, 1). * Instead, shear(1, 1) corresponds to a mapping onto the * line x = y. * * @param xShear the x component to shear by * @param yShear the y component to shear by * @return this transformation, with an updated matrix */ public AffineTransformation setToShear(double xShear, double yShear) { m00 = 1.0; m01 = xShear; m02 = 0.0; m10 = yShear; m11 = 1.0; m12 = 0.0; return this; } /** * Sets this transformation to be a translation. * For a translation by the vector (x, y) * the transformation matrix has the value: *
  
   * |  1  0  dx |
   * |  1  0  dy |
   * |  0  0   1 |
   * 
* @param dx the x component to translate by * @param dy the y component to translate by * @return this transformation, with an updated matrix */ public AffineTransformation setToTranslation(double dx, double dy) { m00 = 1.0; m01 = 0.0; m02 = dx; m10 = 0.0; m11 = 1.0; m12 = dy; return this; } /** * Updates the value of this transformation * to that of a reflection transformation composed * with the current value. * * @param x0 the x-ordinate of a point on the line to reflect around * @param y0 the y-ordinate of a point on the line to reflect around * @param x1 the x-ordinate of a point on the line to reflect around * @param y1 the y-ordinate of a point on the line to reflect around * @return this transformation, with an updated matrix */ public AffineTransformation reflect(double x0, double y0, double x1, double y1) { compose(reflectionInstance(x0, y0, x1, y1)); return this; } /** * Updates the value of this transformation * to that of a reflection transformation composed * with the current value. * * @param x the x-ordinate of the line to reflect around * @param y the y-ordinate of the line to reflect around * @return this transformation, with an updated matrix */ public AffineTransformation reflect(double x, double y) { compose(reflectionInstance(x, y)); return this; } /** * Updates the value of this transformation * to that of a rotation transformation composed * with the current value. * Positive angles correspond to a rotation * in the counter-clockwise direction. * * @param theta the angle to rotate by, in radians * @return this transformation, with an updated matrix */ public AffineTransformation rotate(double theta) { compose(rotationInstance(theta)); return this; } /** * Updates the value of this transformation * to that of a rotation around the origin composed * with the current value, * with the sin and cos of the rotation angle specified directly. * * @param sinTheta the sine of the angle to rotate by * @param cosTheta the cosine of the angle to rotate by * @return this transformation, with an updated matrix */ public AffineTransformation rotate(double sinTheta, double cosTheta) { compose(rotationInstance(sinTheta, cosTheta)); return this; } /** * Updates the value of this transformation * to that of a rotation around a given point composed * with the current value. * Positive angles correspond to a rotation * in the counter-clockwise direction. * * @param theta the angle to rotate by, in radians * @param x the x-ordinate of the rotation point * @param y the y-ordinate of the rotation point * @return this transformation, with an updated matrix */ public AffineTransformation rotate(double theta, double x, double y) { compose(rotationInstance(theta, x, y)); return this; } /** * Updates the value of this transformation * to that of a rotation around a given point composed * with the current value, * with the sin and cos of the rotation angle specified directly. * * @param sinTheta the sine of the angle to rotate by * @param cosTheta the cosine of the angle to rotate by * @param x the x-ordinate of the rotation point * @param y the y-ordinate of the rotation point * @return this transformation, with an updated matrix */ public AffineTransformation rotate(double sinTheta, double cosTheta, double x, double y) { compose(rotationInstance(sinTheta, cosTheta)); return this; } /** * Updates the value of this transformation * to that of a scale transformation composed * with the current value. * * @param xScale the value to scale by in the x direction * @param yScale the value to scale by in the y direction * @return this transformation, with an updated matrix */ public AffineTransformation scale(double xScale, double yScale) { compose(scaleInstance(xScale, yScale)); return this; } /** * Updates the value of this transformation * to that of a shear transformation composed * with the current value. * * @param xShear the value to shear by in the x direction * @param yShear the value to shear by in the y direction * @return this transformation, with an updated matrix */ public AffineTransformation shear(double xShear, double yShear) { compose(shearInstance(xShear, yShear)); return this; } /** * Updates the value of this transformation * to that of a translation transformation composed * with the current value. * * @param x the value to translate by in the x direction * @param y the value to translate by in the y direction * @return this transformation, with an updated matrix */ public AffineTransformation translate(double x, double y) { compose(translationInstance(x, y)); return this; } /** * Updates this transformation to be * the composition of this transformation with the given {@link AffineTransformation}. * This produces a transformation whose effect * is equal to applying this transformation * followed by the argument transformation. * Mathematically, *
   * A.compose(B) = TB x TA
   * 
* * @param trans an affine transformation * @return this transformation, with an updated matrix */ public AffineTransformation compose(AffineTransformation trans) { double mp00 = trans.m00 * m00 + trans.m01 * m10; double mp01 = trans.m00 * m01 + trans.m01 * m11; double mp02 = trans.m00 * m02 + trans.m01 * m12 + trans.m02; double mp10 = trans.m10 * m00 + trans.m11 * m10; double mp11 = trans.m10 * m01 + trans.m11 * m11; double mp12 = trans.m10 * m02 + trans.m11 * m12 + trans.m12; m00 = mp00; m01 = mp01; m02 = mp02; m10 = mp10; m11 = mp11; m12 = mp12; return this; } /** * Updates this transformation to be the composition * of a given {@link AffineTransformation} with this transformation. * This produces a transformation whose effect * is equal to applying the argument transformation * followed by this transformation. * Mathematically, *
   * A.composeBefore(B) = TA x TB
   * 
* * @param trans an affine transformation * @return this transformation, with an updated matrix */ public AffineTransformation composeBefore(AffineTransformation trans) { double mp00 = m00 * trans.m00 + m01 * trans.m10; double mp01 = m00 * trans.m01 + m01 * trans.m11; double mp02 = m00 * trans.m02 + m01 * trans.m12 + m02; double mp10 = m10 * trans.m00 + m11 * trans.m10; double mp11 = m10 * trans.m01 + m11 * trans.m11; double mp12 = m10 * trans.m02 + m11 * trans.m12 + m12; m00 = mp00; m01 = mp01; m02 = mp02; m10 = mp10; m11 = mp11; m12 = mp12; return this; } /** * Applies this transformation to the src coordinate * and places the results in the dest coordinate * (which may be the same as the source). * * @param src the coordinate to transform * @param dest the coordinate to accept the results * @return the dest coordinate */ public Coordinate transform(Coordinate src, Coordinate dest) { double xp = m00 * src.x + m01 * src.y + m02; double yp = m10 * src.x + m11 * src.y + m12; dest.x = xp; dest.y = yp; return dest; } /** * Cretaes a new @link Geometry which is the result * of this transformation applied to the input Geometry. * *@param seq a Geometry *@return a transformed Geometry */ public Geometry transform(Geometry g) { Geometry g2 = (Geometry) g.clone(); g2.apply(this); return g2; } /** * Applies this transformation to the i'th coordinate * in the given CoordinateSequence. * *@param seq a CoordinateSequence *@param i the index of the coordinate to transform */ public void transform(CoordinateSequence seq, int i) { double xp = m00 * seq.getOrdinate(i, 0) + m01 * seq.getOrdinate(i, 1) + m02; double yp = m10 * seq.getOrdinate(i, 0) + m11 * seq.getOrdinate(i, 1) + m12; seq.setOrdinate(i, 0, xp); seq.setOrdinate(i, 1, yp); } /** * Transforms the i'th coordinate in the input sequence * *@param seq a CoordinateSequence *@param i the index of the coordinate to transform */ public void filter(CoordinateSequence seq, int i) { transform(seq, i); } public boolean isGeometryChanged() { return true; } /** * Reports that this filter should continue to be executed until * all coordinates have been transformed. * * @return false */ public boolean isDone() { return false; } /** * Tests if this transformation is the identity transformation. * * @return true if this is the identity transformation */ public boolean isIdentity() { return (m00 == 1 && m01 == 0 && m02 == 0 && m10 == 0 && m11 == 1 && m12 == 0); } /** * Tests if an object is an * AffineTransformation * and has the same matrix as * this transformation. * * @param obj an object to test * @return true if the given object is equal to this object */ public boolean equals(Object obj) { if (obj == null) return false; if (! (obj instanceof AffineTransformation)) return false; AffineTransformation trans = (AffineTransformation) obj; return m00 == trans.m00 && m01 == trans.m01 && m02 == trans.m02 && m10 == trans.m10 && m11 == trans.m11 && m12 == trans.m12; } /** * Gets a text representation of this transformation. * The string is of the form: *
   * AffineTransformation[[m00, m01, m02], [m10, m11, m12]]
   * 
* * @return a string representing this transformation * */ public String toString() { return "AffineTransformation[[" + m00 + ", " + m01 + ", " + m02 + "], [" + m10 + ", " + m11 + ", " + m12 + "]]"; } /** * Clones this transformation * * @return a copy of this transformation */ public Object clone() { try { return super.clone(); } catch(Exception ex) { Assert.shouldNeverReachHere(); } return null; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy