summaryrefslogtreecommitdiffstats
path: root/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
diff options
context:
space:
mode:
Diffstat (limited to 'tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java')
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java1011
1 files changed, 1011 insertions, 0 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
new file mode 100644
index 0000000..ed2eff2
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -0,0 +1,1011 @@
+/*
+ * Copyright (C) 2010 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 com.android.layoutlib.bridge.DelegateManager;
+
+import android.graphics.Matrix.ScaleToFit;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Matrix
+ *
+ * Through the layoutlib_create tool, the original native methods of Matrix have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Matrix class.
+ *
+ * @see DelegateManager
+ *
+ */
+public final class Matrix_Delegate {
+
+ private final static int MATRIX_SIZE = 9;
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Matrix_Delegate> sManager =
+ new DelegateManager<Matrix_Delegate>();
+
+ // ---- delegate data ----
+ private float mValues[] = new float[MATRIX_SIZE];
+
+ // ---- Public Helper methods ----
+
+ /**
+ * Returns an {@link AffineTransform} matching the given Matrix.
+ */
+ public static AffineTransform getAffineTransform(Matrix m) {
+ Matrix_Delegate delegate = sManager.getDelegate(m.native_instance);
+ if (delegate == null) {
+ assert false;
+ return null;
+ }
+
+ return getAffineTransform(delegate);
+ }
+
+ public static boolean hasPerspective(Matrix m) {
+ Matrix_Delegate delegate = sManager.getDelegate(m.native_instance);
+ if (delegate == null) {
+ assert false;
+ return false;
+ }
+
+ return (delegate.mValues[6] != 0 || delegate.mValues[7] != 0 || delegate.mValues[8] != 1);
+ }
+
+
+ // ---- native methods ----
+
+ public static int native_create(int native_src_or_zero) {
+ // create the delegate
+ Matrix_Delegate newDelegate = new Matrix_Delegate();
+
+ // copy from values if needed.
+ if (native_src_or_zero > 0) {
+ Matrix_Delegate oldDelegate = sManager.getDelegate(native_src_or_zero);
+ if (oldDelegate != null) {
+ System.arraycopy(
+ oldDelegate.mValues, 0,
+ newDelegate.mValues, 0,
+ MATRIX_SIZE);
+ }
+ }
+
+ return sManager.addDelegate(newDelegate);
+ }
+
+ public static boolean native_isIdentity(int native_object) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ for (int i = 0, k = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++, k++) {
+ if (d.mValues[k] != ((i==j) ? 1 : 0)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean native_rectStaysRect(int native_object) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return true;
+ }
+
+ return (d.computeTypeMask() & kRectStaysRect_Mask) != 0;
+ }
+
+ public static void native_reset(int native_object) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ reset(d.mValues);
+ }
+
+ public static void native_set(int native_object, int other) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ Matrix_Delegate src = sManager.getDelegate(other);
+ if (src == null) {
+ assert false;
+ return;
+ }
+
+ System.arraycopy(src.mValues, 0, d.mValues, 0, MATRIX_SIZE);
+ }
+
+ public static void native_setTranslate(int native_object, float dx, float dy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ setTranslate(d.mValues, dx, dy);
+ }
+
+ public static void native_setScale(int native_object, float sx, float sy, float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ d.mValues = getScale(sx, sy, px, py);
+ }
+
+ public static void native_setScale(int native_object, float sx, float sy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ d.mValues[0] = sx;
+ d.mValues[1] = 0;
+ d.mValues[2] = 0;
+ d.mValues[3] = 0;
+ d.mValues[4] = sy;
+ d.mValues[5] = 0;
+ d.mValues[6] = 0;
+ d.mValues[7] = 0;
+ d.mValues[8] = 1;
+ }
+
+ public static void native_setRotate(int native_object, float degrees, float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ d.mValues = getRotate(degrees, px, py);
+ }
+
+ public static void native_setRotate(int native_object, float degrees) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ setRotate(d.mValues, degrees);
+ }
+
+ public static void native_setSinCos(int native_object, float sinValue, float cosValue,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ // TODO: do it in one pass
+
+ // translate so that the pivot is in 0,0
+ setTranslate(d.mValues, -px, -py);
+
+ // scale
+ d.postTransform(getRotate(sinValue, cosValue));
+ // translate back the pivot
+ d.postTransform(getTranslate(px, py));
+ }
+
+ public static void native_setSinCos(int native_object, float sinValue, float cosValue) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ setRotate(d.mValues, sinValue, cosValue);
+ }
+
+ public static void native_setSkew(int native_object, float kx, float ky, float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ d.mValues = getSkew(kx, ky, px, py);
+ }
+
+ public static void native_setSkew(int native_object, float kx, float ky) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ d.mValues[0] = 1;
+ d.mValues[1] = kx;
+ d.mValues[2] = -0;
+ d.mValues[3] = ky;
+ d.mValues[4] = 1;
+ d.mValues[5] = 0;
+ d.mValues[6] = 0;
+ d.mValues[7] = 0;
+ d.mValues[8] = 1;
+ }
+
+ public static boolean native_setConcat(int native_object, int a, int b) {
+ if (a == native_object) {
+ return native_preConcat(native_object, b);
+ } else if (b == native_object) {
+ return native_postConcat(native_object, a);
+ }
+
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ Matrix_Delegate a_mtx = sManager.getDelegate(a);
+ if (a_mtx == null) {
+ assert false;
+ return false;
+ }
+
+ Matrix_Delegate b_mtx = sManager.getDelegate(b);
+ if (b_mtx == null) {
+ assert false;
+ return false;
+ }
+
+ multiply(d.mValues, a_mtx.mValues, b_mtx.mValues);
+
+ return true;
+ }
+
+ public static boolean native_preTranslate(int native_object, float dx, float dy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.preTransform(getTranslate(dx, dy));
+ return true;
+ }
+
+ public static boolean native_preScale(int native_object, float sx, float sy,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.preTransform(getScale(sx, sy, px, py));
+ return true;
+ }
+
+ public static boolean native_preScale(int native_object, float sx, float sy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.preTransform(getScale(sx, sy));
+ return true;
+ }
+
+ public static boolean native_preRotate(int native_object, float degrees, float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.preTransform(getRotate(degrees, px, py));
+ return true;
+ }
+
+ public static boolean native_preRotate(int native_object, float degrees) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ double rad = Math.toRadians(degrees);
+ float sin = (float)Math.sin(rad);
+ float cos = (float)Math.cos(rad);
+
+ d.preTransform(getRotate(sin, cos));
+ return true;
+ }
+
+ public static boolean native_preSkew(int native_object, float kx, float ky,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.preTransform(getSkew(kx, ky, px, py));
+ return true;
+ }
+
+ public static boolean native_preSkew(int native_object, float kx, float ky) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.preTransform(getSkew(kx, ky));
+ return true;
+ }
+
+ public static boolean native_preConcat(int native_object, int other_matrix) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ Matrix_Delegate other = sManager.getDelegate(other_matrix);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.preTransform(other.mValues);
+ return true;
+ }
+
+ public static boolean native_postTranslate(int native_object, float dx, float dy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.postTransform(getTranslate(dx, dy));
+ return true;
+ }
+
+ public static boolean native_postScale(int native_object, float sx, float sy,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.postTransform(getScale(sx, sy, px, py));
+ return true;
+ }
+
+ public static boolean native_postScale(int native_object, float sx, float sy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.postTransform(getScale(sx, sy));
+ return true;
+ }
+
+ public static boolean native_postRotate(int native_object, float degrees, float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.preTransform(getRotate(degrees, px, py));
+ return true;
+ }
+
+ public static boolean native_postRotate(int native_object, float degrees) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.postTransform(getRotate(degrees));
+ return true;
+ }
+
+ public static boolean native_postSkew(int native_object, float kx, float ky,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.postTransform(getSkew(kx, ky, px, py));
+ return true;
+ }
+
+ public static boolean native_postSkew(int native_object, float kx, float ky) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.postTransform(getSkew(kx, ky));
+ return true;
+ }
+
+ public static boolean native_postConcat(int native_object, int other_matrix) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ Matrix_Delegate other = sManager.getDelegate(other_matrix);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ d.postTransform(other.mValues);
+ return true;
+ }
+
+ public static boolean native_setRectToRect(int native_object, RectF src, RectF dst, int stf) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ if (src.isEmpty()) {
+ reset(d.mValues);
+ return false;
+ }
+
+ if (dst.isEmpty()) {
+ d.mValues[0] = d.mValues[1] = d.mValues[2] = d.mValues[3] = d.mValues[4] = d.mValues[5]
+ = d.mValues[6] = d.mValues[7] = 0;
+ d.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.nativeInt) {
+ 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.nativeInt || stf == ScaleToFit.END.nativeInt) {
+ float diff;
+
+ if (xLarger) {
+ diff = dst.width() - src.width() * sy;
+ } else {
+ diff = dst.height() - src.height() * sy;
+ }
+
+ if (stf == ScaleToFit.CENTER.nativeInt) {
+ diff = diff / 2;
+ }
+
+ if (xLarger) {
+ tx += diff;
+ } else {
+ ty += diff;
+ }
+ }
+
+ d.mValues[0] = sx;
+ d.mValues[4] = sy;
+ d.mValues[2] = tx;
+ d.mValues[5] = ty;
+ d.mValues[1] = d.mValues[3] = d.mValues[6] = d.mValues[7] = 0;
+
+ }
+ // shared cleanup
+ d.mValues[8] = 1;
+ return true;
+ }
+
+ public static boolean native_setPolyToPoly(int native_object, float[] src, int srcIndex,
+ float[] dst, int dstIndex, int pointCount) {
+ // FIXME
+ throw new UnsupportedOperationException("NATIVE DELEGATE NEEDED");
+ }
+
+ public static boolean native_invert(int native_object, int inverse) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ Matrix_Delegate inv_mtx = sManager.getDelegate(inverse);
+ if (inv_mtx == null) {
+ assert false;
+ return false;
+ }
+
+
+ try {
+ AffineTransform affineTransform = getAffineTransform(d);
+ AffineTransform inverseTransform = affineTransform.createInverse();
+ inv_mtx.mValues[0] = (float)inverseTransform.getScaleX();
+ inv_mtx.mValues[1] = (float)inverseTransform.getShearX();
+ inv_mtx.mValues[2] = (float)inverseTransform.getTranslateX();
+ inv_mtx.mValues[3] = (float)inverseTransform.getScaleX();
+ inv_mtx.mValues[4] = (float)inverseTransform.getShearY();
+ inv_mtx.mValues[5] = (float)inverseTransform.getTranslateY();
+
+ return true;
+ } catch (NoninvertibleTransformException e) {
+ return false;
+ }
+ }
+
+ public static void native_mapPoints(int native_object, float[] dst, int dstIndex,
+ float[] src, int srcIndex, int ptCount, boolean isPts) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ if (isPts) {
+ d.mapPoints(dst, dstIndex, src, srcIndex, ptCount);
+ } else {
+ // src is vectors
+ // FIXME
+ throw new UnsupportedOperationException("NATIVE DELEGATE NEEDED");
+ }
+ }
+
+ public static boolean native_mapRect(int native_object, RectF dst, RectF src) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return false;
+ }
+
+ // array with 4 corners
+ float[] corners = new float[] {
+ src.left, src.top,
+ src.right, src.top,
+ src.right, src.bottom,
+ src.left, src.bottom,
+ };
+
+ // apply the transform to them.
+ d.mapPoints(corners);
+
+ // now put the result in the rect. We take the min/max of Xs and min/max of Ys
+ dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6]));
+ dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6]));
+
+ dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7]));
+ dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7]));
+
+
+ return (d.computeTypeMask() & kRectStaysRect_Mask) != 0;
+ }
+
+ public static float native_mapRadius(int native_object, float radius) {
+ // FIXME
+ throw new UnsupportedOperationException();
+ }
+
+ public static void native_getValues(int native_object, float[] values) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ System.arraycopy(d.mValues, 0, d.mValues, 0, MATRIX_SIZE);
+ }
+
+ public static void native_setValues(int native_object, float[] values) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ assert false;
+ return;
+ }
+
+ System.arraycopy(values, 0, d.mValues, 0, MATRIX_SIZE);
+ }
+
+ public static boolean native_equals(int native_a, int native_b) {
+ Matrix_Delegate a = sManager.getDelegate(native_a);
+ if (a == null) {
+ assert false;
+ return false;
+ }
+
+ Matrix_Delegate b = sManager.getDelegate(native_b);
+ if (b == null) {
+ assert false;
+ return false;
+ }
+
+ for (int i = 0 ; i < MATRIX_SIZE ; i++) {
+ if (a.mValues[i] != b.mValues[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static void finalizer(int native_instance) {
+ sManager.removeDelegate(native_instance);
+ }
+
+ // ---- Private helper methods ----
+
+ private static AffineTransform getAffineTransform(Matrix_Delegate d) {
+ // the AffineTransform constructor takes the value in a different order
+ // for a matrix [ 0 1 2 ]
+ // [ 3 4 5 ]
+ // the order is 0, 3, 1, 4, 2, 5...
+ return new AffineTransform(
+ d.mValues[0], d.mValues[3], d.mValues[1],
+ d.mValues[4], d.mValues[2], d.mValues[5]);
+ }
+
+
+ /**
+ * Reset a matrix to the identity
+ */
+ private static void reset(float[] mtx) {
+ for (int i = 0, k = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++, k++) {
+ mtx[k] = ((i==j) ? 1 : 0);
+ }
+ }
+ }
+
+ @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;
+ }
+
+ /**
+ * Adds the given transformation to the current Matrix
+ * <p/>This in effect does this = this*matrix
+ * @param matrix
+ */
+ private void postTransform(float[] matrix) {
+ float[] tmp = new float[9];
+ multiply(tmp, mValues, matrix);
+ mValues = tmp;
+ }
+
+ /**
+ * Adds the given transformation to the current Matrix
+ * <p/>This in effect does this = matrix*this
+ * @param matrix
+ */
+ private void preTransform(float[] matrix) {
+ float[] tmp = new float[9];
+ multiply(tmp, matrix, mValues);
+ mValues = tmp;
+ }
+
+ /**
+ * 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
+ */
+
+ private void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
+ int pointCount) {
+ //checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
+
+ float[] tmpDest = dst;
+ boolean inPlace = dst == src;
+ if (inPlace) {
+ tmpDest = new float[dstIndex + pointCount * 2];
+ }
+
+ for (int i = 0 ; i < pointCount ; i++) {
+ // just in case we are doing in place, we better put this in temp vars
+ float x = mValues[0] * src[i + srcIndex] +
+ mValues[1] * src[i + srcIndex + 1] +
+ mValues[2];
+ float y = mValues[3] * src[i + srcIndex] +
+ mValues[4] * src[i + srcIndex + 1] +
+ mValues[5];
+
+ tmpDest[i + dstIndex] = x;
+ tmpDest[i + dstIndex + 1] = y;
+ }
+
+ if (inPlace) {
+ System.arraycopy(tmpDest, dstIndex, dst, dstIndex, pointCount * 2);
+ }
+ }
+
+ /**
+ * 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.
+ */
+
+ private void mapPoints(float[] pts) {
+ mapPoints(pts, 0, pts, 0, pts.length >> 1);
+ }
+
+ /**
+ * multiply two matrices and store them in a 3rd.
+ * <p/>This in effect does dest = a*b
+ * dest cannot be the same as a or b.
+ */
+ private static void multiply(float dest[], float[] a, float[] b) {
+ // first row
+ dest[0] = b[0] * a[0] + b[1] * a[3] + b[2] * a[6];
+ dest[1] = b[0] * a[1] + b[1] * a[4] + b[2] * a[7];
+ dest[2] = b[0] * a[2] + b[1] * a[5] + b[2] * a[8];
+
+ // 2nd row
+ dest[3] = b[3] * a[0] + b[4] * a[3] + b[5] * a[6];
+ dest[4] = b[3] * a[1] + b[4] * a[4] + b[5] * a[7];
+ dest[5] = b[3] * a[2] + b[4] * a[5] + b[5] * a[8];
+
+ // 3rd row
+ dest[6] = b[6] * a[0] + b[7] * a[3] + b[8] * a[6];
+ dest[7] = b[6] * a[1] + b[7] * a[4] + b[8] * a[7];
+ dest[8] = b[6] * a[2] + b[7] * a[5] + b[8] * a[8];
+ }
+
+ /**
+ * Returns a matrix that represents a given translate
+ * @param dx
+ * @param dy
+ * @return
+ */
+ private static float[] getTranslate(float dx, float dy) {
+ return setTranslate(new float[9], dx, dy);
+ }
+
+ private static float[] setTranslate(float[] dest, float dx, float dy) {
+ dest[0] = 1;
+ dest[1] = 0;
+ dest[2] = dx;
+ dest[3] = 0;
+ dest[4] = 1;
+ dest[5] = dy;
+ dest[6] = 0;
+ dest[7] = 0;
+ dest[8] = 1;
+ return dest;
+ }
+
+ private static float[] getScale(float sx, float sy) {
+ return new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 };
+ }
+
+ /**
+ * Returns a matrix that represents the given scale info.
+ * @param sx
+ * @param sy
+ * @param px
+ * @param py
+ */
+ private static float[] getScale(float sx, float sy, float px, float py) {
+ float[] tmp = new float[9];
+ float[] tmp2 = new float[9];
+
+ // TODO: do it in one pass
+
+ // translate tmp so that the pivot is in 0,0
+ setTranslate(tmp, -px, -py);
+
+ // scale into tmp2
+ multiply(tmp2, tmp, getScale(sx, sy));
+
+ // translate back the pivot back into tmp
+ multiply(tmp, tmp2, getTranslate(px, py));
+
+ return tmp;
+ }
+
+
+ private static float[] getRotate(float degrees) {
+ double rad = Math.toRadians(degrees);
+ float sin = (float)Math.sin(rad);
+ float cos = (float)Math.cos(rad);
+
+ return getRotate(sin, cos);
+ }
+
+ private static float[] getRotate(float sin, float cos) {
+ return setRotate(new float[9], sin, cos);
+ }
+
+ private static float[] setRotate(float[] dest, float degrees) {
+ double rad = Math.toRadians(degrees);
+ float sin = (float)Math.sin(rad);
+ float cos = (float)Math.cos(rad);
+
+ return setRotate(dest, sin, cos);
+ }
+
+ private static float[] setRotate(float[] dest, float sin, float cos) {
+ dest[0] = cos;
+ dest[1] = -sin;
+ dest[2] = 0;
+ dest[3] = sin;
+ dest[4] = cos;
+ dest[5] = 0;
+ dest[6] = 0;
+ dest[7] = 0;
+ dest[8] = 1;
+ return dest;
+ }
+
+ private static float[] getRotate(float degrees, float px, float py) {
+ float[] tmp = new float[9];
+ float[] tmp2 = new float[9];
+
+ // TODO: do it in one pass
+
+ // translate so that the pivot is in 0,0
+ setTranslate(tmp, -px, -py);
+
+ // rotate into tmp2
+ double rad = Math.toRadians(degrees);
+ float cos = (float)Math.cos(rad);
+ float sin = (float)Math.sin(rad);
+ multiply(tmp2, tmp, getRotate(sin, cos));
+
+ // translate back the pivot back into tmp
+ multiply(tmp, tmp2, getTranslate(px, py));
+
+ return tmp;
+ }
+
+ private static float[] getSkew(float kx, float ky) {
+ return new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 };
+ }
+
+ private static float[] getSkew(float kx, float ky, float px, float py) {
+ float[] tmp = new float[9];
+ float[] tmp2 = new float[9];
+
+ // TODO: do it in one pass
+
+ // translate so that the pivot is in 0,0
+ setTranslate(tmp, -px, -py);
+
+ // skew into tmp2
+ multiply(tmp2, tmp, new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
+ // translate back the pivot back into tmp
+ multiply(tmp, tmp2, getTranslate(px, py));
+
+ return tmp;
+ }
+
+
+}