diff options
Diffstat (limited to 'tools/layoutlib/bridge/src/android/graphics/Matrix.java')
-rw-r--r-- | tools/layoutlib/bridge/src/android/graphics/Matrix.java | 984 |
1 files changed, 984 insertions, 0 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix.java b/tools/layoutlib/bridge/src/android/graphics/Matrix.java new file mode 100644 index 000000000000..3f9a99355a4b --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/Matrix.java @@ -0,0 +1,984 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics; + +import java.awt.geom.AffineTransform; + + +/** + * A matrix implementation overridden by the LayoutLib bridge. + */ +public class Matrix extends _Original_Matrix { + + float mValues[] = new float[9]; + + /** + * Create an identity matrix + */ + public Matrix() { + reset(); + } + + /** + * Create a matrix that is a (deep) copy of src + * @param src The matrix to copy into this matrix + */ + public Matrix(Matrix src) { + set(src); + } + + /** + * Creates a Matrix object from the float array. The array becomes the internal storage + * of the object. + * @param data + */ + private Matrix(float[] data) { + assert data.length != 9; + mValues = data; + } + + @Override + public void finalize() throws Throwable { + // pass + } + + //---------- Custom Methods + + /** + * Adds the given transformation to the current Matrix + * <p/>This in effect does this = this*matrix + * @param matrix + */ + private void addTransform(float[] matrix) { + float[] tmp = new float[9]; + + // first row + tmp[0] = matrix[0] * mValues[0] + matrix[1] * mValues[3] + matrix[2] * mValues[6]; + tmp[1] = matrix[0] * mValues[1] + matrix[1] * mValues[4] + matrix[2] * mValues[7]; + tmp[2] = matrix[0] * mValues[2] + matrix[1] * mValues[5] + matrix[2] * mValues[8]; + + // 2nd row + tmp[3] = matrix[3] * mValues[0] + matrix[4] * mValues[3] + matrix[5] * mValues[6]; + tmp[4] = matrix[3] * mValues[1] + matrix[4] * mValues[4] + matrix[5] * mValues[7]; + tmp[5] = matrix[3] * mValues[2] + matrix[4] * mValues[5] + matrix[5] * mValues[8]; + + // 3rd row + tmp[6] = matrix[6] * mValues[0] + matrix[7] * mValues[3] + matrix[8] * mValues[6]; + tmp[7] = matrix[6] * mValues[1] + matrix[7] * mValues[4] + matrix[8] * mValues[7]; + tmp[8] = matrix[6] * mValues[2] + matrix[7] * mValues[5] + matrix[8] * mValues[8]; + + // copy the result over to mValues + mValues = tmp; + } + + public AffineTransform getTransform() { + return new AffineTransform(mValues[0], mValues[1], mValues[2], + mValues[3], mValues[4], mValues[5]); + } + + public boolean hasPerspective() { + return (mValues[6] != 0 || mValues[7] != 0 || mValues[8] != 1); + } + + //---------- + + /** + * Returns true if the matrix is identity. + * This maybe faster than testing if (getType() == 0) + */ + @Override + public boolean isIdentity() { + for (int i = 0, k = 0; i < 3; i++) { + for (int j = 0; j < 3; j++, k++) { + if (mValues[k] != ((i==j) ? 1 : 0)) { + return false; + } + } + } + + return true; + } + + /** + * Returns true if will map a rectangle to another rectangle. This can be + * true if the matrix is identity, scale-only, or rotates a multiple of 90 + * degrees. + */ + @Override + public boolean rectStaysRect() { + return (computeTypeMask() & kRectStaysRect_Mask) != 0; + } + + /** + * (deep) copy the src matrix into this matrix. If src is null, reset this + * matrix to the identity matrix. + */ + public void set(Matrix src) { + if (src == null) { + reset(); + } else { + System.arraycopy(src.mValues, 0, mValues, 0, mValues.length); + } + } + + @Override + public void set(_Original_Matrix src) { + throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); + } + + /** Returns true if obj is a Matrix and its values equal our values. + */ + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof Matrix) { + Matrix matrix = (Matrix)obj; + for (int i = 0 ; i < 9 ; i++) { + if (mValues[i] != matrix.mValues[i]) { + return false; + } + } + + return true; + } + + return false; + } + + /** Set the matrix to identity */ + @Override + public void reset() { + for (int i = 0, k = 0; i < 3; i++) { + for (int j = 0; j < 3; j++, k++) { + mValues[k] = ((i==j) ? 1 : 0); + } + } + } + + /** Set the matrix to translate by (dx, dy). */ + @Override + public void setTranslate(float dx, float dy) { + mValues[0] = 1; + mValues[1] = 0; + mValues[2] = dx; + mValues[3] = 0; + mValues[4] = 1; + mValues[5] = dy; + mValues[6] = 0; + mValues[7] = 0; + mValues[7] = 1; + } + + /** + * Set the matrix to scale by sx and sy, with a pivot point at (px, py). + * The pivot point is the coordinate that should remain unchanged by the + * specified transformation. + */ + @Override + public void setScale(float sx, float sy, float px, float py) { + // TODO: do it in one pass + + // translate so that the pivot is in 0,0 + mValues[0] = 1; + mValues[1] = 0; + mValues[2] = -px; + mValues[3] = 0; + mValues[4] = 1; + mValues[5] = -py; + mValues[6] = 0; + mValues[7] = 0; + mValues[7] = 1; + + // scale + addTransform(new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 }); + // translate back the pivot + addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 }); + } + + /** Set the matrix to scale by sx and sy. */ + @Override + public void setScale(float sx, float sy) { + mValues[0] = sx; + mValues[1] = 0; + mValues[2] = 0; + mValues[3] = 0; + mValues[4] = sy; + mValues[5] = 0; + mValues[6] = 0; + mValues[7] = 0; + mValues[7] = 1; + } + + /** + * Set the matrix to rotate by the specified number of degrees, with a pivot + * point at (px, py). The pivot point is the coordinate that should remain + * unchanged by the specified transformation. + */ + @Override + public void setRotate(float degrees, float px, float py) { + // TODO: do it in one pass + + // translate so that the pivot is in 0,0 + mValues[0] = 1; + mValues[1] = 0; + mValues[2] = -px; + mValues[3] = 0; + mValues[4] = 1; + mValues[5] = -py; + mValues[6] = 0; + mValues[7] = 0; + mValues[7] = 1; + + // scale + double rad = Math.toRadians(degrees); + float cos = (float)Math.cos(rad); + float sin = (float)Math.sin(rad); + addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 }); + // translate back the pivot + addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 }); + } + + /** + * Set the matrix to rotate about (0,0) by the specified number of degrees. + */ + @Override + public void setRotate(float degrees) { + double rad = Math.toRadians(degrees); + float cos = (float)Math.cos(rad); + float sin = (float)Math.sin(rad); + + mValues[0] = cos; + mValues[1] = -sin; + mValues[2] = 0; + mValues[3] = sin; + mValues[4] = cos; + mValues[5] = 0; + mValues[6] = 0; + mValues[7] = 0; + mValues[7] = 1; + } + + /** + * Set the matrix to rotate by the specified sine and cosine values, with a + * pivot point at (px, py). The pivot point is the coordinate that should + * remain unchanged by the specified transformation. + */ + @Override + public void setSinCos(float sinValue, float cosValue, float px, float py) { + // TODO: do it in one pass + + // translate so that the pivot is in 0,0 + mValues[0] = 1; + mValues[1] = 0; + mValues[2] = -px; + mValues[3] = 0; + mValues[4] = 1; + mValues[5] = -py; + mValues[6] = 0; + mValues[7] = 0; + mValues[7] = 1; + + // scale + addTransform(new float[] { cosValue, -sinValue, 0, sinValue, cosValue, 0, 0, 0, 1 }); + // translate back the pivot + addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 }); + } + + /** Set the matrix to rotate by the specified sine and cosine values. */ + @Override + public void setSinCos(float sinValue, float cosValue) { + mValues[0] = cosValue; + mValues[1] = -sinValue; + mValues[2] = 0; + mValues[3] = sinValue; + mValues[4] = cosValue; + mValues[5] = 0; + mValues[6] = 0; + mValues[7] = 0; + mValues[7] = 1; + } + + /** + * Set the matrix to skew by sx and sy, with a pivot point at (px, py). + * The pivot point is the coordinate that should remain unchanged by the + * specified transformation. + */ + @Override + public void setSkew(float kx, float ky, float px, float py) { + // TODO: do it in one pass + + // translate so that the pivot is in 0,0 + mValues[0] = 1; + mValues[1] = 0; + mValues[2] = -px; + mValues[3] = 0; + mValues[4] = 1; + mValues[5] = -py; + mValues[6] = 0; + mValues[7] = 0; + mValues[7] = 1; + + // scale + addTransform(new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 }); + // translate back the pivot + addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 }); + } + + /** Set the matrix to skew by sx and sy. */ + @Override + public void setSkew(float kx, float ky) { + mValues[0] = 1; + mValues[1] = kx; + mValues[2] = -0; + mValues[3] = ky; + mValues[4] = 1; + mValues[5] = 0; + mValues[6] = 0; + mValues[7] = 0; + mValues[7] = 1; + } + + /** + * Set the matrix to the concatenation of the two specified matrices, + * returning true if the the result can be represented. Either of the two + * matrices may also be the target matrix. this = a * b + */ + public boolean setConcat(Matrix a, Matrix b) { + if (a == this) { + preConcat(b); + } else if (b == this) { + postConcat(b); + } else { + Matrix tmp = new Matrix(b); + tmp.addTransform(a.mValues); + set(tmp); + } + + return true; + } + + @Override + public boolean setConcat(_Original_Matrix a, _Original_Matrix b) { + throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); + } + + /** + * Preconcats the matrix with the specified translation. + * M' = M * T(dx, dy) + */ + @Override + public boolean preTranslate(float dx, float dy) { + // create a matrix that will be multiply by this + Matrix m = new Matrix(new float[] { 1, 0, dx, 0, 1, dy, 0, 0, 1 }); + m.addTransform(this.mValues); + + System.arraycopy(m.mValues, 0, mValues, 0, 9); + return true; + } + + /** + * Preconcats the matrix with the specified scale. + * M' = M * S(sx, sy, px, py) + */ + @Override + public boolean preScale(float sx, float sy, float px, float py) { + Matrix m = new Matrix(); + m.setScale(sx, sy, px, py); + m.addTransform(mValues); + set(m); + + return true; + } + + /** + * Preconcats the matrix with the specified scale. + * M' = M * S(sx, sy) + */ + @Override + public boolean preScale(float sx, float sy) { + Matrix m = new Matrix(); + m.setScale(sx, sy); + m.addTransform(mValues); + set(m); + + return true; + } + + /** + * Preconcats the matrix with the specified rotation. + * M' = M * R(degrees, px, py) + */ + @Override + public boolean preRotate(float degrees, float px, float py) { + Matrix m = new Matrix(); + m.setRotate(degrees, px, py); + m.addTransform(mValues); + set(m); + + return true; + } + + /** + * Preconcats the matrix with the specified rotation. + * M' = M * R(degrees) + */ + @Override + public boolean preRotate(float degrees) { + Matrix m = new Matrix(); + m.setRotate(degrees); + m.addTransform(mValues); + set(m); + + return true; + } + + /** + * Preconcats the matrix with the specified skew. + * M' = M * K(kx, ky, px, py) + */ + @Override + public boolean preSkew(float kx, float ky, float px, float py) { + Matrix m = new Matrix(); + m.setSkew(kx, ky, px, py); + m.addTransform(mValues); + set(m); + + return true; + } + + /** + * Preconcats the matrix with the specified skew. + * M' = M * K(kx, ky) + */ + @Override + public boolean preSkew(float kx, float ky) { + Matrix m = new Matrix(); + m.setSkew(kx, ky); + m.addTransform(mValues); + set(m); + + return true; + } + + /** + * Preconcats the matrix with the specified matrix. + * M' = M * other + */ + public boolean preConcat(Matrix other) { + Matrix m = new Matrix(other); + other.addTransform(mValues); + set(m); + + return true; + } + + @Override + public boolean preConcat(_Original_Matrix other) { + throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); + } + + /** + * Postconcats the matrix with the specified translation. + * M' = T(dx, dy) * M + */ + @Override + public boolean postTranslate(float dx, float dy) { + addTransform(new float[] { 1, 0, dx, 0, 1, dy, 0, 0, 1 }); + return true; + } + + /** + * Postconcats the matrix with the specified scale. + * M' = S(sx, sy, px, py) * M + */ + @Override + public boolean postScale(float sx, float sy, float px, float py) { + // TODO: do it in one pass + // translate so that the pivot is in 0,0 + addTransform(new float[] { 1, 0, -px, 0, 1, py, 0, 0, 1 }); + // scale + addTransform(new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 }); + // translate back the pivot + addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 }); + + return true; + } + + /** + * Postconcats the matrix with the specified scale. + * M' = S(sx, sy) * M + */ + @Override + public boolean postScale(float sx, float sy) { + addTransform(new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 }); + return true; + } + + /** + * Postconcats the matrix with the specified rotation. + * M' = R(degrees, px, py) * M + */ + @Override + public boolean postRotate(float degrees, float px, float py) { + // TODO: do it in one pass + // translate so that the pivot is in 0,0 + addTransform(new float[] { 1, 0, -px, 0, 1, py, 0, 0, 1 }); + // scale + double rad = Math.toRadians(degrees); + float cos = (float)Math.cos(rad); + float sin = (float)Math.sin(rad); + addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 }); + // translate back the pivot + addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 }); + + return true; + } + + /** + * Postconcats the matrix with the specified rotation. + * M' = R(degrees) * M + */ + @Override + public boolean postRotate(float degrees) { + double rad = Math.toRadians(degrees); + float cos = (float)Math.cos(rad); + float sin = (float)Math.sin(rad); + addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 }); + + return true; + } + + /** + * Postconcats the matrix with the specified skew. + * M' = K(kx, ky, px, py) * M + */ + @Override + public boolean postSkew(float kx, float ky, float px, float py) { + // TODO: do it in one pass + // translate so that the pivot is in 0,0 + addTransform(new float[] { 1, 0, -px, 0, 1, py, 0, 0, 1 }); + // scale + addTransform(new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 }); + // translate back the pivot + addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 }); + + return true; + } + + /** + * Postconcats the matrix with the specified skew. + * M' = K(kx, ky) * M + */ + @Override + public boolean postSkew(float kx, float ky) { + addTransform(new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 }); + + return true; + } + + /** + * Postconcats the matrix with the specified matrix. + * M' = other * M + */ + public boolean postConcat(Matrix other) { + addTransform(other.mValues); + + return true; + } + + @Override + public boolean postConcat(_Original_Matrix other) { + throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); + } + + /** Controlls how the src rect should align into the dst rect for + setRectToRect(). + */ + public enum ScaleToFit { + /** + * Scale in X and Y independently, so that src matches dst exactly. + * This may change the aspect ratio of the src. + */ + FILL (0), + /** + * Compute a scale that will maintain the original src aspect ratio, + * but will also ensure that src fits entirely inside dst. At least one + * axis (X or Y) will fit exactly. START aligns the result to the + * left and top edges of dst. + */ + START (1), + /** + * Compute a scale that will maintain the original src aspect ratio, + * but will also ensure that src fits entirely inside dst. At least one + * axis (X or Y) will fit exactly. The result is centered inside dst. + */ + CENTER (2), + /** + * Compute a scale that will maintain the original src aspect ratio, + * but will also ensure that src fits entirely inside dst. At least one + * axis (X or Y) will fit exactly. END aligns the result to the + * right and bottom edges of dst. + */ + END (3); + + // the native values must match those in SkMatrix.h + ScaleToFit(int nativeInt) { + this.nativeInt = nativeInt; + } + final int nativeInt; + } + + /** + * Set the matrix to the scale and translate values that map the source + * rectangle to the destination rectangle, returning true if the result + * can be represented. + * + * @param src the source rectangle to map from. + * @param dst the destination rectangle to map to. + * @param stf the ScaleToFit option + * @return true if the matrix can be represented by the rectangle mapping. + */ + public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) { + if (dst == null || src == null) { + throw new NullPointerException(); + } + + if (src.isEmpty()) { + reset(); + return false; + } + + if (dst.isEmpty()) { + mValues[0] = mValues[1] = mValues[2] = mValues[3] = mValues[4] = mValues[5] + = mValues[6] = mValues[7] = 0; + mValues[8] = 1; + } else { + float tx, sx = dst.width() / src.width(); + float ty, sy = dst.height() / src.height(); + boolean xLarger = false; + + if (stf != ScaleToFit.FILL) { + if (sx > sy) { + xLarger = true; + sx = sy; + } else { + sy = sx; + } + } + + tx = dst.left - src.left * sx; + ty = dst.top - src.top * sy; + if (stf == ScaleToFit.CENTER || stf == ScaleToFit.END) { + float diff; + + if (xLarger) { + diff = dst.width() - src.width() * sy; + } else { + diff = dst.height() - src.height() * sy; + } + + if (stf == ScaleToFit.CENTER) { + diff = diff / 2; + } + + if (xLarger) { + tx += diff; + } else { + ty += diff; + } + } + + mValues[0] = sx; + mValues[4] = sy; + mValues[2] = tx; + mValues[5] = ty; + mValues[1] = mValues[3] = mValues[6] = mValues[7] = 0; + + } + // shared cleanup + mValues[8] = 1; + return true; + } + + @Override + public boolean setRectToRect(RectF src, RectF dst, _Original_Matrix.ScaleToFit stf) { + throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); + } + + /** + * Set the matrix such that the specified src points would map to the + * specified dst points. The "points" are represented as an array of floats, + * order [x0, y0, x1, y1, ...], where each "point" is 2 float values. + * + * @param src The array of src [x,y] pairs (points) + * @param srcIndex Index of the first pair of src values + * @param dst The array of dst [x,y] pairs (points) + * @param dstIndex Index of the first pair of dst values + * @param pointCount The number of pairs/points to be used. Must be [0..4] + * @return true if the matrix was set to the specified transformation + */ + @Override + public boolean setPolyToPoly(float[] src, int srcIndex, + float[] dst, int dstIndex, + int pointCount) { + if (pointCount > 4) { + throw new IllegalArgumentException(); + } + checkPointArrays(src, srcIndex, dst, dstIndex, pointCount); + throw new UnsupportedOperationException("STUB NEEDED"); + } + + /** + * If this matrix can be inverted, return true and if inverse is not null, + * set inverse to be the inverse of this matrix. If this matrix cannot be + * inverted, ignore inverse and return false. + */ + public boolean invert(Matrix inverse) { + throw new UnsupportedOperationException("STUB NEEDED"); + } + + @Override + public boolean invert(_Original_Matrix inverse) { + throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); + } + + /** + * Apply this matrix to the array of 2D points specified by src, and write + * the transformed points into the array of points specified by dst. The + * two arrays represent their "points" as pairs of floats [x, y]. + * + * @param dst The array of dst points (x,y pairs) + * @param dstIndex The index of the first [x,y] pair of dst floats + * @param src The array of src points (x,y pairs) + * @param srcIndex The index of the first [x,y] pair of src floats + * @param pointCount The number of points (x,y pairs) to transform + */ + @Override + public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex, + int pointCount) { + checkPointArrays(src, srcIndex, dst, dstIndex, pointCount); + throw new UnsupportedOperationException("STUB NEEDED"); + } + + /** + * Apply this matrix to the array of 2D vectors specified by src, and write + * the transformed vectors into the array of vectors specified by dst. The + * two arrays represent their "vectors" as pairs of floats [x, y]. + * + * @param dst The array of dst vectors (x,y pairs) + * @param dstIndex The index of the first [x,y] pair of dst floats + * @param src The array of src vectors (x,y pairs) + * @param srcIndex The index of the first [x,y] pair of src floats + * @param vectorCount The number of vectors (x,y pairs) to transform + */ + @Override + public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, + int vectorCount) { + checkPointArrays(src, srcIndex, dst, dstIndex, vectorCount); + throw new UnsupportedOperationException("STUB NEEDED"); + } + + /** + * Apply this matrix to the array of 2D points specified by src, and write + * the transformed points into the array of points specified by dst. The + * two arrays represent their "points" as pairs of floats [x, y]. + * + * @param dst The array of dst points (x,y pairs) + * @param src The array of src points (x,y pairs) + */ + @Override + public void mapPoints(float[] dst, float[] src) { + if (dst.length != src.length) { + throw new ArrayIndexOutOfBoundsException(); + } + mapPoints(dst, 0, src, 0, dst.length >> 1); + } + + /** + * Apply this matrix to the array of 2D vectors specified by src, and write + * the transformed vectors into the array of vectors specified by dst. The + * two arrays represent their "vectors" as pairs of floats [x, y]. + * + * @param dst The array of dst vectors (x,y pairs) + * @param src The array of src vectors (x,y pairs) + */ + @Override + public void mapVectors(float[] dst, float[] src) { + if (dst.length != src.length) { + throw new ArrayIndexOutOfBoundsException(); + } + mapVectors(dst, 0, src, 0, dst.length >> 1); + } + + /** + * Apply this matrix to the array of 2D points, and write the transformed + * points back into the array + * + * @param pts The array [x0, y0, x1, y1, ...] of points to transform. + */ + @Override + public void mapPoints(float[] pts) { + mapPoints(pts, 0, pts, 0, pts.length >> 1); + } + + /** + * Apply this matrix to the array of 2D vectors, and write the transformed + * vectors back into the array. + * @param vecs The array [x0, y0, x1, y1, ...] of vectors to transform. + */ + @Override + public void mapVectors(float[] vecs) { + mapVectors(vecs, 0, vecs, 0, vecs.length >> 1); + } + + /** + * Apply this matrix to the src rectangle, and write the transformed + * rectangle into dst. This is accomplished by transforming the 4 corners of + * src, and then setting dst to the bounds of those points. + * + * @param dst Where the transformed rectangle is written. + * @param src The original rectangle to be transformed. + * @return the result of calling rectStaysRect() + */ + @Override + public boolean mapRect(RectF dst, RectF src) { + if (dst == null || src == null) { + throw new NullPointerException(); + } + throw new UnsupportedOperationException("STUB NEEDED"); + } + + /** + * Apply this matrix to the rectangle, and write the transformed rectangle + * back into it. This is accomplished by transforming the 4 corners of rect, + * and then setting it to the bounds of those points + * + * @param rect The rectangle to transform. + * @return the result of calling rectStaysRect() + */ + @Override + public boolean mapRect(RectF rect) { + return mapRect(rect, rect); + } + + /** + * Return the mean radius of a circle after it has been mapped by + * this matrix. NOTE: in perspective this value assumes the circle + * has its center at the origin. + */ + @Override + public float mapRadius(float radius) { + throw new UnsupportedOperationException("STUB NEEDED"); + } + + /** Copy 9 values from the matrix into the array. + */ + @Override + public void getValues(float[] values) { + if (values.length < 9) { + throw new ArrayIndexOutOfBoundsException(); + } + System.arraycopy(mValues, 0, values, 0, mValues.length); + } + + /** Copy 9 values from the array into the matrix. + Depending on the implementation of Matrix, these may be + transformed into 16.16 integers in the Matrix, such that + a subsequent call to getValues() will not yield exactly + the same values. + */ + @Override + public void setValues(float[] values) { + if (values.length < 9) { + throw new ArrayIndexOutOfBoundsException(); + } + System.arraycopy(values, 0, mValues, 0, mValues.length); + } + + @SuppressWarnings("unused") + private final static int kIdentity_Mask = 0; + private final static int kTranslate_Mask = 0x01; //!< set if the matrix has translation + private final static int kScale_Mask = 0x02; //!< set if the matrix has X or Y scale + private final static int kAffine_Mask = 0x04; //!< set if the matrix skews or rotates + private final static int kPerspective_Mask = 0x08; //!< set if the matrix is in perspective + private final static int kRectStaysRect_Mask = 0x10; + @SuppressWarnings("unused") + private final static int kUnknown_Mask = 0x80; + + @SuppressWarnings("unused") + private final static int kAllMasks = kTranslate_Mask | + kScale_Mask | + kAffine_Mask | + kPerspective_Mask | + kRectStaysRect_Mask; + + // these guys align with the masks, so we can compute a mask from a variable 0/1 + @SuppressWarnings("unused") + private final static int kTranslate_Shift = 0; + @SuppressWarnings("unused") + private final static int kScale_Shift = 1; + @SuppressWarnings("unused") + private final static int kAffine_Shift = 2; + @SuppressWarnings("unused") + private final static int kPerspective_Shift = 3; + private final static int kRectStaysRect_Shift = 4; + + private int computeTypeMask() { + int mask = 0; + + if (mValues[6] != 0. || mValues[7] != 0. || mValues[8] != 1.) { + mask |= kPerspective_Mask; + } + + if (mValues[2] != 0. || mValues[5] != 0.) { + mask |= kTranslate_Mask; + } + + float m00 = mValues[0]; + float m01 = mValues[1]; + float m10 = mValues[3]; + float m11 = mValues[4]; + + if (m01 != 0. || m10 != 0.) { + mask |= kAffine_Mask; + } + + if (m00 != 1. || m11 != 1.) { + mask |= kScale_Mask; + } + + if ((mask & kPerspective_Mask) == 0) { + // map non-zero to 1 + int im00 = m00 != 0 ? 1 : 0; + int im01 = m01 != 0 ? 1 : 0; + int im10 = m10 != 0 ? 1 : 0; + int im11 = m11 != 0 ? 1 : 0; + + // record if the (p)rimary and (s)econdary diagonals are all 0 or + // all non-zero (answer is 0 or 1) + int dp0 = (im00 | im11) ^ 1; // true if both are 0 + int dp1 = im00 & im11; // true if both are 1 + int ds0 = (im01 | im10) ^ 1; // true if both are 0 + int ds1 = im01 & im10; // true if both are 1 + + // return 1 if primary is 1 and secondary is 0 or + // primary is 0 and secondary is 1 + mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift; + } + + return mask; + } +} |