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