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