📄 affinetransform.java
字号:
this.m11 = m11; this.m02 = m02; this.m12 = m12; updateState(); } /** * Constructs a new <code>AffineTransform</code> from an array of * floating point values representing either the 4 non-translation * enries or the 6 specifiable entries of the 3x3 transformation * matrix. The values are retrieved from the array as * { m00 m10 m01 m11 [m02 m12]}. * @param flatmatrix the float array containing the values to be set * in the new <code>AffineTransform</code> object. The length of the * array is assumed to be at least 4. If the length of the array is * less than 6, only the first 4 values are taken. If the length of * the array is greater than 6, the first 6 values are taken. */ public AffineTransform(float[] flatmatrix) { m00 = flatmatrix[0]; m10 = flatmatrix[1]; m01 = flatmatrix[2]; m11 = flatmatrix[3]; if (flatmatrix.length > 5) { m02 = flatmatrix[4]; m12 = flatmatrix[5]; } updateState(); } /** * Constructs a new <code>AffineTransform</code> from 6 double * precision values representing the 6 specifiable entries of the 3x3 * transformation matrix. * @param m00, m01, m02, m10, m11, m12 the * 6 floating point values that compose the 3x3 transformation matrix */ public AffineTransform(double m00, double m10, double m01, double m11, double m02, double m12) { this.m00 = m00; this.m10 = m10; this.m01 = m01; this.m11 = m11; this.m02 = m02; this.m12 = m12; updateState(); } /** * Constructs a new <code>AffineTransform</code> from an array of * double precision values representing either the 4 non-translation * entries or the 6 specifiable entries of the 3x3 transformation * matrix. The values are retrieved from the array as * { m00 m10 m01 m11 [m02 m12]}. * @param flatmatrix the double array containing the values to be set * in the new <code>AffineTransform</code> object. The length of the * array is assumed to be at least 4. If the length of the array is * less than 6, only the first 4 values are taken. If the length of * the array is greater than 6, the first 6 values are taken. */ public AffineTransform(double[] flatmatrix) { m00 = flatmatrix[0]; m10 = flatmatrix[1]; m01 = flatmatrix[2]; m11 = flatmatrix[3]; if (flatmatrix.length > 5) { m02 = flatmatrix[4]; m12 = flatmatrix[5]; } updateState(); } /** * Returns a transform representing a translation transformation. * The matrix representing the returned transform is: * <pre> * [ 1 0 tx ] * [ 0 1 ty ] * [ 0 0 1 ] * </pre> * @param tx the distance by which coordinates are translated in the * X axis direction * @param ty the distance by which coordinates are translated in the * Y axis direction * @return an <code>AffineTransform</code> object that represents a * translation transformation, created with the specified vector. */ public static AffineTransform getTranslateInstance(double tx, double ty) { AffineTransform Tx = new AffineTransform(); Tx.setToTranslation(tx, ty); return Tx; } /** * Returns a transform representing a rotation transformation. * The matrix representing the returned transform is: * <pre> * [ cos(theta) -sin(theta) 0 ] * [ sin(theta) cos(theta) 0 ] * [ 0 0 1 ] * </pre> * Rotating with a positive angle theta rotates points on the positive * x axis toward the positive y axis. * @param theta the angle of rotation in radians * @return an <code>AffineTransform</code> object that is a rotation * transformation, created with the specified angle of rotation. */ public static AffineTransform getRotateInstance(double theta) { AffineTransform Tx = new AffineTransform(); Tx.setToRotation(theta); return Tx; } /** * Returns a transform that rotates coordinates around an anchor point. * This operation is equivalent to translating the coordinates so * that the anchor point is at the origin (S1), then rotating them * about the new origin (S2), and finally translating so that the * intermediate origin is restored to the coordinates of the original * anchor point (S3). * <p> * This operation is equivalent to the following sequence of calls: * <pre> * AffineTransform Tx = new AffineTransform(); * Tx.setToTranslation(x, y); // S3: final translation * Tx.rotate(theta); // S2: rotate around anchor * Tx.translate(-x, -y); // S1: translate anchor to origin * </pre> * The matrix representing the returned transform is: * <pre> * [ cos(theta) -sin(theta) x-x*cos+y*sin ] * [ sin(theta) cos(theta) y-x*sin-y*cos ] * [ 0 0 1 ] * </pre> * Rotating with a positive angle theta rotates points on the positive * x axis toward the positive y axis. * @param theta the angle of rotation in radians * @param x, y the coordinates of the anchor point of the * rotation * @return an <code>AffineTransform</code> object that rotates * coordinates around the specified point by the specified angle of * rotation. */ public static AffineTransform getRotateInstance(double theta, double x, double y) { AffineTransform Tx = new AffineTransform(); Tx.setToRotation(theta, x, y); return Tx; } /** * Returns a transform representing a scaling transformation. * The matrix representing the returned transform is: * <pre> * [ sx 0 0 ] * [ 0 sy 0 ] * [ 0 0 1 ] * </pre> * @param sx the factor by which coordinates are scaled along the * X axis direction * @param sy the factor by which coordinates are scaled along the * Y axis direction * @return an <code>AffineTransform</code> object that scales * coordinates by the specified factors. */ public static AffineTransform getScaleInstance(double sx, double sy) { AffineTransform Tx = new AffineTransform(); Tx.setToScale(sx, sy); return Tx; } /** * Returns a transform representing a shearing transformation. * The matrix representing the returned transform is: * <pre> * [ 1 shx 0 ] * [ shy 1 0 ] * [ 0 0 1 ] * </pre> * @param shx the multiplier by which coordinates are shifted in the * direction of the positive X axis as a factor of their Y coordinate * @param shy the multiplier by which coordinates are shifted in the * direction of the positive Y axis as a factor of their X coordinate * @return an <code>AffineTransform</code> object that shears * coordinates by the specified multipliers. */ public static AffineTransform getShearInstance(double shx, double shy) { AffineTransform Tx = new AffineTransform(); Tx.setToShear(shx, shy); return Tx; } /** * Retrieves the flag bits describing the conversion properties of * this transform. * The return value is either one of the constants TYPE_IDENTITY * or TYPE_GENERAL_TRANSFORM, or a combination of the * appriopriate flag bits. * A valid combination of flag bits is an exclusive OR operation * that can combine * the TYPE_TRANSLATION flag bit * in addition to either of the * TYPE_UNIFORM_SCALE or TYPE_GENERAL_SCALE flag bits * as well as either of the * TYPE_QUADRANT_ROTATION or TYPE_GENERAL_ROTATION flag bits. * @return the OR combination of any of the indicated flags that * apply to this transform * @see #TYPE_IDENTITY * @see #TYPE_TRANSLATION * @see #TYPE_UNIFORM_SCALE * @see #TYPE_GENERAL_SCALE * @see #TYPE_QUADRANT_ROTATION * @see #TYPE_GENERAL_ROTATION * @see #TYPE_GENERAL_TRANSFORM */ public int getType() { if (type == TYPE_UNKNOWN) { calculateType(); } return type; } /** * This is the utility function to calculate the flag bits when * they have not been cached. * @see #getType */ private void calculateType() { int ret = TYPE_IDENTITY; boolean sgn0, sgn1; double M0, M1, M2, M3; updateState(); switch (state) { default: stateError(); break; /* NOTREACHED */ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): ret = TYPE_TRANSLATION; /* NOBREAK */ case (APPLY_SHEAR | APPLY_SCALE): if ((M0 = m00) * (M2 = m01) + (M3 = m10) * (M1 = m11) != 0) { // Transformed unit vectors are not perpendicular... this.type = TYPE_GENERAL_TRANSFORM; return; } sgn0 = (M0 >= 0.0); sgn1 = (M1 >= 0.0); if (sgn0 == sgn1) { // sgn(M0) == sgn(M1) therefore sgn(M2) == -sgn(M3) // This is the "unflipped" (right-handed) state if (M0 != M1 || M2 != -M3) { ret |= (TYPE_GENERAL_ROTATION | TYPE_GENERAL_SCALE); } else if (M0 * M1 - M2 * M3 != 1.0) { ret |= (TYPE_GENERAL_ROTATION | TYPE_UNIFORM_SCALE); } else { ret |= TYPE_GENERAL_ROTATION; } } else { // sgn(M0) == -sgn(M1) therefore sgn(M2) == sgn(M3) // This is the "flipped" (left-handed) state if (M0 != -M1 || M2 != M3) { ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP | TYPE_GENERAL_SCALE); } else if (M0 * M1 - M2 * M3 != 1.0) { ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP | TYPE_UNIFORM_SCALE); } else { ret |= (TYPE_GENERAL_ROTATION | TYPE_FLIP); } } break; case (APPLY_SHEAR | APPLY_TRANSLATE): ret = TYPE_TRANSLATION; /* NOBREAK */ case (APPLY_SHEAR): sgn0 = ((M0 = m01) >= 0.0); sgn1 = ((M1 = m10) >= 0.0); if (sgn0 != sgn1) { // Different signs - simple 90 degree rotation if (M0 != -M1) { ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE); } else if (M0 != 1.0 && M0 != -1.0) { ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE); } else { ret |= TYPE_QUADRANT_ROTATION; } } else { // Same signs - 90 degree rotation plus an axis flip too if (M0 == M1) { ret |= (TYPE_QUADRANT_ROTATION | TYPE_FLIP | TYPE_UNIFORM_SCALE); } else { ret |= (TYPE_QUADRANT_ROTATION | TYPE_FLIP | TYPE_GENERAL_SCALE); } } break; case (APPLY_SCALE | APPLY_TRANSLATE): ret = TYPE_TRANSLATION; /* NOBREAK */ case (APPLY_SCALE): sgn0 = ((M0 = m00) >= 0.0); sgn1 = ((M1 = m11) >= 0.0); if (sgn0 == sgn1) { if (sgn0) { // Both scaling factors non-negative - simple scale // Note: APPLY_SCALE implies M0, M1 are not both 1 if (M0 == M1) { ret |= TYPE_UNIFORM_SCALE; } else { ret |= TYPE_GENERAL_SCALE; } } else { // Both scaling factors negative - 180 degree rotation if (M0 != M1) { ret |= (TYPE_QUADRANT_ROTATION | TYPE_GENERAL_SCALE); } else if (M0 != -1.0) { ret |= (TYPE_QUADRANT_ROTATION | TYPE_UNIFORM_SCALE); } else { ret |= TYPE_QUADRANT_ROTATION; } } } else { // Scaling factor signs different - flip about some axis if (M0 == -M1) { if (M0 == 1.0 || M0 == -1.0) { ret |= TYPE_FLIP; } else { ret |= (TYPE_FLIP | TYPE_UNIFORM_SCALE); } } else { ret |= (TYPE_FLIP | TYPE_GENERAL_SCALE); } } break; case (APPLY_TRANSLATE): ret = TYPE_TRANSLATION; break; case (APPLY_IDENTITY): break; } this.type = ret; } /** * Returns the determinant of the matrix representation of the transform. * The determinant is useful both to determine if the transform can * be inverted and to get a single value representing the * combined X and Y scaling of the transform. * <p> * If the determinant is non-zero, then this transform is * invertible and the various methods that depend on the inverse * transform do not need to throw a * {@link NoninvertibleTransformException}. * If the determinant is zero then this transform can not be * inverted since the transform maps all input coordinates onto * a line or a point. * If the determinant is near enough to zero then inverse transform * operations might not carry enough precision to produce meaningful * results. * <p> * If this transform represents a uniform scale, as indicated by * the <code>getType</code> method then the determinant also * represents the square of the uniform scale factor by which all of * the points are expanded from or contracted towards the origin. * If this transform represents a non-uniform scale or more general * transform then the determinant is not likely to represent a * value useful for any purpose other than determining if inverse * transforms are possible. * <p> * Mathematically, the determinant is calculated using the formula: * <pre> * | m00 m01 m02 | * | m10 m11 m12 | = m00 * m11 - m01 * m10 * | 0 0 1 | * </pre> * * @return the determinant of the matrix used to transform the * coordinates. * @see #getType * @see #createInverse * @see #inverseTransform * @see #TYPE_UNIFORM_SCALE */ public double getDeterminant() { switch (state) { default: stateError(); return 0; /* NOTREACHED */ case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE): case (APPLY_SHEAR | APPLY_SCALE): return m00 * m11 - m01 * m10; case (APPLY_SHEAR | APPLY_TRANSLATE): case (APPLY_SHEAR): return -(m01 * m10); case (APPLY_SCALE | APPLY_TRANSLATE): case (APPLY_SCALE): return m00 * m11; case (APPLY_TRANSLATE): case (APPLY_IDENTITY): return 1.0; } } /** * Manually recalculates the state of the transform when the matrix * changes too much to predict the effects on the state. * The following table specifies what the various settings of the * state field say about the values of the corresponding matrix * element fields. * Note that the rules governing the SCALE fields are slightly
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -