summaryrefslogtreecommitdiff
path: root/tools/layoutlib/bridge/src/android/graphics/Matrix.java
diff options
context:
space:
mode:
Diffstat (limited to 'tools/layoutlib/bridge/src/android/graphics/Matrix.java')
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Matrix.java984
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;
+ }
+}