Rect.java revision 5d7dc30638953195ed55d32bc9dc37102a613ff8
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
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 com.android.ide.common.api;
18
19import com.google.common.annotations.Beta;
20import com.android.annotations.NonNull;
21import com.android.annotations.Nullable;
22
23
24/**
25 * Mutable rectangle bounds.
26 * <p/>
27 * To be valid, w >= 1 and h >= 1.
28 * By definition:
29 * - right side = x + w - 1.
30 * - bottom side = y + h - 1.
31 * <p>
32 * <b>NOTE: This is not a public or final API; if you rely on this be prepared
33 * to adjust your code for the next tools release.</b>
34 * </p>
35 */
36@Beta
37public class Rect {
38    public int x, y, w, h;
39
40    /** Initialize an invalid rectangle. */
41    public Rect() {
42    }
43
44    /** Initialize rectangle to the given values. They can be invalid. */
45    public Rect(int x, int y, int w, int h) {
46        set(x, y, w, h);
47    }
48
49    /** Initialize rectangle to the given values. They can be invalid. */
50    public Rect(@NonNull Rect r) {
51        set(r);
52    }
53
54    /** Initialize rectangle to the given values. They can be invalid. */
55    @NonNull
56    public Rect set(int x, int y, int w, int h) {
57        this.x = x;
58        this.y = y;
59        this.w = w;
60        this.h = h;
61        return this;
62    }
63
64    /** Initialize rectangle to match the given one. */
65    @NonNull
66    public Rect set(@NonNull Rect r) {
67        set(r.x, r.y, r.w, r.h);
68        return this;
69    }
70
71    /** Returns a new instance of a rectangle with the same values. */
72    @NonNull
73    public Rect copy() {
74        return new Rect(x, y, w, h);
75    }
76
77    /** Returns true if the rectangle has valid bounds, i.e. w>0 and h>0. */
78    public boolean isValid() {
79        return w > 0 && h > 0;
80    }
81
82    /** Returns true if the rectangle contains the x,y coordinates, borders included. */
83    public boolean contains(int x, int y) {
84        return isValid() &&
85            x >= this.x &&
86            y >= this.y &&
87            x < (this.x + this.w) &&
88            y < (this.y + this.h);
89    }
90
91    /** Returns true if the rectangle contains the x,y coordinates, borders included. */
92    public boolean contains(@Nullable Point p) {
93        return p != null && contains(p.x, p.y);
94    }
95
96    /**
97     * Moves this rectangle by setting it's x,y coordinates to the new values.
98     * @return Returns self, for chaining.
99     */
100    @NonNull
101    public Rect moveTo(int x, int y) {
102        this.x = x;
103        this.y = y;
104        return this;
105    }
106
107    /**
108     * Offsets this rectangle by adding the given x,y deltas to the x,y coordinates.
109     * @return Returns self, for chaining.
110     */
111    @NonNull
112    public Rect offsetBy(int x, int y) {
113        this.x += x;
114        this.y += y;
115        return this;
116    }
117
118    @NonNull
119    public Point getCenter() {
120        return new Point(x + (w > 0 ? w / 2 : 0),
121                         y + (h > 0 ? h / 2 : 0));
122    }
123
124    @NonNull
125    public Point getTopLeft() {
126        return new Point(x, y);
127    }
128
129    @NonNull
130    public Point getBottomLeft() {
131        return new Point(x,
132                         y + (h > 0 ? h : 0));
133    }
134
135    @NonNull
136    public Point getTopRight() {
137        return new Point(x + (w > 0 ? w : 0),
138                         y);
139    }
140
141    @NonNull
142    public Point getBottomRight() {
143        return new Point(x + (w > 0 ? w : 0),
144                         y + (h > 0 ? h : 0));
145    }
146
147    /**
148     * Returns the X coordinate of the right hand side of the rectangle
149     *
150     * @return the X coordinate of the right hand side of the rectangle
151     */
152    public int x2() {
153        return x + w;
154    }
155
156    /**
157     * Returns the Y coordinate of the bottom of the rectangle
158     *
159     * @return the Y coordinate of the bottom of the rectangle
160     */
161    public int y2() {
162        return y + h;
163    }
164
165    /**
166     * Returns the X coordinate of the center of the rectangle
167     *
168     * @return the X coordinate of the center of the rectangle
169     */
170    public int centerX() {
171        return x + w / 2;
172    }
173
174    /**
175     * Returns the Y coordinate of the center of the rectangle
176     *
177     * @return the Y coordinate of the center of the rectangle
178     */
179    public int centerY() {
180        return y + h / 2;
181    }
182
183    @Override
184    public String toString() {
185        return String.format("Rect [(%d,%d)-(%d,%d): %dx%d]", x, y, x + w, y + h, w, h);
186    }
187
188    @Override
189    public boolean equals(Object obj) {
190        if (obj instanceof Rect) {
191            Rect rhs = (Rect) obj;
192            // validity must be equal on both sides.
193            if (isValid() != rhs.isValid()) {
194                return false;
195            }
196            // an invalid rect is equal to any other invalid rect regardless of coordinates
197            if (!isValid() && !rhs.isValid()) {
198                return true;
199            }
200
201            return this.x == rhs.x && this.y == rhs.y && this.w == rhs.w && this.h == rhs.h;
202        }
203
204        return false;
205    }
206
207    @Override
208    public int hashCode() {
209        int hc = x;
210        hc ^= ((y >>  8) & 0x0FFFFFF) | ((y & 0x00000FF) << 24);
211        hc ^= ((w >> 16) & 0x000FFFF) | ((w & 0x000FFFF) << 16);
212        hc ^= ((h >> 24) & 0x00000FF) | ((h & 0x0FFFFFF) <<  8);
213        return hc;
214    }
215
216    /**
217     * Returns the center point in the rectangle
218     *
219     * @return the center point in the rectangle
220     */
221    @NonNull
222    public Point center() {
223        return new Point(x + w / 2, y + h / 2);
224    }
225}
226