957 lines
32 KiB
Java
957 lines
32 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2006 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 android.annotation.NonNull;
|
||
|
|
||
|
import dalvik.annotation.optimization.CriticalNative;
|
||
|
import dalvik.annotation.optimization.FastNative;
|
||
|
|
||
|
import libcore.util.NativeAllocationRegistry;
|
||
|
|
||
|
import java.io.PrintWriter;
|
||
|
|
||
|
/**
|
||
|
* The Matrix class holds a 3x3 matrix for transforming coordinates.
|
||
|
*/
|
||
|
@android.ravenwood.annotation.RavenwoodKeepWholeClass
|
||
|
@android.ravenwood.annotation.RavenwoodClassLoadHook(
|
||
|
android.ravenwood.annotation.RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK)
|
||
|
public class Matrix {
|
||
|
|
||
|
public static final int MSCALE_X = 0; //!< use with getValues/setValues
|
||
|
public static final int MSKEW_X = 1; //!< use with getValues/setValues
|
||
|
public static final int MTRANS_X = 2; //!< use with getValues/setValues
|
||
|
public static final int MSKEW_Y = 3; //!< use with getValues/setValues
|
||
|
public static final int MSCALE_Y = 4; //!< use with getValues/setValues
|
||
|
public static final int MTRANS_Y = 5; //!< use with getValues/setValues
|
||
|
public static final int MPERSP_0 = 6; //!< use with getValues/setValues
|
||
|
public static final int MPERSP_1 = 7; //!< use with getValues/setValues
|
||
|
public static final int MPERSP_2 = 8; //!< use with getValues/setValues
|
||
|
|
||
|
/**
|
||
|
* The identity matrix. Multiplying by another matrix {@code M} returns {@code M}. This matrix
|
||
|
* is immutable, and attempting to modify it will throw an {@link IllegalStateException}.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public final static Matrix IDENTITY_MATRIX = new Matrix() {
|
||
|
void oops() {
|
||
|
throw new IllegalStateException("Matrix can not be modified");
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void set(Matrix src) {
|
||
|
oops();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void reset() {
|
||
|
oops();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setTranslate(float dx, float dy) {
|
||
|
oops();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setScale(float sx, float sy, float px, float py) {
|
||
|
oops();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setScale(float sx, float sy) {
|
||
|
oops();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setRotate(float degrees, float px, float py) {
|
||
|
oops();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setRotate(float degrees) {
|
||
|
oops();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setSinCos(float sinValue, float cosValue, float px, float py) {
|
||
|
oops();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setSinCos(float sinValue, float cosValue) {
|
||
|
oops();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setSkew(float kx, float ky, float px, float py) {
|
||
|
oops();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setSkew(float kx, float ky) {
|
||
|
oops();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean setConcat(Matrix a, Matrix b) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean preTranslate(float dx, float dy) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean preScale(float sx, float sy, float px, float py) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean preScale(float sx, float sy) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean preRotate(float degrees, float px, float py) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean preRotate(float degrees) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean preSkew(float kx, float ky, float px, float py) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean preSkew(float kx, float ky) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean preConcat(Matrix other) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean postTranslate(float dx, float dy) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean postScale(float sx, float sy, float px, float py) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean postScale(float sx, float sy) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean postRotate(float degrees, float px, float py) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean postRotate(float degrees) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean postSkew(float kx, float ky, float px, float py) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean postSkew(float kx, float ky) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean postConcat(Matrix other) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex,
|
||
|
int pointCount) {
|
||
|
oops();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setValues(float[] values) {
|
||
|
oops();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
private static class NoImagePreloadHolder {
|
||
|
public static final NativeAllocationRegistry sRegistry =
|
||
|
NativeAllocationRegistry.createMalloced(
|
||
|
Matrix.class.getClassLoader(), ExtraNatives.nGetNativeFinalizer());
|
||
|
}
|
||
|
|
||
|
private final long native_instance;
|
||
|
|
||
|
/**
|
||
|
* Create an identity matrix
|
||
|
*/
|
||
|
public Matrix() {
|
||
|
native_instance = ExtraNatives.nCreate(0);
|
||
|
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a matrix that is a (deep) copy of src
|
||
|
*
|
||
|
* @param src The matrix to copy into this matrix
|
||
|
*/
|
||
|
public Matrix(Matrix src) {
|
||
|
native_instance = ExtraNatives.nCreate(src != null ? src.native_instance : 0);
|
||
|
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the matrix is identity. This maybe faster than testing if (getType() == 0)
|
||
|
*/
|
||
|
public boolean isIdentity() {
|
||
|
return nIsIdentity(native_instance);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets whether this matrix is affine. An affine matrix preserves straight lines and has no
|
||
|
* perspective.
|
||
|
*
|
||
|
* @return Whether the matrix is affine.
|
||
|
*/
|
||
|
public boolean isAffine() {
|
||
|
return nIsAffine(native_instance);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*/
|
||
|
public boolean rectStaysRect() {
|
||
|
return nRectStaysRect(native_instance);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* (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 {
|
||
|
nSet(native_instance, src.native_instance);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true iff obj is a Matrix and its values equal our values.
|
||
|
*/
|
||
|
@Override
|
||
|
public boolean equals(Object obj) {
|
||
|
// if (obj == this) return true; -- NaN value would mean matrix != itself
|
||
|
if (!(obj instanceof Matrix)) {
|
||
|
return false;
|
||
|
}
|
||
|
return nEquals(native_instance, ((Matrix) obj).native_instance);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int hashCode() {
|
||
|
// This should generate the hash code by performing some arithmetic operation on all
|
||
|
// the matrix elements -- our equals() does an element-by-element comparison, and we
|
||
|
// need to ensure that the hash code for two equal objects is the same. We're not
|
||
|
// really using this at the moment, so we take the easy way out.
|
||
|
return 44;
|
||
|
}
|
||
|
|
||
|
/** Set the matrix to identity */
|
||
|
public void reset() {
|
||
|
nReset(native_instance);
|
||
|
}
|
||
|
|
||
|
/** Set the matrix to translate by (dx, dy). */
|
||
|
public void setTranslate(float dx, float dy) {
|
||
|
nSetTranslate(native_instance, dx, dy);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*/
|
||
|
public void setScale(float sx, float sy, float px, float py) {
|
||
|
nSetScale(native_instance, sx, sy, px, py);
|
||
|
}
|
||
|
|
||
|
/** Set the matrix to scale by sx and sy. */
|
||
|
public void setScale(float sx, float sy) {
|
||
|
nSetScale(native_instance, sx, sy);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*/
|
||
|
public void setRotate(float degrees, float px, float py) {
|
||
|
nSetRotate(native_instance, degrees, px, py);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the matrix to rotate about (0,0) by the specified number of degrees.
|
||
|
*/
|
||
|
public void setRotate(float degrees) {
|
||
|
nSetRotate(native_instance, degrees);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*/
|
||
|
public void setSinCos(float sinValue, float cosValue, float px, float py) {
|
||
|
nSetSinCos(native_instance, sinValue, cosValue, px, py);
|
||
|
}
|
||
|
|
||
|
/** Set the matrix to rotate by the specified sine and cosine values. */
|
||
|
public void setSinCos(float sinValue, float cosValue) {
|
||
|
nSetSinCos(native_instance, sinValue, cosValue);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*/
|
||
|
public void setSkew(float kx, float ky, float px, float py) {
|
||
|
nSetSkew(native_instance, kx, ky, px, py);
|
||
|
}
|
||
|
|
||
|
/** Set the matrix to skew by sx and sy. */
|
||
|
public void setSkew(float kx, float ky) {
|
||
|
nSetSkew(native_instance, kx, ky);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the matrix to the concatenation of the two specified matrices and return true.
|
||
|
* <p>
|
||
|
* Either of the two matrices may also be the target matrix, that is
|
||
|
* <code>matrixA.setConcat(matrixA, matrixB);</code> is valid.
|
||
|
* </p>
|
||
|
* <p class="note">
|
||
|
* In {@link android.os.Build.VERSION_CODES#GINGERBREAD_MR1} and below, this function returns
|
||
|
* true only if the result can be represented. In
|
||
|
* {@link android.os.Build.VERSION_CODES#HONEYCOMB} and above, it always returns true.
|
||
|
* </p>
|
||
|
*/
|
||
|
public boolean setConcat(Matrix a, Matrix b) {
|
||
|
nSetConcat(native_instance, a.native_instance, b.native_instance);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Preconcats the matrix with the specified translation. M' = M * T(dx, dy)
|
||
|
*/
|
||
|
public boolean preTranslate(float dx, float dy) {
|
||
|
nPreTranslate(native_instance, dx, dy);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Preconcats the matrix with the specified scale. M' = M * S(sx, sy, px, py)
|
||
|
*/
|
||
|
public boolean preScale(float sx, float sy, float px, float py) {
|
||
|
nPreScale(native_instance, sx, sy, px, py);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Preconcats the matrix with the specified scale. M' = M * S(sx, sy)
|
||
|
*/
|
||
|
public boolean preScale(float sx, float sy) {
|
||
|
nPreScale(native_instance, sx, sy);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Preconcats the matrix with the specified rotation. M' = M * R(degrees, px, py)
|
||
|
*/
|
||
|
public boolean preRotate(float degrees, float px, float py) {
|
||
|
nPreRotate(native_instance, degrees, px, py);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Preconcats the matrix with the specified rotation. M' = M * R(degrees)
|
||
|
*/
|
||
|
public boolean preRotate(float degrees) {
|
||
|
nPreRotate(native_instance, degrees);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Preconcats the matrix with the specified skew. M' = M * K(kx, ky, px, py)
|
||
|
*/
|
||
|
public boolean preSkew(float kx, float ky, float px, float py) {
|
||
|
nPreSkew(native_instance, kx, ky, px, py);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Preconcats the matrix with the specified skew. M' = M * K(kx, ky)
|
||
|
*/
|
||
|
public boolean preSkew(float kx, float ky) {
|
||
|
nPreSkew(native_instance, kx, ky);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Preconcats the matrix with the specified matrix. M' = M * other
|
||
|
*/
|
||
|
public boolean preConcat(Matrix other) {
|
||
|
nPreConcat(native_instance, other.native_instance);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Postconcats the matrix with the specified translation. M' = T(dx, dy) * M
|
||
|
*/
|
||
|
public boolean postTranslate(float dx, float dy) {
|
||
|
nPostTranslate(native_instance, dx, dy);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Postconcats the matrix with the specified scale. M' = S(sx, sy, px, py) * M
|
||
|
*/
|
||
|
public boolean postScale(float sx, float sy, float px, float py) {
|
||
|
nPostScale(native_instance, sx, sy, px, py);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Postconcats the matrix with the specified scale. M' = S(sx, sy) * M
|
||
|
*/
|
||
|
public boolean postScale(float sx, float sy) {
|
||
|
nPostScale(native_instance, sx, sy);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Postconcats the matrix with the specified rotation. M' = R(degrees, px, py) * M
|
||
|
*/
|
||
|
public boolean postRotate(float degrees, float px, float py) {
|
||
|
nPostRotate(native_instance, degrees, px, py);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Postconcats the matrix with the specified rotation. M' = R(degrees) * M
|
||
|
*/
|
||
|
public boolean postRotate(float degrees) {
|
||
|
nPostRotate(native_instance, degrees);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Postconcats the matrix with the specified skew. M' = K(kx, ky, px, py) * M
|
||
|
*/
|
||
|
public boolean postSkew(float kx, float ky, float px, float py) {
|
||
|
nPostSkew(native_instance, kx, ky, px, py);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Postconcats the matrix with the specified skew. M' = K(kx, ky) * M
|
||
|
*/
|
||
|
public boolean postSkew(float kx, float ky) {
|
||
|
nPostSkew(native_instance, kx, ky);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Postconcats the matrix with the specified matrix. M' = other * M
|
||
|
*/
|
||
|
public boolean postConcat(Matrix other) {
|
||
|
nPostConcat(native_instance, other.native_instance);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Controls 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();
|
||
|
}
|
||
|
return nSetRectToRect(native_instance, src, dst, stf.nativeInt);
|
||
|
}
|
||
|
|
||
|
// private helper to perform range checks on arrays of "points"
|
||
|
private static void checkPointArrays(float[] src, int srcIndex,
|
||
|
float[] dst, int dstIndex,
|
||
|
int pointCount) {
|
||
|
// check for too-small and too-big indices
|
||
|
int srcStop = srcIndex + (pointCount << 1);
|
||
|
int dstStop = dstIndex + (pointCount << 1);
|
||
|
if ((pointCount | srcIndex | dstIndex | srcStop | dstStop) < 0 ||
|
||
|
srcStop > src.length || dstStop > dst.length) {
|
||
|
throw new ArrayIndexOutOfBoundsException();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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
|
||
|
*/
|
||
|
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);
|
||
|
return nSetPolyToPoly(native_instance, src, srcIndex,
|
||
|
dst, dstIndex, pointCount);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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) {
|
||
|
return nInvert(native_instance, inverse.native_instance);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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
|
||
|
*/
|
||
|
public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
|
||
|
int pointCount) {
|
||
|
checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
|
||
|
nMapPoints(native_instance, dst, dstIndex, src, srcIndex,
|
||
|
pointCount, true);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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]. Note: this method does not apply the translation associated with
|
||
|
* the matrix. Use {@link Matrix#mapPoints(float[], int, float[], int, int)} if you want the
|
||
|
* translation to be applied.
|
||
|
*
|
||
|
* @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
|
||
|
*/
|
||
|
public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex,
|
||
|
int vectorCount) {
|
||
|
checkPointArrays(src, srcIndex, dst, dstIndex, vectorCount);
|
||
|
nMapPoints(native_instance, dst, dstIndex, src, srcIndex,
|
||
|
vectorCount, false);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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)
|
||
|
*/
|
||
|
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]. Note: this method does not apply the translation associated with
|
||
|
* the matrix. Use {@link Matrix#mapPoints(float[], float[])} if you want the translation to be
|
||
|
* applied.
|
||
|
*
|
||
|
* @param dst The array of dst vectors (x,y pairs)
|
||
|
* @param src The array of src vectors (x,y pairs)
|
||
|
*/
|
||
|
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.
|
||
|
*/
|
||
|
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. Note: this method does not apply the translation associated with the matrix. Use
|
||
|
* {@link Matrix#mapPoints(float[])} if you want the translation to be applied.
|
||
|
*
|
||
|
* @param vecs The array [x0, y0, x1, y1, ...] of vectors to transform.
|
||
|
*/
|
||
|
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()
|
||
|
*/
|
||
|
public boolean mapRect(RectF dst, RectF src) {
|
||
|
if (dst == null || src == null) {
|
||
|
throw new NullPointerException();
|
||
|
}
|
||
|
return nMapRect(native_instance, dst, src);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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()
|
||
|
*/
|
||
|
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.
|
||
|
*/
|
||
|
public float mapRadius(float radius) {
|
||
|
return nMapRadius(native_instance, radius);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Copy 9 values from the matrix into the array.
|
||
|
*/
|
||
|
public void getValues(float[] values) {
|
||
|
if (values.length < 9) {
|
||
|
throw new ArrayIndexOutOfBoundsException();
|
||
|
}
|
||
|
nGetValues(native_instance, values);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*/
|
||
|
public void setValues(float[] values) {
|
||
|
if (values.length < 9) {
|
||
|
throw new ArrayIndexOutOfBoundsException();
|
||
|
}
|
||
|
nSetValues(native_instance, values);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public String toString() {
|
||
|
StringBuilder sb = new StringBuilder(64);
|
||
|
sb.append("Matrix{");
|
||
|
toShortString(sb);
|
||
|
sb.append('}');
|
||
|
return sb.toString();
|
||
|
|
||
|
}
|
||
|
|
||
|
public String toShortString() {
|
||
|
StringBuilder sb = new StringBuilder(64);
|
||
|
toShortString(sb);
|
||
|
return sb.toString();
|
||
|
}
|
||
|
|
||
|
private void toShortString(StringBuilder sb) {
|
||
|
float[] values = new float[9];
|
||
|
getValues(values);
|
||
|
sb.append('[');
|
||
|
sb.append(values[0]);
|
||
|
sb.append(", ");
|
||
|
sb.append(values[1]);
|
||
|
sb.append(", ");
|
||
|
sb.append(values[2]);
|
||
|
sb.append("][");
|
||
|
sb.append(values[3]);
|
||
|
sb.append(", ");
|
||
|
sb.append(values[4]);
|
||
|
sb.append(", ");
|
||
|
sb.append(values[5]);
|
||
|
sb.append("][");
|
||
|
sb.append(values[6]);
|
||
|
sb.append(", ");
|
||
|
sb.append(values[7]);
|
||
|
sb.append(", ");
|
||
|
sb.append(values[8]);
|
||
|
sb.append(']');
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Dumps a human-readable shortened string of the matrix into the given
|
||
|
* stream
|
||
|
*
|
||
|
* @param pw The {@link PrintWriter} into which the string representation of
|
||
|
* the matrix will be written.
|
||
|
*/
|
||
|
public final void dump(@NonNull PrintWriter pw) {
|
||
|
float[] values = new float[9];
|
||
|
getValues(values);
|
||
|
pw.print('[');
|
||
|
pw.print(values[0]);
|
||
|
pw.print(", ");
|
||
|
pw.print(values[1]);
|
||
|
pw.print(", ");
|
||
|
pw.print(values[2]);
|
||
|
pw.print("][");
|
||
|
pw.print(values[3]);
|
||
|
pw.print(", ");
|
||
|
pw.print(values[4]);
|
||
|
pw.print(", ");
|
||
|
pw.print(values[5]);
|
||
|
pw.print("][");
|
||
|
pw.print(values[6]);
|
||
|
pw.print(", ");
|
||
|
pw.print(values[7]);
|
||
|
pw.print(", ");
|
||
|
pw.print(values[8]);
|
||
|
pw.print(']');
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @hide For access by android.graphics.pdf but must not be accessed outside the module.
|
||
|
* FIXME: PdfRenderer accesses it, but the plan is to leave it out of the module.
|
||
|
*/
|
||
|
public final long ni() {
|
||
|
return native_instance;
|
||
|
}
|
||
|
|
||
|
// ------------------ Fast JNI ------------------------
|
||
|
|
||
|
@FastNative
|
||
|
private static native boolean nSetRectToRect(long nObject,
|
||
|
RectF src, RectF dst, int stf);
|
||
|
@FastNative
|
||
|
private static native boolean nSetPolyToPoly(long nObject,
|
||
|
float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount);
|
||
|
@FastNative
|
||
|
private static native void nMapPoints(long nObject,
|
||
|
float[] dst, int dstIndex, float[] src, int srcIndex,
|
||
|
int ptCount, boolean isPts);
|
||
|
@FastNative
|
||
|
private static native boolean nMapRect(long nObject, RectF dst, RectF src);
|
||
|
@FastNative
|
||
|
private static native void nGetValues(long nObject, float[] values);
|
||
|
@FastNative
|
||
|
private static native void nSetValues(long nObject, float[] values);
|
||
|
|
||
|
|
||
|
// ------------------ Critical JNI ------------------------
|
||
|
|
||
|
@CriticalNative
|
||
|
private static native boolean nIsIdentity(long nObject);
|
||
|
@CriticalNative
|
||
|
private static native boolean nIsAffine(long nObject);
|
||
|
@CriticalNative
|
||
|
private static native boolean nRectStaysRect(long nObject);
|
||
|
@CriticalNative
|
||
|
private static native void nReset(long nObject);
|
||
|
@CriticalNative
|
||
|
private static native void nSet(long nObject, long nOther);
|
||
|
@CriticalNative
|
||
|
private static native void nSetTranslate(long nObject, float dx, float dy);
|
||
|
@CriticalNative
|
||
|
private static native void nSetScale(long nObject, float sx, float sy, float px, float py);
|
||
|
@CriticalNative
|
||
|
private static native void nSetScale(long nObject, float sx, float sy);
|
||
|
@CriticalNative
|
||
|
private static native void nSetRotate(long nObject, float degrees, float px, float py);
|
||
|
@CriticalNative
|
||
|
private static native void nSetRotate(long nObject, float degrees);
|
||
|
@CriticalNative
|
||
|
private static native void nSetSinCos(long nObject, float sinValue, float cosValue,
|
||
|
float px, float py);
|
||
|
@CriticalNative
|
||
|
private static native void nSetSinCos(long nObject, float sinValue, float cosValue);
|
||
|
@CriticalNative
|
||
|
private static native void nSetSkew(long nObject, float kx, float ky, float px, float py);
|
||
|
@CriticalNative
|
||
|
private static native void nSetSkew(long nObject, float kx, float ky);
|
||
|
@CriticalNative
|
||
|
private static native void nSetConcat(long nObject, long nA, long nB);
|
||
|
@CriticalNative
|
||
|
private static native void nPreTranslate(long nObject, float dx, float dy);
|
||
|
@CriticalNative
|
||
|
private static native void nPreScale(long nObject, float sx, float sy, float px, float py);
|
||
|
@CriticalNative
|
||
|
private static native void nPreScale(long nObject, float sx, float sy);
|
||
|
@CriticalNative
|
||
|
private static native void nPreRotate(long nObject, float degrees, float px, float py);
|
||
|
@CriticalNative
|
||
|
private static native void nPreRotate(long nObject, float degrees);
|
||
|
@CriticalNative
|
||
|
private static native void nPreSkew(long nObject, float kx, float ky, float px, float py);
|
||
|
@CriticalNative
|
||
|
private static native void nPreSkew(long nObject, float kx, float ky);
|
||
|
@CriticalNative
|
||
|
private static native void nPreConcat(long nObject, long nOther_matrix);
|
||
|
@CriticalNative
|
||
|
private static native void nPostTranslate(long nObject, float dx, float dy);
|
||
|
@CriticalNative
|
||
|
private static native void nPostScale(long nObject, float sx, float sy, float px, float py);
|
||
|
@CriticalNative
|
||
|
private static native void nPostScale(long nObject, float sx, float sy);
|
||
|
@CriticalNative
|
||
|
private static native void nPostRotate(long nObject, float degrees, float px, float py);
|
||
|
@CriticalNative
|
||
|
private static native void nPostRotate(long nObject, float degrees);
|
||
|
@CriticalNative
|
||
|
private static native void nPostSkew(long nObject, float kx, float ky, float px, float py);
|
||
|
@CriticalNative
|
||
|
private static native void nPostSkew(long nObject, float kx, float ky);
|
||
|
@CriticalNative
|
||
|
private static native void nPostConcat(long nObject, long nOther_matrix);
|
||
|
@CriticalNative
|
||
|
private static native boolean nInvert(long nObject, long nInverse);
|
||
|
@CriticalNative
|
||
|
private static native float nMapRadius(long nObject, float radius);
|
||
|
@CriticalNative
|
||
|
private static native boolean nEquals(long nA, long nB);
|
||
|
|
||
|
/**
|
||
|
* Due to b/337329128, native methods that are called by the static initializers cannot be
|
||
|
* in the same class when running on a host side JVM (such as on Ravenwood and Android Studio).
|
||
|
*
|
||
|
* There are two methods that are called by the static initializers (either directly or
|
||
|
* indirectly) in this class, namely nCreate() and nGetNativeFinalizer(). On Ravenwood
|
||
|
* these methods can't be on the Matrix class itself, so we use a nested class to host them.
|
||
|
*/
|
||
|
private static class ExtraNatives {
|
||
|
static native long nCreate(long nSrc_or_zero);
|
||
|
static native long nGetNativeFinalizer();
|
||
|
}
|
||
|
}
|