All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.android.graphics.Matrix_Delegate Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * 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.ide.common.rendering.api.ILayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;

import android.graphics.Matrix.ScaleToFit;

import java.awt.geom.AffineTransform;

import libcore.util.NativeAllocationRegistry_Delegate;

/**
 * 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 sManager =
            new DelegateManager(Matrix_Delegate.class);
    private static long sFinalizer = -1;

    // ---- delegate data ----
    private float mValues[] = new float[MATRIX_SIZE];

    // ---- Public Helper methods ----

    public static Matrix_Delegate getDelegate(long native_instance) {
        return sManager.getDelegate(native_instance);
    }

    /**
     * Returns an {@link AffineTransform} matching the given Matrix.
     */
    public static AffineTransform getAffineTransform(Matrix m) {
        Matrix_Delegate delegate = sManager.getDelegate(m.ni());
        if (delegate == null) {
            return null;
        }

        return delegate.getAffineTransform();
    }

    public static boolean hasPerspective(Matrix m) {
        Matrix_Delegate delegate = sManager.getDelegate(m.ni());
        if (delegate == null) {
            return false;
        }

        return delegate.hasPerspective();
    }

    /**
     * Sets the content of the matrix with the content of another matrix.
     */
    public void set(Matrix_Delegate matrix) {
        System.arraycopy(matrix.mValues, 0, mValues, 0, MATRIX_SIZE);
    }

    /**
     * Sets the content of the matrix with the content of another matrix represented as an array
     * of values.
     */
    public void set(float[] values) {
        System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE);
    }

    /**
     * Resets the matrix to be the identity matrix.
     */
    public void reset() {
        reset(mValues);
    }

    /**
     * Returns whether or not the matrix is identity.
     */
    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;
    }

    private static float[] setValues(AffineTransform matrix, float[] values) {
        values[0] = (float) matrix.getScaleX();
        values[1] = (float) matrix.getShearX();
        values[2] = (float) matrix.getTranslateX();
        values[3] = (float) matrix.getShearY();
        values[4] = (float) matrix.getScaleY();
        values[5] = (float) matrix.getTranslateY();
        values[6] = 0.f;
        values[7] = 0.f;
        values[8] = 1.f;

        return values;
    }

    public static float[] makeValues(AffineTransform matrix) {
        return setValues(matrix, new float[MATRIX_SIZE]);
    }

    public static Matrix_Delegate make(AffineTransform matrix) {
        return new Matrix_Delegate(makeValues(matrix));
    }

    public boolean mapRect(RectF dst, RectF src) {
        // 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.
        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 (computeTypeMask() & kRectStaysRect_Mask) != 0;
    }


    /**
     * Returns an {@link AffineTransform} matching the matrix.
     */
    public AffineTransform getAffineTransform() {
        return getAffineTransform(mValues);
    }

    public boolean hasPerspective() {
        return (mValues[6] != 0 || mValues[7] != 0 || mValues[8] != 1);
    }



    // ---- native methods ----

    @LayoutlibDelegate
    /*package*/ static long nCreate(long 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.addNewDelegate(newDelegate);
    }

    @LayoutlibDelegate
    /*package*/ static boolean nIsIdentity(long native_object) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return false;
        }

        return d.isIdentity();
    }

    @LayoutlibDelegate
    /*package*/ static boolean nIsAffine(long native_object) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return true;
        }

        return (d.computeTypeMask() & kPerspective_Mask) == 0;
    }

    @LayoutlibDelegate
    /*package*/ static boolean nRectStaysRect(long native_object) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return true;
        }

        return (d.computeTypeMask() & kRectStaysRect_Mask) != 0;
    }

    @LayoutlibDelegate
    /*package*/ static void nReset(long native_object) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return;
        }

        reset(d.mValues);
    }

    @LayoutlibDelegate
    /*package*/ static void nSet(long native_object, long other) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return;
        }

        Matrix_Delegate src = sManager.getDelegate(other);
        if (src == null) {
            return;
        }

        System.arraycopy(src.mValues, 0, d.mValues, 0, MATRIX_SIZE);
    }

    @LayoutlibDelegate
    /*package*/ static void nSetTranslate(long native_object, float dx, float dy) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return;
        }

        setTranslate(d.mValues, dx, dy);
    }

    @LayoutlibDelegate
    /*package*/ static void nSetScale(long native_object, float sx, float sy,
            float px, float py) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return;
        }

        d.mValues = getScale(sx, sy, px, py);
    }

    @LayoutlibDelegate
    /*package*/ static void nSetScale(long native_object, float sx, float sy) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            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;
    }

    @LayoutlibDelegate
    /*package*/ static void nSetRotate(long native_object, float degrees, float px, float py) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return;
        }

        d.mValues = getRotate(degrees, px, py);
    }

    @LayoutlibDelegate
    /*package*/ static void nSetRotate(long native_object, float degrees) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return;
        }

        setRotate(d.mValues, degrees);
    }

    @LayoutlibDelegate
    /*package*/ static void nSetSinCos(long native_object, float sinValue, float cosValue,
            float px, float py) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            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));
    }

    @LayoutlibDelegate
    /*package*/ static void nSetSinCos(long native_object, float sinValue, float cosValue) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return;
        }

        setRotate(d.mValues, sinValue, cosValue);
    }

    @LayoutlibDelegate
    /*package*/ static void nSetSkew(long native_object, float kx, float ky,
            float px, float py) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return;
        }

        d.mValues = getSkew(kx, ky, px, py);
    }

    @LayoutlibDelegate
    /*package*/ static void nSetSkew(long native_object, float kx, float ky) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            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;
    }

    @LayoutlibDelegate
    /*package*/ static void nSetConcat(long native_object, long a, long b) {
        if (a == native_object) {
            nPreConcat(native_object, b);
            return;
        } else if (b == native_object) {
            nPostConcat(native_object, a);
            return;
        }

        Matrix_Delegate d = sManager.getDelegate(native_object);
        Matrix_Delegate a_mtx = sManager.getDelegate(a);
        Matrix_Delegate b_mtx = sManager.getDelegate(b);
        if (d != null && a_mtx != null && b_mtx != null) {
            multiply(d.mValues, a_mtx.mValues, b_mtx.mValues);
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPreTranslate(long native_object, float dx, float dy) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {
            d.preTransform(getTranslate(dx, dy));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPreScale(long native_object, float sx, float sy,
            float px, float py) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {
            d.preTransform(getScale(sx, sy, px, py));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPreScale(long native_object, float sx, float sy) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {
            d.preTransform(getScale(sx, sy));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPreRotate(long native_object, float degrees,
            float px, float py) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {
            d.preTransform(getRotate(degrees, px, py));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPreRotate(long native_object, float degrees) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {

            double rad = Math.toRadians(degrees);
            float sin = (float) Math.sin(rad);
            float cos = (float) Math.cos(rad);

            d.preTransform(getRotate(sin, cos));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPreSkew(long native_object, float kx, float ky,
            float px, float py) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {
            d.preTransform(getSkew(kx, ky, px, py));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPreSkew(long native_object, float kx, float ky) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {
            d.preTransform(getSkew(kx, ky));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPreConcat(long native_object, long other_matrix) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        Matrix_Delegate other = sManager.getDelegate(other_matrix);
        if (d != null && other != null) {
            d.preTransform(other.mValues);
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPostTranslate(long native_object, float dx, float dy) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {
            d.postTransform(getTranslate(dx, dy));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPostScale(long native_object, float sx, float sy,
            float px, float py) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {
            d.postTransform(getScale(sx, sy, px, py));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPostScale(long native_object, float sx, float sy) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {
            d.postTransform(getScale(sx, sy));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPostRotate(long native_object, float degrees,
            float px, float py) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {
            d.postTransform(getRotate(degrees, px, py));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPostRotate(long native_object, float degrees) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {
            d.postTransform(getRotate(degrees));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPostSkew(long native_object, float kx, float ky,
            float px, float py) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {
            d.postTransform(getSkew(kx, ky, px, py));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPostSkew(long native_object, float kx, float ky) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d != null) {
            d.postTransform(getSkew(kx, ky));
        }
    }

    @LayoutlibDelegate
    /*package*/ static void nPostConcat(long native_object, long other_matrix) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        Matrix_Delegate other = sManager.getDelegate(other_matrix);
        if (d != null && other != null) {
            d.postTransform(other.mValues);
        }
    }

    @LayoutlibDelegate
    /*package*/ static boolean nSetRectToRect(long native_object, RectF src,
            RectF dst, int stf) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            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;
    }

    @LayoutlibDelegate
    /*package*/ static boolean nSetPolyToPoly(long native_object, float[] src, int srcIndex,
            float[] dst, int dstIndex, int pointCount) {
        // FIXME
        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
                "Matrix.setPolyToPoly is not supported.",
                null, null, null /*data*/);
        return false;
    }

    @LayoutlibDelegate
    /*package*/ static boolean nInvert(long native_object, long inverse) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return false;
        }

        Matrix_Delegate inv_mtx = sManager.getDelegate(inverse);
        if (inv_mtx == null) {
            return false;
        }

        float det = d.mValues[0] * (d.mValues[4] * d.mValues[8] - d.mValues[5] * d.mValues[7])
                  + d.mValues[1] * (d.mValues[5] * d.mValues[6] - d.mValues[3] * d.mValues[8])
                  + d.mValues[2] * (d.mValues[3] * d.mValues[7] - d.mValues[4] * d.mValues[6]);

        if (det == 0.0) {
            return false;
        }

        inv_mtx.mValues[0] = (d.mValues[4] * d.mValues[8] - d.mValues[5] * d.mValues[7]) / det;
        inv_mtx.mValues[1] = (d.mValues[2] * d.mValues[7] - d.mValues[1] * d.mValues[8]) / det;
        inv_mtx.mValues[2] = (d.mValues[1] * d.mValues[5] - d.mValues[2] * d.mValues[4]) / det;
        inv_mtx.mValues[3] = (d.mValues[5] * d.mValues[6] - d.mValues[3] * d.mValues[8]) / det;
        inv_mtx.mValues[4] = (d.mValues[0] * d.mValues[8] - d.mValues[2] * d.mValues[6]) / det;
        inv_mtx.mValues[5] = (d.mValues[2] * d.mValues[3] - d.mValues[0] * d.mValues[5]) / det;
        inv_mtx.mValues[6] = (d.mValues[3] * d.mValues[7] - d.mValues[4] * d.mValues[6]) / det;
        inv_mtx.mValues[7] = (d.mValues[1] * d.mValues[6] - d.mValues[0] * d.mValues[7]) / det;
        inv_mtx.mValues[8] = (d.mValues[0] * d.mValues[4] - d.mValues[1] * d.mValues[3]) / det;

        return true;
    }

    @LayoutlibDelegate
    /*package*/ static void nMapPoints(long native_object, float[] dst, int dstIndex,
            float[] src, int srcIndex, int ptCount, boolean isPts) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return;
        }

        if (isPts) {
            d.mapPoints(dst, dstIndex, src, srcIndex, ptCount);
        } else {
            d.mapVectors(dst, dstIndex, src, srcIndex, ptCount);
        }
    }

    @LayoutlibDelegate
    /*package*/ static boolean nMapRect(long native_object, RectF dst, RectF src) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return false;
        }

        return d.mapRect(dst, src);
    }

    @LayoutlibDelegate
    /*package*/ static float nMapRadius(long native_object, float radius) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return 0.f;
        }

        float[] src = new float[] { radius, 0.f, 0.f, radius };
        d.mapVectors(src, 0, src, 0, 2);

        float l1 = (float) Math.hypot(src[0], src[1]);
        float l2 = (float) Math.hypot(src[2], src[3]);
        return (float) Math.sqrt(l1 * l2);
    }

    @LayoutlibDelegate
    /*package*/ static void nGetValues(long native_object, float[] values) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return;
        }

        System.arraycopy(d.mValues, 0, values, 0, MATRIX_SIZE);
    }

    @LayoutlibDelegate
    /*package*/ static void nSetValues(long native_object, float[] values) {
        Matrix_Delegate d = sManager.getDelegate(native_object);
        if (d == null) {
            return;
        }

        System.arraycopy(values, 0, d.mValues, 0, MATRIX_SIZE);
    }

    @LayoutlibDelegate
    /*package*/ static boolean nEquals(long native_a, long native_b) {
        Matrix_Delegate a = sManager.getDelegate(native_a);
        if (a == null) {
            return false;
        }

        Matrix_Delegate b = sManager.getDelegate(native_b);
        if (b == null) {
            return false;
        }

        for (int i = 0 ; i < MATRIX_SIZE ; i++) {
            if (a.mValues[i] != b.mValues[i]) {
                return false;
            }
        }

        return true;
    }

    @LayoutlibDelegate
    /*package*/ static long nGetNativeFinalizer() {
        synchronized (Matrix_Delegate.class) {
            if (sFinalizer == -1) {
                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(sManager::removeJavaReferenceFor);
            }
        }
        return sFinalizer;
    }

    // ---- Private helper methods ----

    /*package*/ static AffineTransform getAffineTransform(float[] matrix) {
        // 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(
                matrix[0], matrix[3], matrix[1],
                matrix[4], matrix[2], matrix[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;
    }

    private Matrix_Delegate() {
        reset();
    }

    private Matrix_Delegate(float[] values) {
        System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE);
    }

    /**
     * Adds the given transformation to the current Matrix
     * 

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 *

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) { final int count = pointCount * 2; float[] tmpDest = dst; boolean inPlace = dst == src; if (inPlace) { tmpDest = new float[dstIndex + count]; } for (int i = 0 ; i < count ; i += 2) { // 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, count); } } /** * 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); } private void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount) { if (hasPerspective()) { // transform the (0,0) point float[] origin = new float[] { 0.f, 0.f}; mapPoints(origin); // translate the vector data as points mapPoints(dst, dstIndex, src, srcIndex, ptCount); // then substract the transformed origin. final int count = ptCount * 2; for (int i = 0 ; i < count ; i += 2) { dst[dstIndex + i] = dst[dstIndex + i] - origin[0]; dst[dstIndex + i + 1] = dst[dstIndex + i + 1] - origin[1]; } } else { // make a copy of the matrix Matrix_Delegate copy = new Matrix_Delegate(mValues); // remove the translation setTranslate(copy.mValues, 0, 0); // map the content as points. copy.mapPoints(dst, dstIndex, src, srcIndex, ptCount); } } /** * multiply two matrices and store them in a 3rd. *

This in effect does dest = a*b * dest cannot be the same as a or b. */ /*package*/ 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 */ /*package*/ static float[] getTranslate(float dx, float dy) { return setTranslate(new float[9], dx, dy); } /*package*/ 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; } /*package*/ 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 */ /*package*/ 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; } /*package*/ 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); } /*package*/ static float[] getRotate(float sin, float cos) { return setRotate(new float[9], sin, cos); } /*package*/ 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); } /*package*/ 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; } /*package*/ 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; } /*package*/ static float[] getSkew(float kx, float ky) { return new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 }; } /*package*/ 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; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy