/*
 * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.javafx.geom.transform;

import com.sun.javafx.geom.BaseBounds;
import com.sun.javafx.geom.Point2D;
import com.sun.javafx.geom.Vec3d;
import com.sun.javafx.geom.Vec3f;

A general-purpose 4x4 transform that may or may not be affine. The GeneralTransform is typically used only for projection transforms.
/** * A general-purpose 4x4 transform that may or may not be affine. The * GeneralTransform is typically used only for projection transforms. * */
public final class GeneralTransform3D implements CanTransformVec3d { //The 4x4 double-precision floating point matrix. The mathematical //representation is row major, as in traditional matrix mathematics. protected double[] mat = new double[16]; //flag if this is an identity transformation. private boolean identity;
Constructs and initializes a transform to the identity matrix.
/** * Constructs and initializes a transform to the identity matrix. */
public GeneralTransform3D() { setIdentity(); }
Returns true if the transform is affine. A transform is considered to be affine if the last row of its matrix is (0,0,0,1). Note that an instance of AffineTransform3D is always affine.
/** * Returns true if the transform is affine. A transform is considered * to be affine if the last row of its matrix is (0,0,0,1). Note that * an instance of AffineTransform3D is always affine. */
public boolean isAffine() { if (!isInfOrNaN() && almostZero(mat[12]) && almostZero(mat[13]) && almostZero(mat[14]) && almostOne(mat[15])) { return true; } else { return false; } }
Sets the value of this transform to the specified transform.
Params:
  • t1 – the transform to copy into this transform.
Returns:this transform
/** * Sets the value of this transform to the specified transform. * * @param t1 the transform to copy into this transform. * * @return this transform */
public GeneralTransform3D set(GeneralTransform3D t1) { System.arraycopy(t1.mat, 0, mat, 0, mat.length); updateState(); return this; }
Sets the matrix values of this transform to the values in the specified array.
Params:
  • m – an array of 16 values to copy into this transform in row major order.
Returns:this transform
/** * Sets the matrix values of this transform to the values in the * specified array. * * @param m an array of 16 values to copy into this transform in * row major order. * * @return this transform */
public GeneralTransform3D set(double[] m) { System.arraycopy(m, 0, mat, 0, mat.length); updateState(); return this; }
Returns a copy of an array of 16 values that contains the 4x4 matrix of this transform. The first four elements of the array will contain the top row of the transform matrix, etc.
Params:
  • rv – the return value, or null
Returns:an array of 16 values
/** * Returns a copy of an array of 16 values that contains the 4x4 matrix * of this transform. The first four elements of the array will contain * the top row of the transform matrix, etc. * * @param rv the return value, or null * * @return an array of 16 values */
public double[] get(double[] rv) { if (rv == null) { rv = new double[mat.length]; } System.arraycopy(mat, 0, rv, 0, mat.length); return rv; } public double get(int index) { assert ((index >= 0) && (index < mat.length)); return mat[index]; } private Vec3d tempV3d; public BaseBounds transform(BaseBounds src, BaseBounds dst) { if (tempV3d == null) { tempV3d = new Vec3d(); } return TransformHelper.general3dBoundsTransform(this, src, dst, tempV3d); }
Transform 2D point (with z == 0)
Params:
  • point –
  • pointOut –
Returns:
/** * Transform 2D point (with z == 0) * @param point * @param pointOut * @return */
public Point2D transform(Point2D point, Point2D pointOut) { if (pointOut == null) { pointOut = new Point2D(); } double w = mat[12] * point.x + mat[13] * point.y + mat[15]; float outX = (float) (mat[0] * point.x + mat[1] * point.y + mat[3]); pointOut.y = (float) (mat[4] * point.x + mat[5] * point.y + mat[7]); pointOut.x = outX; if (w != 0.0) { pointOut.x /= w; pointOut.y /= w; } return pointOut; }
Transforms the point parameter with this transform and places the result into pointOut. The fourth element of the point input parameter is assumed to be one.
Params:
  • point – the input point to be transformed
  • pointOut – the transformed point
Returns:the transformed point
/** * Transforms the point parameter with this transform and * places the result into pointOut. The fourth element of the * point input parameter is assumed to be one. * * @param point the input point to be transformed * * @param pointOut the transformed point * * @return the transformed point */
public Vec3d transform(Vec3d point, Vec3d pointOut) { if (pointOut == null) { pointOut = new Vec3d(); } double w = mat[12] * point.x + mat[13] * point.y + mat[14] * point.z + mat[15]; double outX = mat[0] * point.x + mat[1] * point.y + mat[2] * point.z + mat[3]; double outY = mat[4] * point.x + mat[5] * point.y + mat[6] * point.z + mat[7]; pointOut.z = mat[8] * point.x + mat[9] * point.y + mat[10] * point.z + mat[11]; pointOut.x = outX; pointOut.y = outY; if (w != 0.0) { pointOut.x /= w; pointOut.y /= w; pointOut.z /= w; } return pointOut; }
Transforms the point parameter with this transform and places the result back into point. The fourth element of the point input parameter is assumed to be one.
Params:
  • point – the input point to be transformed
Returns:the transformed point
/** * Transforms the point parameter with this transform and * places the result back into point. The fourth element of the * point input parameter is assumed to be one. * * @param point the input point to be transformed * * @return the transformed point */
public Vec3d transform(Vec3d point) { return transform(point, point); }
Transforms the normal parameter by this transform and places the value into normalOut. The fourth element of the normal is assumed to be zero. Note: For correct lighting results, if a transform has uneven scaling surface normals should transformed by the inverse transpose of the transform. This the responsibility of the application and is not done automatically by this method.
Params:
  • normal – the input normal to be transformed
  • normalOut – the transformed normal
Returns:the transformed normal
/** * Transforms the normal parameter by this transform and places the value * into normalOut. The fourth element of the normal is assumed to be zero. * Note: For correct lighting results, if a transform has uneven scaling * surface normals should transformed by the inverse transpose of * the transform. This the responsibility of the application and is not * done automatically by this method. * * @param normal the input normal to be transformed * * @param normalOut the transformed normal * * @return the transformed normal */
public Vec3f transformNormal(Vec3f normal, Vec3f normalOut) { if (normalOut == null) { normalOut = new Vec3f(); } float outX = (float) (mat[0] * normal.x + mat[1] * normal.y + mat[2] * normal.z); float outY = (float) (mat[4] * normal.x + mat[5] * normal.y + mat[6] * normal.z); normalOut.z = (float) (mat[8] * normal.x + mat[9] * normal.y + mat[10] * normal.z); normalOut.x = outX; normalOut.y = outY; return normalOut; }
Transforms the normal parameter by this transform and places the value back into normal. The fourth element of the normal is assumed to be zero. Note: For correct lighting results, if a transform has uneven scaling surface normals should transformed by the inverse transpose of the transform. This the responsibility of the application and is not done automatically by this method.
Params:
  • normal – the input normal to be transformed
Returns:the transformed normal
/** * Transforms the normal parameter by this transform and places the value * back into normal. The fourth element of the normal is assumed to be zero. * Note: For correct lighting results, if a transform has uneven scaling * surface normals should transformed by the inverse transpose of * the transform. This the responsibility of the application and is not * done automatically by this method. * * @param normal the input normal to be transformed * * @return the transformed normal */
public Vec3f transformNormal(Vec3f normal) { return transformNormal(normal, normal); }
Sets the value of this transform to a perspective projection transform. This transform maps points from Eye Coordinates (EC) to Clipping Coordinates (CC). Note that the field of view is specified in radians.
Params:
  • verticalFOV – specifies whether the fov is vertical (Y direction).
  • fov – specifies the field of view in radians
  • aspect – specifies the aspect ratio. The aspect ratio is the ratio of width to height.
  • zNear – the distance to the frustum's near clipping plane. This value must be positive, (the value -zNear is the location of the near clip plane).
  • zFar – the distance to the frustum's far clipping plane
Returns:this transform
/** * Sets the value of this transform to a perspective projection transform. * This transform maps points from Eye Coordinates (EC) * to Clipping Coordinates (CC). * Note that the field of view is specified in radians. * * @param verticalFOV specifies whether the fov is vertical (Y direction). * * @param fov specifies the field of view in radians * * @param aspect specifies the aspect ratio. The aspect ratio is the ratio * of width to height. * * @param zNear the distance to the frustum's near clipping plane. * This value must be positive, (the value -zNear is the location of the * near clip plane). * * @param zFar the distance to the frustum's far clipping plane * * @return this transform */
public GeneralTransform3D perspective(boolean verticalFOV, double fov, double aspect, double zNear, double zFar) { double sine; double cotangent; double deltaZ; double half_fov = fov * 0.5; deltaZ = zFar - zNear; sine = Math.sin(half_fov); cotangent = Math.cos(half_fov) / sine; mat[0] = verticalFOV ? cotangent / aspect : cotangent; mat[5] = verticalFOV ? cotangent : cotangent * aspect; mat[10] = -(zFar + zNear) / deltaZ; mat[11] = -2.0 * zNear * zFar / deltaZ; mat[14] = -1.0; mat[1] = mat[2] = mat[3] = mat[4] = mat[6] = mat[7] = mat[8] = mat[9] = mat[12] = mat[13] = mat[15] = 0; updateState(); return this; }
Sets the value of this transform to an orthographic (parallel) projection transform. This transform maps coordinates from Eye Coordinates (EC) to Clipping Coordinates (CC). Note that unlike the similar function in OpenGL, the clipping coordinates generated by the resulting transform are in a right-handed coordinate system.
Params:
  • left – the vertical line on the left edge of the near clipping plane mapped to the left edge of the graphics window
  • right – the vertical line on the right edge of the near clipping plane mapped to the right edge of the graphics window
  • bottom – the horizontal line on the bottom edge of the near clipping plane mapped to the bottom edge of the graphics window
  • top – the horizontal line on the top edge of the near clipping plane mapped to the top edge of the graphics window
  • near – the distance to the frustum's near clipping plane (the value -near is the location of the near clip plane)
  • far – the distance to the frustum's far clipping plane
Returns:this transform
/** * Sets the value of this transform to an orthographic (parallel) * projection transform. * This transform maps coordinates from Eye Coordinates (EC) * to Clipping Coordinates (CC). Note that unlike the similar function * in OpenGL, the clipping coordinates generated by the resulting * transform are in a right-handed coordinate system. * @param left the vertical line on the left edge of the near * clipping plane mapped to the left edge of the graphics window * @param right the vertical line on the right edge of the near * clipping plane mapped to the right edge of the graphics window * @param bottom the horizontal line on the bottom edge of the near * clipping plane mapped to the bottom edge of the graphics window * @param top the horizontal line on the top edge of the near * clipping plane mapped to the top edge of the graphics window * @param near the distance to the frustum's near clipping plane * (the value -near is the location of the near clip plane) * @param far the distance to the frustum's far clipping plane * * @return this transform */
public GeneralTransform3D ortho(double left, double right, double bottom, double top, double near, double far) { double deltax = 1 / (right - left); double deltay = 1 / (top - bottom); double deltaz = 1 / (far - near); mat[0] = 2.0 * deltax; mat[3] = -(right + left) * deltax; mat[5] = 2.0 * deltay; mat[7] = -(top + bottom) * deltay; mat[10] = 2.0 * deltaz; mat[11] = (far + near) * deltaz; mat[1] = mat[2] = mat[4] = mat[6] = mat[8] = mat[9] = mat[12] = mat[13] = mat[14] = 0; mat[15] = 1; updateState(); return this; } public double computeClipZCoord() { double zEc = (1.0 - mat[15]) / mat[14]; double zCc = mat[10] * zEc + mat[11]; return zCc; }
Computes the determinant of this transform.
Returns:the determinant
/** * Computes the determinant of this transform. * * @return the determinant */
public double determinant() { // cofactor exapainsion along first row return mat[0]*(mat[5]*(mat[10]*mat[15] - mat[11]*mat[14]) - mat[6]*(mat[ 9]*mat[15] - mat[11]*mat[13]) + mat[7]*(mat[ 9]*mat[14] - mat[10]*mat[13])) - mat[1]*(mat[4]*(mat[10]*mat[15] - mat[11]*mat[14]) - mat[6]*(mat[ 8]*mat[15] - mat[11]*mat[12]) + mat[7]*(mat[ 8]*mat[14] - mat[10]*mat[12])) + mat[2]*(mat[4]*(mat[ 9]*mat[15] - mat[11]*mat[13]) - mat[5]*(mat[ 8]*mat[15] - mat[11]*mat[12]) + mat[7]*(mat[ 8]*mat[13] - mat[ 9]*mat[12])) - mat[3]*(mat[4]*(mat[ 9]*mat[14] - mat[10]*mat[13]) - mat[5]*(mat[ 8]*mat[14] - mat[10]*mat[12]) + mat[6]*(mat[ 8]*mat[13] - mat[ 9]*mat[12])); }
Inverts this transform in place.
Returns:this transform
/** * Inverts this transform in place. * * @return this transform */
public GeneralTransform3D invert() { return invert(this); }
General invert routine. Inverts t1 and places the result in "this". Note that this routine handles both the "this" version and the non-"this" version. Also note that since this routine is slow anyway, we won't worry about allocating a little bit of garbage.
/** * General invert routine. Inverts t1 and places the result in "this". * Note that this routine handles both the "this" version and the * non-"this" version. * * Also note that since this routine is slow anyway, we won't worry * about allocating a little bit of garbage. */
private GeneralTransform3D invert(GeneralTransform3D t1) { double[] tmp = new double[16]; int[] row_perm = new int[4]; // Use LU decomposition and backsubstitution code specifically // for floating-point 4x4 matrices. // Copy source matrix to tmp System.arraycopy(t1.mat, 0, tmp, 0, tmp.length); // Calculate LU decomposition: Is the matrix singular? if (!luDecomposition(tmp, row_perm)) { // Matrix has no inverse throw new SingularMatrixException(); } // Perform back substitution on the identity matrix // luDecomposition will set rot[] & scales[] for use // in luBacksubstituation mat[0] = 1.0; mat[1] = 0.0; mat[2] = 0.0; mat[3] = 0.0; mat[4] = 0.0; mat[5] = 1.0; mat[6] = 0.0; mat[7] = 0.0; mat[8] = 0.0; mat[9] = 0.0; mat[10] = 1.0; mat[11] = 0.0; mat[12] = 0.0; mat[13] = 0.0; mat[14] = 0.0; mat[15] = 1.0; luBacksubstitution(tmp, row_perm, this.mat); updateState(); return this; }
Given a 4x4 array "matrix0", this function replaces it with the LU decomposition of a row-wise permutation of itself. The input parameters are "matrix0" and "dimen". The array "matrix0" is also an output parameter. The vector "row_perm[4]" is an output parameter that contains the row permutations resulting from partial pivoting. The output parameter "even_row_xchg" is 1 when the number of row exchanges is even, or -1 otherwise. Assumes data type is always double. This function is similar to luDecomposition, except that it is tuned specifically for 4x4 matrices.
Returns:true if the matrix is nonsingular, or false otherwise.
/** * Given a 4x4 array "matrix0", this function replaces it with the * LU decomposition of a row-wise permutation of itself. The input * parameters are "matrix0" and "dimen". The array "matrix0" is also * an output parameter. The vector "row_perm[4]" is an output * parameter that contains the row permutations resulting from partial * pivoting. The output parameter "even_row_xchg" is 1 when the * number of row exchanges is even, or -1 otherwise. Assumes data * type is always double. * * This function is similar to luDecomposition, except that it * is tuned specifically for 4x4 matrices. * * @return true if the matrix is nonsingular, or false otherwise. */
private static boolean luDecomposition(double[] matrix0, int[] row_perm) { // Reference: Press, Flannery, Teukolsky, Vetterling, // _Numerical_Recipes_in_C_, Cambridge University Press, // 1988, pp 40-45. // // Can't re-use this temporary since the method is static. double row_scale[] = new double[4]; // Determine implicit scaling information by looping over rows { int i, j; int ptr, rs; double big, temp; ptr = 0; rs = 0; // For each row ... i = 4; while (i-- != 0) { big = 0.0; // For each column, find the largest element in the row j = 4; while (j-- != 0) { temp = matrix0[ptr++]; temp = Math.abs(temp); if (temp > big) { big = temp; } } // Is the matrix singular? if (big == 0.0) { return false; } row_scale[rs++] = 1.0 / big; } } { int j; int mtx; mtx = 0; // For all columns, execute Crout's method for (j = 0; j < 4; j++) { int i, imax, k; int target, p1, p2; double sum, big, temp; // Determine elements of upper diagonal matrix U for (i = 0; i < j; i++) { target = mtx + (4*i) + j; sum = matrix0[target]; k = i; p1 = mtx + (4*i); p2 = mtx + j; while (k-- != 0) { sum -= matrix0[p1] * matrix0[p2]; p1++; p2 += 4; } matrix0[target] = sum; } // Search for largest pivot element and calculate // intermediate elements of lower diagonal matrix L. big = 0.0; imax = -1; for (i = j; i < 4; i++) { target = mtx + (4*i) + j; sum = matrix0[target]; k = j; p1 = mtx + (4*i); p2 = mtx + j; while (k-- != 0) { sum -= matrix0[p1] * matrix0[p2]; p1++; p2 += 4; } matrix0[target] = sum; // Is this the best pivot so far? if ((temp = row_scale[i] * Math.abs(sum)) >= big) { big = temp; imax = i; } } if (imax < 0) { return false; } // Is a row exchange necessary? if (j != imax) { // Yes: exchange rows k = 4; p1 = mtx + (4*imax); p2 = mtx + (4*j); while (k-- != 0) { temp = matrix0[p1]; matrix0[p1++] = matrix0[p2]; matrix0[p2++] = temp; } // Record change in scale factor row_scale[imax] = row_scale[j]; } // Record row permutation row_perm[j] = imax; // Is the matrix singular if (matrix0[(mtx + (4*j) + j)] == 0.0) { return false; } // Divide elements of lower diagonal matrix L by pivot if (j != (4-1)) { temp = 1.0 / (matrix0[(mtx + (4*j) + j)]); target = mtx + (4*(j+1)) + j; i = 3 - j; while (i-- != 0) { matrix0[target] *= temp; target += 4; } } } } return true; }
Solves a set of linear equations. The input parameters "matrix1", and "row_perm" come from luDecompostionD4x4 and do not change here. The parameter "matrix2" is a set of column vectors assembled into a 4x4 matrix of floating-point values. The procedure takes each column of "matrix2" in turn and treats it as the right-hand side of the matrix equation Ax = LUx = b. The solution vector replaces the original column of the matrix. If "matrix2" is the identity matrix, the procedure replaces its contents with the inverse of the matrix from which "matrix1" was originally derived.
/** * Solves a set of linear equations. The input parameters "matrix1", * and "row_perm" come from luDecompostionD4x4 and do not change * here. The parameter "matrix2" is a set of column vectors assembled * into a 4x4 matrix of floating-point values. The procedure takes each * column of "matrix2" in turn and treats it as the right-hand side of the * matrix equation Ax = LUx = b. The solution vector replaces the * original column of the matrix. * * If "matrix2" is the identity matrix, the procedure replaces its contents * with the inverse of the matrix from which "matrix1" was originally * derived. */
// // Reference: Press, Flannery, Teukolsky, Vetterling, // _Numerical_Recipes_in_C_, Cambridge University Press, // 1988, pp 44-45. // private static void luBacksubstitution(double[] matrix1, int[] row_perm, double[] matrix2) { int i, ii, ip, j, k; int rp; int cv, rv; // rp = row_perm; rp = 0; // For each column vector of matrix2 ... for (k = 0; k < 4; k++) { // cv = &(matrix2[0][k]); cv = k; ii = -1; // Forward substitution for (i = 0; i < 4; i++) { double sum; ip = row_perm[rp+i]; sum = matrix2[cv+4*ip]; matrix2[cv+4*ip] = matrix2[cv+4*i]; if (ii >= 0) { // rv = &(matrix1[i][0]); rv = i*4; for (j = ii; j <= i-1; j++) { sum -= matrix1[rv+j] * matrix2[cv+4*j]; } } else if (sum != 0.0) { ii = i; } matrix2[cv+4*i] = sum; } // Backsubstitution // rv = &(matrix1[3][0]); rv = 3*4; matrix2[cv+4*3] /= matrix1[rv+3]; rv -= 4; matrix2[cv+4*2] = (matrix2[cv+4*2] - matrix1[rv+3] * matrix2[cv+4*3]) / matrix1[rv+2]; rv -= 4; matrix2[cv+4*1] = (matrix2[cv+4*1] - matrix1[rv+2] * matrix2[cv+4*2] - matrix1[rv+3] * matrix2[cv+4*3]) / matrix1[rv+1]; rv -= 4; matrix2[cv+4*0] = (matrix2[cv+4*0] - matrix1[rv+1] * matrix2[cv+4*1] - matrix1[rv+2] * matrix2[cv+4*2] - matrix1[rv+3] * matrix2[cv+4*3]) / matrix1[rv+0]; } }
Sets the value of this transform to the result of multiplying itself with transform t1 : this = this * t1.
Params:
  • t1 – the other transform
Returns:this transform
/** * Sets the value of this transform to the result of multiplying itself * with transform t1 : this = this * t1. * * @param t1 the other transform * * @return this transform */
public GeneralTransform3D mul(BaseTransform t1) { if (t1.isIdentity()) { return this; } double tmp0, tmp1, tmp2, tmp3; double tmp4, tmp5, tmp6, tmp7; double tmp8, tmp9, tmp10, tmp11; double tmp12, tmp13, tmp14, tmp15; double mxx = t1.getMxx(); double mxy = t1.getMxy(); double mxz = t1.getMxz(); double mxt = t1.getMxt(); double myx = t1.getMyx(); double myy = t1.getMyy(); double myz = t1.getMyz(); double myt = t1.getMyt(); double mzx = t1.getMzx(); double mzy = t1.getMzy(); double mzz = t1.getMzz(); double mzt = t1.getMzt(); tmp0 = mat[0] * mxx + mat[1] * myx + mat[2] * mzx; tmp1 = mat[0] * mxy + mat[1] * myy + mat[2] * mzy; tmp2 = mat[0] * mxz + mat[1] * myz + mat[2] * mzz; tmp3 = mat[0] * mxt + mat[1] * myt + mat[2] * mzt + mat[3]; tmp4 = mat[4] * mxx + mat[5] * myx + mat[6] * mzx; tmp5 = mat[4] * mxy + mat[5] * myy + mat[6] * mzy; tmp6 = mat[4] * mxz + mat[5] * myz + mat[6] * mzz; tmp7 = mat[4] * mxt + mat[5] * myt + mat[6] * mzt + mat[7]; tmp8 = mat[8] * mxx + mat[9] * myx + mat[10] * mzx; tmp9 = mat[8] * mxy + mat[9] * myy + mat[10] * mzy; tmp10 = mat[8] * mxz + mat[9] * myz + mat[10] * mzz; tmp11 = mat[8] * mxt + mat[9] * myt + mat[10] * mzt + mat[11]; if (isAffine()) { tmp12 = tmp13 = tmp14 = 0; tmp15 = 1; } else { tmp12 = mat[12] * mxx + mat[13] * myx + mat[14] * mzx; tmp13 = mat[12] * mxy + mat[13] * myy + mat[14] * mzy; tmp14 = mat[12] * mxz + mat[13] * myz + mat[14] * mzz; tmp15 = mat[12] * mxt + mat[13] * myt + mat[14] * mzt + mat[15]; } mat[0] = tmp0; mat[1] = tmp1; mat[2] = tmp2; mat[3] = tmp3; mat[4] = tmp4; mat[5] = tmp5; mat[6] = tmp6; mat[7] = tmp7; mat[8] = tmp8; mat[9] = tmp9; mat[10] = tmp10; mat[11] = tmp11; mat[12] = tmp12; mat[13] = tmp13; mat[14] = tmp14; mat[15] = tmp15; updateState(); return this; }
Sets the value of this transform to the result of multiplying itself with a scale transform:
scaletx =
    [ sx  0  0  0 ]
    [  0 sy  0  0 ]
    [  0  0 sz  0 ]
    [  0  0  0  1 ].
this = this * scaletx.
Params:
  • sx – the X coordinate scale factor
  • sy – the Y coordinate scale factor
  • sz – the Z coordinate scale factor
Returns:this transform
/** * Sets the value of this transform to the result of multiplying itself * with a scale transform: * <pre> * scaletx = * [ sx 0 0 0 ] * [ 0 sy 0 0 ] * [ 0 0 sz 0 ] * [ 0 0 0 1 ]. * this = this * scaletx. * </pre> * * @param sx the X coordinate scale factor * @param sy the Y coordinate scale factor * @param sz the Z coordinate scale factor * * @return this transform */
public GeneralTransform3D scale(double sx, double sy, double sz) { boolean update = false; if (sx != 1.0) { mat[0] *= sx; mat[4] *= sx; mat[8] *= sx; mat[12] *= sx; update = true; } if (sy != 1.0) { mat[1] *= sy; mat[5] *= sy; mat[9] *= sy; mat[13] *= sy; update = true; } if (sz != 1.0) { mat[2] *= sz; mat[6] *= sz; mat[10] *= sz; mat[14] *= sz; update = true; } if (update) { updateState(); } return this; }
Sets the value of this transform to the result of multiplying itself with transform t1 : this = this * t1.
Params:
  • t1 – the other transform
Returns:this transform
/** * Sets the value of this transform to the result of multiplying itself * with transform t1 : this = this * t1. * * @param t1 the other transform * * @return this transform */
public GeneralTransform3D mul(GeneralTransform3D t1) { if (t1.isIdentity()) { return this; } double tmp0, tmp1, tmp2, tmp3; double tmp4, tmp5, tmp6, tmp7; double tmp8, tmp9, tmp10, tmp11; double tmp12, tmp13, tmp14, tmp15; if (t1.isAffine()) { tmp0 = mat[0] * t1.mat[0] + mat[1] * t1.mat[4] + mat[2] * t1.mat[8]; tmp1 = mat[0] * t1.mat[1] + mat[1] * t1.mat[5] + mat[2] * t1.mat[9]; tmp2 = mat[0] * t1.mat[2] + mat[1] * t1.mat[6] + mat[2] * t1.mat[10]; tmp3 = mat[0] * t1.mat[3] + mat[1] * t1.mat[7] + mat[2] * t1.mat[11] + mat[3]; tmp4 = mat[4] * t1.mat[0] + mat[5] * t1.mat[4] + mat[6] * t1.mat[8]; tmp5 = mat[4] * t1.mat[1] + mat[5] * t1.mat[5] + mat[6] * t1.mat[9]; tmp6 = mat[4] * t1.mat[2] + mat[5] * t1.mat[6] + mat[6] * t1.mat[10]; tmp7 = mat[4] * t1.mat[3] + mat[5] * t1.mat[7] + mat[6] * t1.mat[11] + mat[7]; tmp8 = mat[8] * t1.mat[0] + mat[9] * t1.mat[4] + mat[10] * t1.mat[8]; tmp9 = mat[8] * t1.mat[1] + mat[9] * t1.mat[5] + mat[10] * t1.mat[9]; tmp10 = mat[8] * t1.mat[2] + mat[9] * t1.mat[6] + mat[10] * t1.mat[10]; tmp11 = mat[8] * t1.mat[3] + mat[9] * t1.mat[7] + mat[10] * t1.mat[11] + mat[11]; if (isAffine()) { tmp12 = tmp13 = tmp14 = 0; tmp15 = 1; } else { tmp12 = mat[12] * t1.mat[0] + mat[13] * t1.mat[4] + mat[14] * t1.mat[8]; tmp13 = mat[12] * t1.mat[1] + mat[13] * t1.mat[5] + mat[14] * t1.mat[9]; tmp14 = mat[12] * t1.mat[2] + mat[13] * t1.mat[6] + mat[14] * t1.mat[10]; tmp15 = mat[12] * t1.mat[3] + mat[13] * t1.mat[7] + mat[14] * t1.mat[11] + mat[15]; } } else { tmp0 = mat[0] * t1.mat[0] + mat[1] * t1.mat[4] + mat[2] * t1.mat[8] + mat[3] * t1.mat[12]; tmp1 = mat[0] * t1.mat[1] + mat[1] * t1.mat[5] + mat[2] * t1.mat[9] + mat[3] * t1.mat[13]; tmp2 = mat[0] * t1.mat[2] + mat[1] * t1.mat[6] + mat[2] * t1.mat[10] + mat[3] * t1.mat[14]; tmp3 = mat[0] * t1.mat[3] + mat[1] * t1.mat[7] + mat[2] * t1.mat[11] + mat[3] * t1.mat[15]; tmp4 = mat[4] * t1.mat[0] + mat[5] * t1.mat[4] + mat[6] * t1.mat[8] + mat[7] * t1.mat[12]; tmp5 = mat[4] * t1.mat[1] + mat[5] * t1.mat[5] + mat[6] * t1.mat[9] + mat[7] * t1.mat[13]; tmp6 = mat[4] * t1.mat[2] + mat[5] * t1.mat[6] + mat[6] * t1.mat[10] + mat[7] * t1.mat[14]; tmp7 = mat[4] * t1.mat[3] + mat[5] * t1.mat[7] + mat[6] * t1.mat[11] + mat[7] * t1.mat[15]; tmp8 = mat[8] * t1.mat[0] + mat[9] * t1.mat[4] + mat[10] * t1.mat[8] + mat[11] * t1.mat[12]; tmp9 = mat[8] * t1.mat[1] + mat[9] * t1.mat[5] + mat[10] * t1.mat[9] + mat[11] * t1.mat[13]; tmp10 = mat[8] * t1.mat[2] + mat[9] * t1.mat[6] + mat[10] * t1.mat[10] + mat[11] * t1.mat[14]; tmp11 = mat[8] * t1.mat[3] + mat[9] * t1.mat[7] + mat[10] * t1.mat[11] + mat[11] * t1.mat[15]; if (isAffine()) { tmp12 = t1.mat[12]; tmp13 = t1.mat[13]; tmp14 = t1.mat[14]; tmp15 = t1.mat[15]; } else { tmp12 = mat[12] * t1.mat[0] + mat[13] * t1.mat[4] + mat[14] * t1.mat[8] + mat[15] * t1.mat[12]; tmp13 = mat[12] * t1.mat[1] + mat[13] * t1.mat[5] + mat[14] * t1.mat[9] + mat[15] * t1.mat[13]; tmp14 = mat[12] * t1.mat[2] + mat[13] * t1.mat[6] + mat[14] * t1.mat[10] + mat[15] * t1.mat[14]; tmp15 = mat[12] * t1.mat[3] + mat[13] * t1.mat[7] + mat[14] * t1.mat[11] + mat[15] * t1.mat[15]; } } mat[0] = tmp0; mat[1] = tmp1; mat[2] = tmp2; mat[3] = tmp3; mat[4] = tmp4; mat[5] = tmp5; mat[6] = tmp6; mat[7] = tmp7; mat[8] = tmp8; mat[9] = tmp9; mat[10] = tmp10; mat[11] = tmp11; mat[12] = tmp12; mat[13] = tmp13; mat[14] = tmp14; mat[15] = tmp15; updateState(); return this; }
Sets this transform to the identity matrix.
Returns:this transform
/** * Sets this transform to the identity matrix. * * @return this transform */
public GeneralTransform3D setIdentity() { mat[0] = 1.0; mat[1] = 0.0; mat[2] = 0.0; mat[3] = 0.0; mat[4] = 0.0; mat[5] = 1.0; mat[6] = 0.0; mat[7] = 0.0; mat[8] = 0.0; mat[9] = 0.0; mat[10] = 1.0; mat[11] = 0.0; mat[12] = 0.0; mat[13] = 0.0; mat[14] = 0.0; mat[15] = 1.0; identity = true; return this; }
Returns true if the transform is identity. A transform is considered to be identity if the diagonal elements of its matrix is all 1s otherwise 0s.
/** * Returns true if the transform is identity. A transform is considered * to be identity if the diagonal elements of its matrix is all 1s * otherwise 0s. */
public boolean isIdentity() { return identity; } private void updateState() { //set the identity flag. identity = mat[0] == 1.0 && mat[5] == 1.0 && mat[10] == 1.0 && mat[15] == 1.0 && mat[1] == 0.0 && mat[2] == 0.0 && mat[3] == 0.0 && mat[4] == 0.0 && mat[6] == 0.0 && mat[7] == 0.0 && mat[8] == 0.0 && mat[9] == 0.0 && mat[11] == 0.0 && mat[12] == 0.0 && mat[13] == 0.0 && mat[14] == 0.0; } // Check whether matrix has an Infinity or NaN value. If so, don't treat it // as affine. boolean isInfOrNaN() { // The following is a faster version of the check. // Instead of 3 tests per array element (Double.isInfinite is 2 tests), // for a total of 48 tests, we will do 16 multiplies and 1 test. double d = 0.0; for (int i = 0; i < mat.length; i++) { d *= mat[i]; } return d != 0.0; } private static final double EPSILON_ABSOLUTE = 1.0e-5; static boolean almostZero(double a) { return ((a < EPSILON_ABSOLUTE) && (a > -EPSILON_ABSOLUTE)); } static boolean almostOne(double a) { return ((a < 1+EPSILON_ABSOLUTE) && (a > 1-EPSILON_ABSOLUTE)); } public GeneralTransform3D copy() { GeneralTransform3D newTransform = new GeneralTransform3D(); newTransform.set(this); return newTransform; }
Returns the matrix elements of this transform as a string.
Returns: the matrix elements of this transform
/** * Returns the matrix elements of this transform as a string. * @return the matrix elements of this transform */
@Override public String toString() { return mat[0] + ", " + mat[1] + ", " + mat[2] + ", " + mat[3] + "\n" + mat[4] + ", " + mat[5] + ", " + mat[6] + ", " + mat[7] + "\n" + mat[8] + ", " + mat[9] + ", " + mat[10] + ", " + mat[11] + "\n" + mat[12] + ", " + mat[13] + ", " + mat[14] + ", " + mat[15] + "\n"; } }