1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/*
2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright (C) 2011 The Android Open Source Project
3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Licensed under the Apache License, Version 2.0 (the "License");
5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * you may not use this file except in compliance with the License.
6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You may obtain a copy of the License at
7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *      http://www.apache.org/licenses/LICENSE-2.0
9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software
11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * distributed under the License is distributed on an "AS IS" BASIS,
12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * See the License for the specific language governing permissions and
14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * limitations under the License.
15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspackage androidx.media.filterfw.geometry;
18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.annotation.SuppressLint;
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.Matrix;
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.PointF;
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.RectF;
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/**
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * The Quad class specifies a (possibly affine transformed) rectangle.
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * A Quad instance holds 4 points that define its shape. The points may represent any rectangle that
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * has been transformed by an affine transformation. This means that Quads can represent translated,
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * scaled, rotated and sheared/skewed rectangles. As such, Quads are restricted to the set of
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * parallelograms.
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Each point in the Quad represents a specific corner of the Quad. These are top-left, top-right,
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * bottom-left, and bottom-right. These labels allow mapping a transformed Quad back to an up-right
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Quad, with the point-to-point mapping well-defined. They do not necessarily indicate that e.g.
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * the top-left corner is actually at the top-left of coordinate space.
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks@SuppressLint("FloatMath")
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic class Quad {
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final PointF mTopLeft;
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final PointF mTopRight;
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final PointF mBottomLeft;
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private final PointF mBottomRight;
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the unit Quad.
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The unit Quad has its top-left point at (0, 0) and bottom-right point at (1, 1).
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the unit Quad.
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static Quad unitQuad() {
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new Quad(0f, 0f, 1f, 0f, 0f, 1f, 1f, 1f);
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Return a Quad from the specified rectangle.
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param rect a RectF instance.
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return Quad that represents the passed rectangle.
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static Quad fromRect(RectF rect) {
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new Quad(new PointF(rect.left, rect.top),
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        new PointF(rect.right, rect.top),
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        new PointF(rect.left, rect.bottom),
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        new PointF(rect.right, rect.bottom));
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Return a Quad from the specified rectangle coordinates.
69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param x the top left x coordinate
71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param y the top left y coordinate
72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param width the width of the rectangle
73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param height the height of the rectangle
74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return Quad that represents the passed rectangle.
75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static Quad fromRect(float x, float y, float width, float height) {
77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new Quad(new PointF(x, y),
78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        new PointF(x + width, y),
79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        new PointF(x, y + height),
80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        new PointF(x + width, y + height));
81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Return a Quad that spans the specified points and height.
85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The returned Quad has the specified top-left and top-right points, and the specified height
87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * while maintaining 90 degree angles on all 4 corners.
88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param topLeft the top-left of the quad
90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param topRight the top-right of the quad
91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param height the height of the quad
92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return Quad that spans the specified points and height.
93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static Quad fromLineAndHeight(PointF topLeft, PointF topRight, float height) {
95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        PointF dp = new PointF(topRight.x - topLeft.x, topRight.y - topLeft.y);
96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float len = dp.length();
97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        PointF np = new PointF(height * (dp.y / len), height * (dp.x / len));
98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        PointF p2 = new PointF(topLeft.x - np.x, topLeft.y + np.y);
99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        PointF p3 = new PointF(topRight.x - np.x, topRight.y + np.y);
100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new Quad(topLeft, topRight, p2, p3);
101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Return a Quad that represents the specified rotated rectangle.
105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The Quad is rotated counter-clockwise around its centroid.
107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param rect the source rectangle
109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param angle the angle to rotate the source rectangle in radians
110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the Quad representing the source rectangle rotated by the given angle.
111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static Quad fromRotatedRect(RectF rect, float angle) {
113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return Quad.fromRect(rect).rotated(angle);
114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Return a Quad that represents the specified transformed rectangle.
118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The transform is applied by multiplying each point (x, y, 1) by the matrix.
120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param rect the source rectangle
122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param matrix the transformation matrix
123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the Quad representing the source rectangle transformed by the matrix
124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static Quad fromTransformedRect(RectF rect, Matrix matrix) {
126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return Quad.fromRect(rect).transformed(matrix);
127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the transformation matrix to transform the source Quad to the target Quad.
131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param source the source quad
133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param target the target quad
134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the transformation matrix to map source to target.
135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public static Matrix getTransform(Quad source, Quad target) {
137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // We only use the first 3 points as they sufficiently specify the transform
138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        Matrix transform = new Matrix();
139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        transform.setPolyToPoly(source.asCoords(), 0, target.asCoords(), 0, 3);
140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return transform;
141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The top-left point of the Quad.
145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return top-left point of the Quad.
146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public PointF topLeft() {
148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mTopLeft;
149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The top-right point of the Quad.
153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return top-right point of the Quad.
154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public PointF topRight() {
156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mTopRight;
157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The bottom-left point of the Quad.
161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return bottom-left point of the Quad.
162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public PointF bottomLeft() {
164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mBottomLeft;
165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The bottom-right point of the Quad.
169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return bottom-right point of the Quad.
170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public PointF bottomRight() {
172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return mBottomRight;
173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Rotate the quad by the given angle.
177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The Quad is rotated counter-clockwise around its centroid.
179227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
180227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param angle the angle to rotate in radians
181227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the rotated Quad
182227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
183227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public Quad rotated(float angle) {
184227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        PointF center = center();
185227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float cosa = (float) Math.cos(angle);
186227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float sina = (float) Math.sin(angle);
187227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
188227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        PointF topLeft = rotatePoint(topLeft(), center, cosa, sina);
189227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        PointF topRight = rotatePoint(topRight(), center, cosa, sina);
190227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        PointF bottomLeft = rotatePoint(bottomLeft(), center, cosa, sina);
191227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        PointF bottomRight = rotatePoint(bottomRight(), center, cosa, sina);
192227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
193227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new Quad(topLeft, topRight, bottomLeft, bottomRight);
194227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
195227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
196227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
197227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Transform the quad with the given transformation matrix.
198227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
199227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The transform is applied by multiplying each point (x, y, 1) by the matrix.
200227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
201227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param matrix the transformation matrix
202227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the transformed Quad
203227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
204227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public Quad transformed(Matrix matrix) {
205227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float[] points = asCoords();
206227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        matrix.mapPoints(points);
207227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new Quad(points);
208227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
209227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
210227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
211227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the centroid of the Quad.
212227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
213227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The centroid of the Quad is where the two inner diagonals connecting the opposite corners
214227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * meet.
215227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
216227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the centroid of the Quad.
217227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
218227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public PointF center() {
219227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // As the diagonals bisect each other, we can simply return the center of one of the
220227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        // diagonals.
221227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new PointF((mTopLeft.x + mBottomRight.x) / 2f,
222227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                          (mTopLeft.y + mBottomRight.y) / 2f);
223227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
224227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
225227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
226227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the quad as a float-array of coordinates.
227227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * The order of coordinates is top-left, top-right, bottom-left, bottom-right. This is the
228227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * default order of coordinates used in ImageShaders, so this method can be used to bind
229227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * an attribute to the Quad.
230227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
231227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public float[] asCoords() {
232227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new float[] { mTopLeft.x, mTopLeft.y,
233227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                             mTopRight.x, mTopRight.y,
234227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                             mBottomLeft.x, mBottomLeft.y,
235227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                             mBottomRight.x, mBottomRight.y };
236227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
237227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
238227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
239227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Grow the Quad outwards by the specified factor.
240227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
241227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * This method moves the corner points of the Quad outward along the diagonals that connect
242227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * them to the centroid. A factor of 1.0 moves the quad outwards by the distance of the corners
243227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * to the centroid.
244227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
245227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param factor the growth factor
246227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the Quad grown by the specified amount
247227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
248227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public Quad grow(float factor) {
249227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        PointF pc = center();
250227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new Quad(factor * (mTopLeft.x - pc.x) + pc.x,
251227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        factor * (mTopLeft.y - pc.y) + pc.y,
252227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        factor * (mTopRight.x - pc.x) + pc.x,
253227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        factor * (mTopRight.y - pc.y) + pc.y,
254227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        factor * (mBottomLeft.x - pc.x) + pc.x,
255227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        factor * (mBottomLeft.y - pc.y) + pc.y,
256227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        factor * (mBottomRight.x - pc.x) + pc.x,
257227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        factor * (mBottomRight.y - pc.y) + pc.y);
258227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
259227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
260227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
261227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Scale the Quad by the specified factor.
262227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
263227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param factor the scaling factor
264227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the Quad instance scaled by the specified factor.
265227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
266227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public Quad scale(float factor) {
267227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new Quad(mTopLeft.x * factor, mTopLeft.y * factor,
268227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        mTopRight.x * factor, mTopRight.y * factor,
269227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        mBottomLeft.x * factor, mBottomLeft.y * factor,
270227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        mBottomRight.x * factor, mBottomRight.y * factor);
271227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
272227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
273227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
274227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Scale the Quad by the specified factors in the x and y factors.
275227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
276227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param sx the x scaling factor
277227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @param sy the y scaling factor
278227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the Quad instance scaled by the specified factors.
279227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
280227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public Quad scale2(float sx, float sy) {
281227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new Quad(mTopLeft.x * sx, mTopLeft.y * sy,
282227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        mTopRight.x * sx, mTopRight.y * sy,
283227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        mBottomLeft.x * sx, mBottomLeft.y * sy,
284227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                        mBottomRight.x * sx, mBottomRight.y * sy);
285227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
286227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
287227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
288227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the Quad's left-to-right edge.
289227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
290227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns a vector that goes from the Quad's top-left to top-right (or bottom-left to
291227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * bottom-right).
292227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
293227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the edge vector as a PointF.
294227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
295227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public PointF xEdge() {
296227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new PointF(mTopRight.x - mTopLeft.x, mTopRight.y - mTopLeft.y);
297227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
298227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
299227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    /**
300227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns the Quad's top-to-bottom edge.
301227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
302227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * Returns a vector that goes from the Quad's top-left to bottom-left (or top-right to
303227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * bottom-right).
304227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     *
305227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     * @return the edge vector as a PointF.
306227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks     */
307227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public PointF yEdge() {
308227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new PointF(mBottomLeft.x - mTopLeft.x, mBottomLeft.y - mTopLeft.y);
309227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
310227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
311227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    @Override
312227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    public String toString() {
313227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return "Quad(" + mTopLeft.x + ", " + mTopLeft.y + ", "
314227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                       + mTopRight.x + ", " + mTopRight.y + ", "
315227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                       + mBottomLeft.x + ", " + mBottomLeft.y + ", "
316227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks                       + mBottomRight.x + ", " + mBottomRight.y + ")";
317227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
318227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
319227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private Quad(PointF topLeft, PointF topRight, PointF bottomLeft, PointF bottomRight) {
320227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mTopLeft = topLeft;
321227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mTopRight = topRight;
322227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mBottomLeft = bottomLeft;
323227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mBottomRight = bottomRight;
324227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
325227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
326227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private Quad(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3) {
327227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mTopLeft = new PointF(x0, y0);
328227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mTopRight = new PointF(x1, y1);
329227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mBottomLeft = new PointF(x2, y2);
330227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mBottomRight = new PointF(x3, y3);
331227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
332227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
333227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private Quad(float[] points) {
334227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mTopLeft = new PointF(points[0], points[1]);
335227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mTopRight = new PointF(points[2], points[3]);
336227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mBottomLeft = new PointF(points[4], points[5]);
337227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        mBottomRight = new PointF(points[6], points[7]);
338227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
339227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
340227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    private static PointF rotatePoint(PointF p, PointF c, float cosa, float sina) {
341227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float x = (p.x - c.x) * cosa - (p.y - c.y) * sina + c.x;
342227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        float y = (p.x - c.x) * sina + (p.y - c.y) * cosa + c.y;
343227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        return new PointF(x,y);
344227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
345227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
346227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
347