Matrix.java revision 3a58ec108bb430b81a328adb2062035f860159b4
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.graphics;
18
19import java.io.PrintWriter;
20
21
22/**
23 * The Matrix class holds a 3x3 matrix for transforming coordinates.
24 * Matrix does not have a constructor, so it must be explicitly initialized
25 * using either reset() - to construct an identity matrix, or one of the set..()
26 * functions (e.g. setTranslate, setRotate, etc.).
27 */
28public class Matrix {
29
30    public static final int MSCALE_X = 0;   //!< use with getValues/setValues
31    public static final int MSKEW_X  = 1;   //!< use with getValues/setValues
32    public static final int MTRANS_X = 2;   //!< use with getValues/setValues
33    public static final int MSKEW_Y  = 3;   //!< use with getValues/setValues
34    public static final int MSCALE_Y = 4;   //!< use with getValues/setValues
35    public static final int MTRANS_Y = 5;   //!< use with getValues/setValues
36    public static final int MPERSP_0 = 6;   //!< use with getValues/setValues
37    public static final int MPERSP_1 = 7;   //!< use with getValues/setValues
38    public static final int MPERSP_2 = 8;   //!< use with getValues/setValues
39
40    /**
41     * @hide
42     */
43    public int native_instance;
44
45    /**
46     * Create an identity matrix
47     */
48    public Matrix() {
49        native_instance = native_create(0);
50    }
51
52    /**
53     * Create a matrix that is a (deep) copy of src
54     * @param src The matrix to copy into this matrix
55     */
56    public Matrix(Matrix src) {
57        native_instance = native_create(src != null ? src.native_instance : 0);
58    }
59
60    /**
61     * Returns true if the matrix is identity.
62     * This maybe faster than testing if (getType() == 0)
63     */
64    public boolean isIdentity() {
65        return native_isIdentity(native_instance);
66    }
67
68    /**
69     * Returns true if will map a rectangle to another rectangle. This can be
70     * true if the matrix is identity, scale-only, or rotates a multiple of 90
71     * degrees.
72     */
73    public boolean rectStaysRect() {
74        return native_rectStaysRect(native_instance);
75    }
76
77    /**
78     * (deep) copy the src matrix into this matrix. If src is null, reset this
79     * matrix to the identity matrix.
80     */
81    public void set(Matrix src) {
82        if (src == null) {
83            reset();
84        } else {
85            native_set(native_instance, src.native_instance);
86        }
87    }
88
89    /** Returns true iff obj is a Matrix and its values equal our values.
90    */
91    public boolean equals(Object obj) {
92        return obj != null &&
93               obj instanceof Matrix &&
94               native_equals(native_instance, ((Matrix)obj).native_instance);
95    }
96
97    /** Set the matrix to identity */
98    public void reset() {
99        native_reset(native_instance);
100    }
101
102    /** Set the matrix to translate by (dx, dy). */
103    public void setTranslate(float dx, float dy) {
104        native_setTranslate(native_instance, dx, dy);
105    }
106
107    /**
108     * Set the matrix to scale by sx and sy, with a pivot point at (px, py).
109     * The pivot point is the coordinate that should remain unchanged by the
110     * specified transformation.
111     */
112    public void setScale(float sx, float sy, float px, float py) {
113        native_setScale(native_instance, sx, sy, px, py);
114    }
115
116    /** Set the matrix to scale by sx and sy. */
117    public void setScale(float sx, float sy) {
118        native_setScale(native_instance, sx, sy);
119    }
120
121    /**
122     * Set the matrix to rotate by the specified number of degrees, with a pivot
123     * point at (px, py). The pivot point is the coordinate that should remain
124     * unchanged by the specified transformation.
125     */
126    public void setRotate(float degrees, float px, float py) {
127        native_setRotate(native_instance, degrees, px, py);
128    }
129
130    /**
131     * Set the matrix to rotate about (0,0) by the specified number of degrees.
132     */
133    public void setRotate(float degrees) {
134        native_setRotate(native_instance, degrees);
135    }
136
137    /**
138     * Set the matrix to rotate by the specified sine and cosine values, with a
139     * pivot point at (px, py). The pivot point is the coordinate that should
140     * remain unchanged by the specified transformation.
141     */
142    public void setSinCos(float sinValue, float cosValue, float px, float py) {
143        native_setSinCos(native_instance, sinValue, cosValue, px, py);
144    }
145
146    /** Set the matrix to rotate by the specified sine and cosine values. */
147    public void setSinCos(float sinValue, float cosValue) {
148        native_setSinCos(native_instance, sinValue, cosValue);
149    }
150
151    /**
152     * Set the matrix to skew by sx and sy, with a pivot point at (px, py).
153     * The pivot point is the coordinate that should remain unchanged by the
154     * specified transformation.
155     */
156    public void setSkew(float kx, float ky, float px, float py) {
157        native_setSkew(native_instance, kx, ky, px, py);
158    }
159
160    /** Set the matrix to skew by sx and sy. */
161    public void setSkew(float kx, float ky) {
162        native_setSkew(native_instance, kx, ky);
163    }
164
165    /**
166     * Set the matrix to the concatenation of the two specified matrices,
167     * returning true if the the result can be represented. Either of the two
168     * matrices may also be the target matrix. this = a * b
169     */
170    public boolean setConcat(Matrix a, Matrix b) {
171        return native_setConcat(native_instance, a.native_instance,
172                                b.native_instance);
173    }
174
175    /**
176     * Preconcats the matrix with the specified translation.
177     * M' = M * T(dx, dy)
178     */
179    public boolean preTranslate(float dx, float dy) {
180        return native_preTranslate(native_instance, dx, dy);
181    }
182
183    /**
184     * Preconcats the matrix with the specified scale.
185     * M' = M * S(sx, sy, px, py)
186     */
187    public boolean preScale(float sx, float sy, float px, float py) {
188        return native_preScale(native_instance, sx, sy, px, py);
189    }
190
191    /**
192     * Preconcats the matrix with the specified scale.
193     * M' = M * S(sx, sy)
194     */
195    public boolean preScale(float sx, float sy) {
196        return native_preScale(native_instance, sx, sy);
197    }
198
199    /**
200     * Preconcats the matrix with the specified rotation.
201     * M' = M * R(degrees, px, py)
202     */
203    public boolean preRotate(float degrees, float px, float py) {
204        return native_preRotate(native_instance, degrees, px, py);
205    }
206
207    /**
208     * Preconcats the matrix with the specified rotation.
209     * M' = M * R(degrees)
210     */
211    public boolean preRotate(float degrees) {
212        return native_preRotate(native_instance, degrees);
213    }
214
215    /**
216     * Preconcats the matrix with the specified skew.
217     * M' = M * K(kx, ky, px, py)
218     */
219    public boolean preSkew(float kx, float ky, float px, float py) {
220        return native_preSkew(native_instance, kx, ky, px, py);
221    }
222
223    /**
224     * Preconcats the matrix with the specified skew.
225     * M' = M * K(kx, ky)
226     */
227    public boolean preSkew(float kx, float ky) {
228        return native_preSkew(native_instance, kx, ky);
229    }
230
231    /**
232     * Preconcats the matrix with the specified matrix.
233     * M' = M * other
234     */
235    public boolean preConcat(Matrix other) {
236        return native_preConcat(native_instance, other.native_instance);
237    }
238
239    /**
240     * Postconcats the matrix with the specified translation.
241     * M' = T(dx, dy) * M
242     */
243    public boolean postTranslate(float dx, float dy) {
244        return native_postTranslate(native_instance, dx, dy);
245    }
246
247    /**
248     * Postconcats the matrix with the specified scale.
249     * M' = S(sx, sy, px, py) * M
250     */
251    public boolean postScale(float sx, float sy, float px, float py) {
252        return native_postScale(native_instance, sx, sy, px, py);
253    }
254
255    /**
256     * Postconcats the matrix with the specified scale.
257     * M' = S(sx, sy) * M
258     */
259    public boolean postScale(float sx, float sy) {
260        return native_postScale(native_instance, sx, sy);
261    }
262
263    /**
264     * Postconcats the matrix with the specified rotation.
265     * M' = R(degrees, px, py) * M
266     */
267    public boolean postRotate(float degrees, float px, float py) {
268        return native_postRotate(native_instance, degrees, px, py);
269    }
270
271    /**
272     * Postconcats the matrix with the specified rotation.
273     * M' = R(degrees) * M
274     */
275    public boolean postRotate(float degrees) {
276        return native_postRotate(native_instance, degrees);
277    }
278
279    /**
280     * Postconcats the matrix with the specified skew.
281     * M' = K(kx, ky, px, py) * M
282     */
283    public boolean postSkew(float kx, float ky, float px, float py) {
284        return native_postSkew(native_instance, kx, ky, px, py);
285    }
286
287    /**
288     * Postconcats the matrix with the specified skew.
289     * M' = K(kx, ky) * M
290     */
291    public boolean postSkew(float kx, float ky) {
292        return native_postSkew(native_instance, kx, ky);
293    }
294
295    /**
296     * Postconcats the matrix with the specified matrix.
297     * M' = other * M
298     */
299    public boolean postConcat(Matrix other) {
300        return native_postConcat(native_instance, other.native_instance);
301    }
302
303    /** Controlls how the src rect should align into the dst rect for
304        setRectToRect().
305    */
306    public enum ScaleToFit {
307        /**
308         * Scale in X and Y independently, so that src matches dst exactly.
309         * This may change the aspect ratio of the src.
310         */
311        FILL    (0),
312        /**
313         * Compute a scale that will maintain the original src aspect ratio,
314         * but will also ensure that src fits entirely inside dst. At least one
315         * axis (X or Y) will fit exactly. START aligns the result to the
316         * left and top edges of dst.
317         */
318        START   (1),
319        /**
320         * Compute a scale that will maintain the original src aspect ratio,
321         * but will also ensure that src fits entirely inside dst. At least one
322         * axis (X or Y) will fit exactly. The result is centered inside dst.
323         */
324        CENTER  (2),
325        /**
326         * Compute a scale that will maintain the original src aspect ratio,
327         * but will also ensure that src fits entirely inside dst. At least one
328         * axis (X or Y) will fit exactly. END aligns the result to the
329         * right and bottom edges of dst.
330         */
331        END     (3);
332
333        // the native values must match those in SkMatrix.h
334        ScaleToFit(int nativeInt) {
335            this.nativeInt = nativeInt;
336        }
337        final int nativeInt;
338    }
339
340    /**
341     * Set the matrix to the scale and translate values that map the source
342     * rectangle to the destination rectangle, returning true if the the result
343     * can be represented.
344     *
345     * @param src the source rectangle to map from.
346     * @param dst the destination rectangle to map to.
347     * @param stf the ScaleToFit option
348     * @return true if the matrix can be represented by the rectangle mapping.
349     */
350    public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) {
351        if (dst == null || src == null) {
352            throw new NullPointerException();
353        }
354        return native_setRectToRect(native_instance, src, dst, stf.nativeInt);
355    }
356
357    // private helper to perform range checks on arrays of "points"
358    private static void checkPointArrays(float[] src, int srcIndex,
359                                         float[] dst, int dstIndex,
360                                         int pointCount) {
361        // check for too-small and too-big indices
362        int srcStop = srcIndex + (pointCount << 1);
363        int dstStop = dstIndex + (pointCount << 1);
364        if ((pointCount | srcIndex | dstIndex | srcStop | dstStop) < 0 ||
365                srcStop > src.length || dstStop > dst.length) {
366            throw new ArrayIndexOutOfBoundsException();
367        }
368    }
369
370    /**
371     * Set the matrix such that the specified src points would map to the
372     * specified dst points. The "points" are represented as an array of floats,
373     * order [x0, y0, x1, y1, ...], where each "point" is 2 float values.
374     *
375     * @param src   The array of src [x,y] pairs (points)
376     * @param srcIndex Index of the first pair of src values
377     * @param dst   The array of dst [x,y] pairs (points)
378     * @param dstIndex Index of the first pair of dst values
379     * @param pointCount The number of pairs/points to be used. Must be [0..4]
380     * @return true if the matrix was set to the specified transformation
381     */
382    public boolean setPolyToPoly(float[] src, int srcIndex,
383                                 float[] dst, int dstIndex,
384                                 int pointCount) {
385        if (pointCount > 4) {
386            throw new IllegalArgumentException();
387        }
388        checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
389        return native_setPolyToPoly(native_instance, src, srcIndex,
390                                    dst, dstIndex, pointCount);
391    }
392
393    /**
394     * If this matrix can be inverted, return true and if inverse is not null,
395     * set inverse to be the inverse of this matrix. If this matrix cannot be
396     * inverted, ignore inverse and return false.
397     */
398    public boolean invert(Matrix inverse) {
399        return native_invert(native_instance, inverse.native_instance);
400    }
401
402    /**
403    * Apply this matrix to the array of 2D points specified by src, and write
404     * the transformed points into the array of points specified by dst. The
405     * two arrays represent their "points" as pairs of floats [x, y].
406     *
407     * @param dst   The array of dst points (x,y pairs)
408     * @param dstIndex The index of the first [x,y] pair of dst floats
409     * @param src   The array of src points (x,y pairs)
410     * @param srcIndex The index of the first [x,y] pair of src floats
411     * @param pointCount The number of points (x,y pairs) to transform
412     */
413    public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
414                          int pointCount) {
415        checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
416        native_mapPoints(native_instance, dst, dstIndex, src, srcIndex,
417                         pointCount, true);
418    }
419
420    /**
421    * Apply this matrix to the array of 2D vectors specified by src, and write
422     * the transformed vectors into the array of vectors specified by dst. The
423     * two arrays represent their "vectors" as pairs of floats [x, y].
424     *
425     * Note: this method does not apply the translation associated with the matrix. Use
426     * {@link Matrix#mapPoints(float[], int, float[], int, int)} if you want the translation
427     * to be applied.
428     *
429     * @param dst   The array of dst vectors (x,y pairs)
430     * @param dstIndex The index of the first [x,y] pair of dst floats
431     * @param src   The array of src vectors (x,y pairs)
432     * @param srcIndex The index of the first [x,y] pair of src floats
433     * @param vectorCount The number of vectors (x,y pairs) to transform
434     */
435    public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex,
436                          int vectorCount) {
437        checkPointArrays(src, srcIndex, dst, dstIndex, vectorCount);
438        native_mapPoints(native_instance, dst, dstIndex, src, srcIndex,
439                         vectorCount, false);
440    }
441
442    /**
443     * Apply this matrix to the array of 2D points specified by src, and write
444     * the transformed points into the array of points specified by dst. The
445     * two arrays represent their "points" as pairs of floats [x, y].
446     *
447     * @param dst   The array of dst points (x,y pairs)
448     * @param src   The array of src points (x,y pairs)
449     */
450    public void mapPoints(float[] dst, float[] src) {
451        if (dst.length != src.length) {
452            throw new ArrayIndexOutOfBoundsException();
453        }
454        mapPoints(dst, 0, src, 0, dst.length >> 1);
455    }
456
457    /**
458     * Apply this matrix to the array of 2D vectors specified by src, and write
459     * the transformed vectors into the array of vectors specified by dst. The
460     * two arrays represent their "vectors" as pairs of floats [x, y].
461     *
462     * Note: this method does not apply the translation associated with the matrix. Use
463     * {@link Matrix#mapPoints(float[], float[])} if you want the translation to be applied.
464     *
465     * @param dst   The array of dst vectors (x,y pairs)
466     * @param src   The array of src vectors (x,y pairs)
467     */
468    public void mapVectors(float[] dst, float[] src) {
469        if (dst.length != src.length) {
470            throw new ArrayIndexOutOfBoundsException();
471        }
472        mapVectors(dst, 0, src, 0, dst.length >> 1);
473    }
474
475    /**
476     * Apply this matrix to the array of 2D points, and write the transformed
477     * points back into the array
478     *
479     * @param pts The array [x0, y0, x1, y1, ...] of points to transform.
480     */
481    public void mapPoints(float[] pts) {
482        mapPoints(pts, 0, pts, 0, pts.length >> 1);
483    }
484
485    /**
486     * Apply this matrix to the array of 2D vectors, and write the transformed
487     * vectors back into the array.
488     *
489     * Note: this method does not apply the translation associated with the matrix. Use
490     * {@link Matrix#mapPoints(float[])} if you want the translation to be applied.
491     *
492     * @param vecs The array [x0, y0, x1, y1, ...] of vectors to transform.
493     */
494    public void mapVectors(float[] vecs) {
495        mapVectors(vecs, 0, vecs, 0, vecs.length >> 1);
496    }
497
498    /**
499     * Apply this matrix to the src rectangle, and write the transformed
500     * rectangle into dst. This is accomplished by transforming the 4 corners of
501     * src, and then setting dst to the bounds of those points.
502     *
503     * @param dst Where the transformed rectangle is written.
504     * @param src The original rectangle to be transformed.
505     * @return the result of calling rectStaysRect()
506     */
507    public boolean mapRect(RectF dst, RectF src) {
508        if (dst == null || src == null) {
509            throw new NullPointerException();
510        }
511        return native_mapRect(native_instance, dst, src);
512    }
513
514    /**
515     * Apply this matrix to the rectangle, and write the transformed rectangle
516     * back into it. This is accomplished by transforming the 4 corners of rect,
517     * and then setting it to the bounds of those points
518     *
519     * @param rect The rectangle to transform.
520     * @return the result of calling rectStaysRect()
521     */
522    public boolean mapRect(RectF rect) {
523        return mapRect(rect, rect);
524    }
525
526    /**
527     * Return the mean radius of a circle after it has been mapped by
528     * this matrix. NOTE: in perspective this value assumes the circle
529     * has its center at the origin.
530     */
531    public float mapRadius(float radius) {
532        return native_mapRadius(native_instance, radius);
533    }
534
535    /** Copy 9 values from the matrix into the array.
536    */
537    public void getValues(float[] values) {
538        if (values.length < 9) {
539            throw new ArrayIndexOutOfBoundsException();
540        }
541        native_getValues(native_instance, values);
542    }
543
544    /** Copy 9 values from the array into the matrix.
545        Depending on the implementation of Matrix, these may be
546        transformed into 16.16 integers in the Matrix, such that
547        a subsequent call to getValues() will not yield exactly
548        the same values.
549    */
550    public void setValues(float[] values) {
551        if (values.length < 9) {
552            throw new ArrayIndexOutOfBoundsException();
553        }
554        native_setValues(native_instance, values);
555    }
556
557    public String toString() {
558        StringBuilder sb = new StringBuilder(64);
559        sb.append("Matrix{");
560        toShortString(sb);
561        sb.append('}');
562        return sb.toString();
563
564    }
565
566    public String toShortString() {
567        StringBuilder sb = new StringBuilder(64);
568        toShortString(sb);
569        return sb.toString();
570    }
571
572    /**
573     * @hide
574     */
575    public void toShortString(StringBuilder sb) {
576        float[] values = new float[9];
577        getValues(values);
578        sb.append('[');
579        sb.append(values[0]); sb.append(", "); sb.append(values[1]); sb.append(", ");
580        sb.append(values[2]); sb.append("][");
581        sb.append(values[3]); sb.append(", "); sb.append(values[4]); sb.append(", ");
582        sb.append(values[5]); sb.append("][");
583        sb.append(values[6]); sb.append(", "); sb.append(values[7]); sb.append(", ");
584        sb.append(values[8]); sb.append(']');
585    }
586
587    /**
588     * Print short string, to optimize dumping.
589     * @hide
590     */
591    public void printShortString(PrintWriter pw) {
592        float[] values = new float[9];
593        getValues(values);
594        pw.print('[');
595        pw.print(values[0]); pw.print(", "); pw.print(values[1]); pw.print(", ");
596                pw.print(values[2]); pw.print("][");
597        pw.print(values[3]); pw.print(", "); pw.print(values[4]); pw.print(", ");
598                pw.print(values[5]); pw.print("][");
599        pw.print(values[6]); pw.print(", "); pw.print(values[7]); pw.print(", ");
600                pw.print(values[8]); pw.print(']');
601
602    }
603
604    protected void finalize() throws Throwable {
605        finalizer(native_instance);
606    }
607
608    /*package*/ final int ni() {
609        return native_instance;
610    }
611
612    private static native int native_create(int native_src_or_zero);
613    private static native boolean native_isIdentity(int native_object);
614    private static native boolean native_rectStaysRect(int native_object);
615    private static native void native_reset(int native_object);
616    private static native void native_set(int native_object, int other);
617    private static native void native_setTranslate(int native_object,
618                                                   float dx, float dy);
619    private static native void native_setScale(int native_object,
620                                        float sx, float sy, float px, float py);
621    private static native void native_setScale(int native_object,
622                                               float sx, float sy);
623    private static native void native_setRotate(int native_object,
624                                            float degrees, float px, float py);
625    private static native void native_setRotate(int native_object,
626                                                float degrees);
627    private static native void native_setSinCos(int native_object,
628                            float sinValue, float cosValue, float px, float py);
629    private static native void native_setSinCos(int native_object,
630                                                float sinValue, float cosValue);
631    private static native void native_setSkew(int native_object,
632                                        float kx, float ky, float px, float py);
633    private static native void native_setSkew(int native_object,
634                                              float kx, float ky);
635    private static native boolean native_setConcat(int native_object,
636                                                   int a, int b);
637    private static native boolean native_preTranslate(int native_object,
638                                                      float dx, float dy);
639    private static native boolean native_preScale(int native_object,
640                                        float sx, float sy, float px, float py);
641    private static native boolean native_preScale(int native_object,
642                                                  float sx, float sy);
643    private static native boolean native_preRotate(int native_object,
644                                            float degrees, float px, float py);
645    private static native boolean native_preRotate(int native_object,
646                                                   float degrees);
647    private static native boolean native_preSkew(int native_object,
648                                        float kx, float ky, float px, float py);
649    private static native boolean native_preSkew(int native_object,
650                                                 float kx, float ky);
651    private static native boolean native_preConcat(int native_object,
652                                                   int other_matrix);
653    private static native boolean native_postTranslate(int native_object,
654                                                       float dx, float dy);
655    private static native boolean native_postScale(int native_object,
656                                        float sx, float sy, float px, float py);
657    private static native boolean native_postScale(int native_object,
658                                                   float sx, float sy);
659    private static native boolean native_postRotate(int native_object,
660                                            float degrees, float px, float py);
661    private static native boolean native_postRotate(int native_object,
662                                                    float degrees);
663    private static native boolean native_postSkew(int native_object,
664                                        float kx, float ky, float px, float py);
665    private static native boolean native_postSkew(int native_object,
666                                                  float kx, float ky);
667    private static native boolean native_postConcat(int native_object,
668                                                    int other_matrix);
669    private static native boolean native_setRectToRect(int native_object,
670                                                RectF src, RectF dst, int stf);
671    private static native boolean native_setPolyToPoly(int native_object,
672        float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount);
673    private static native boolean native_invert(int native_object, int inverse);
674    private static native void native_mapPoints(int native_object,
675                        float[] dst, int dstIndex, float[] src, int srcIndex,
676                        int ptCount, boolean isPts);
677    private static native boolean native_mapRect(int native_object,
678                                                 RectF dst, RectF src);
679    private static native float native_mapRadius(int native_object,
680                                                 float radius);
681    private static native void native_getValues(int native_object,
682                                                float[] values);
683    private static native void native_setValues(int native_object,
684                                                float[] values);
685    private static native boolean native_equals(int native_a, int native_b);
686    private static native void finalizer(int native_instance);
687}
688