Rect.java revision 8169daed2f7a8731d478b884b1f455c747b88478
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 android.os.Parcel; 20import android.os.Parcelable; 21 22/** 23 * Rect holds four integer coordinates for a rectangle. The rectangle is 24 * represented by the coordinates of its 4 edges (left, top, right bottom). 25 * These fields can be accessed directly. Use width() and height() to retrieve 26 * the rectangle's width and height. Note: most methods do not check to see that 27 * the coordinates are sorted correctly (i.e. left <= right and top <= bottom). 28 */ 29public final class Rect implements Parcelable { 30 public int left; 31 public int top; 32 public int right; 33 public int bottom; 34 35 /** 36 * Create a new empty Rect. All coordinates are initialized to 0. 37 */ 38 public Rect() {} 39 40 /** 41 * Create a new rectangle with the specified coordinates. Note: no range 42 * checking is performed, so the caller must ensure that left <= right and 43 * top <= bottom. 44 * 45 * @param left The X coordinate of the left side of the rectagle 46 * @param top The Y coordinate of the top of the rectangle 47 * @param right The X coordinate of the right side of the rectagle 48 * @param bottom The Y coordinate of the bottom of the rectangle 49 */ 50 public Rect(int left, int top, int right, int bottom) { 51 this.left = left; 52 this.top = top; 53 this.right = right; 54 this.bottom = bottom; 55 } 56 57 /** 58 * Create a new rectangle, initialized with the values in the specified 59 * rectangle (which is left unmodified). 60 * 61 * @param r The rectangle whose coordinates are copied into the new 62 * rectangle. 63 */ 64 public Rect(Rect r) { 65 left = r.left; 66 top = r.top; 67 right = r.right; 68 bottom = r.bottom; 69 } 70 71 public boolean equals(Object obj) { 72 Rect r = (Rect) obj; 73 if (r != null) { 74 return left == r.left && top == r.top && right == r.right 75 && bottom == r.bottom; 76 } 77 return false; 78 } 79 80 public String toString() { 81 return "Rect(" + left + ", " + top + " - " + right + ", " + bottom + ")"; 82 } 83 84 /** 85 * Return a string representation of the rectangle in a compact form. 86 */ 87 public String toShortString() { 88 return "[" + left + "," + top + "][" + right + "," + bottom + "]"; 89 } 90 91 /** 92 * Returns true if the rectangle is empty (left >= right or top >= bottom) 93 */ 94 public final boolean isEmpty() { 95 return left >= right || top >= bottom; 96 } 97 98 /** 99 * @return the rectangle's width. This does not check for a valid rectangle 100 * (i.e. left <= right) so the result may be negative. 101 */ 102 public final int width() { 103 return right - left; 104 } 105 106 /** 107 * @return the rectangle's height. This does not check for a valid rectangle 108 * (i.e. top <= bottom) so the result may be negative. 109 */ 110 public final int height() { 111 return bottom - top; 112 } 113 114 /** 115 * @return the horizontal center of the rectangle. If the computed value 116 * is fractional, this method returns the largest integer that is 117 * less than the computed value. 118 */ 119 public final int centerX() { 120 return (left + right) >> 1; 121 } 122 123 /** 124 * @return the vertical center of the rectangle. If the computed value 125 * is fractional, this method returns the largest integer that is 126 * less than the computed value. 127 */ 128 public final int centerY() { 129 return (top + bottom) >> 1; 130 } 131 132 /** 133 * @return the exact horizontal center of the rectangle as a float. 134 */ 135 public final float exactCenterX() { 136 return (left + right) * 0.5f; 137 } 138 139 /** 140 * @return the exact vertical center of the rectangle as a float. 141 */ 142 public final float exactCenterY() { 143 return (top + bottom) * 0.5f; 144 } 145 146 /** 147 * Set the rectangle to (0,0,0,0) 148 */ 149 public void setEmpty() { 150 left = right = top = bottom = 0; 151 } 152 153 /** 154 * Set the rectangle's coordinates to the specified values. Note: no range 155 * checking is performed, so it is up to the caller to ensure that 156 * left <= right and top <= bottom. 157 * 158 * @param left The X coordinate of the left side of the rectagle 159 * @param top The Y coordinate of the top of the rectangle 160 * @param right The X coordinate of the right side of the rectagle 161 * @param bottom The Y coordinate of the bottom of the rectangle 162 */ 163 public void set(int left, int top, int right, int bottom) { 164 this.left = left; 165 this.top = top; 166 this.right = right; 167 this.bottom = bottom; 168 } 169 170 /** 171 * Copy the coordinates from src into this rectangle. 172 * 173 * @param src The rectangle whose coordinates are copied into this 174 * rectangle. 175 */ 176 public void set(Rect src) { 177 this.left = src.left; 178 this.top = src.top; 179 this.right = src.right; 180 this.bottom = src.bottom; 181 } 182 183 /** 184 * Offset the rectangle by adding dx to its left and right coordinates, and 185 * adding dy to its top and bottom coordinates. 186 * 187 * @param dx The amount to add to the rectangle's left and right coordinates 188 * @param dy The amount to add to the rectangle's top and bottom coordinates 189 */ 190 public void offset(int dx, int dy) { 191 left += dx; 192 top += dy; 193 right += dx; 194 bottom += dy; 195 } 196 197 /** 198 * Offset the rectangle to a specific (left, top) position, 199 * keeping its width and height the same. 200 * 201 * @param newLeft The new "left" coordinate for the rectangle 202 * @param newTop The new "top" coordinate for the rectangle 203 */ 204 public void offsetTo(int newLeft, int newTop) { 205 right += newLeft - left; 206 bottom += newTop - top; 207 left = newLeft; 208 top = newTop; 209 } 210 211 /** 212 * Inset the rectangle by (dx,dy). If dx is positive, then the sides are 213 * moved inwards, making the rectangle narrower. If dx is negative, then the 214 * sides are moved outwards, making the rectangle wider. The same holds true 215 * for dy and the top and bottom. 216 * 217 * @param dx The amount to add(subtract) from the rectangle's left(right) 218 * @param dy The amount to add(subtract) from the rectangle's top(bottom) 219 */ 220 public void inset(int dx, int dy) { 221 left += dx; 222 top += dy; 223 right -= dx; 224 bottom -= dy; 225 } 226 227 /** 228 * Returns true if (x,y) is inside the rectangle. The left and top are 229 * considered to be inside, while the right and bottom are not. This means 230 * that for a x,y to be contained: left <= x < right and top <= y < bottom. 231 * An empty rectangle never contains any point. 232 * 233 * @param x The X coordinate of the point being tested for containment 234 * @param y The Y coordinate of the point being tested for containment 235 * @return true iff (x,y) are contained by the rectangle, where containment 236 * means left <= x < right and top <= y < bottom 237 */ 238 public boolean contains(int x, int y) { 239 return left < right && top < bottom // check for empty first 240 && x >= left && x < right && y >= top && y < bottom; 241 } 242 243 /** 244 * Returns true iff the 4 specified sides of a rectangle are inside or equal 245 * to this rectangle. i.e. is this rectangle a superset of the specified 246 * rectangle. An empty rectangle never contains another rectangle. 247 * 248 * @param left The left side of the rectangle being tested for containment 249 * @param top The top of the rectangle being tested for containment 250 * @param right The right side of the rectangle being tested for containment 251 * @param bottom The bottom of the rectangle being tested for containment 252 * @return true iff the the 4 specified sides of a rectangle are inside or 253 * equal to this rectangle 254 */ 255 public boolean contains(int left, int top, int right, int bottom) { 256 // check for empty first 257 return this.left < this.right && this.top < this.bottom 258 // now check for containment 259 && this.left <= left && this.top <= top 260 && this.right >= right && this.bottom >= bottom; 261 } 262 263 /** 264 * Returns true iff the specified rectangle r is inside or equal to this 265 * rectangle. An empty rectangle never contains another rectangle. 266 * 267 * @param r The rectangle being tested for containment. 268 * @return true iff the specified rectangle r is inside or equal to this 269 * rectangle 270 */ 271 public boolean contains(Rect r) { 272 // check for empty first 273 return this.left < this.right && this.top < this.bottom 274 // now check for containment 275 && left <= r.left && top <= r.top 276 && right >= r.right && bottom >= r.bottom; 277 } 278 279 /** 280 * If the rectangle specified by left,top,right,bottom intersects this 281 * rectangle, return true and set this rectangle to that intersection, 282 * otherwise return false and do not change this rectangle. No check is 283 * performed to see if either rectangle is empty. Note: To just test for 284 * intersection, use intersects() 285 * 286 * @param left The left side of the rectangle being intersected with this 287 * rectangle 288 * @param top The top of the rectangle being intersected with this rectangle 289 * @param right The right side of the rectangle being intersected with this 290 * rectangle. 291 * @param bottom The bottom of the rectangle being intersected with this 292 * rectangle. 293 * @return true if the specified rectangle and this rectangle intersect 294 * (and this rectangle is then set to that intersection) else 295 * return false and do not change this rectangle. 296 */ 297 public boolean intersect(int left, int top, int right, int bottom) { 298 if (this.left < right && left < this.right 299 && this.top < bottom && top < this.bottom) { 300 if (this.left < left) { 301 this.left = left; 302 } 303 if (this.top < top) { 304 this.top = top; 305 } 306 if (this.right > right) { 307 this.right = right; 308 } 309 if (this.bottom > bottom) { 310 this.bottom = bottom; 311 } 312 return true; 313 } 314 return false; 315 } 316 317 /** 318 * If the specified rectangle intersects this rectangle, return true and set 319 * this rectangle to that intersection, otherwise return false and do not 320 * change this rectangle. No check is performed to see if either rectangle 321 * is empty. To just test for intersection, use intersects() 322 * 323 * @param r The rectangle being intersected with this rectangle. 324 * @return true if the specified rectangle and this rectangle intersect 325 * (and this rectangle is then set to that intersection) else 326 * return false and do not change this rectangle. 327 */ 328 public boolean intersect(Rect r) { 329 return intersect(r.left, r.top, r.right, r.bottom); 330 } 331 332 /** 333 * If rectangles a and b intersect, return true and set this rectangle to 334 * that intersection, otherwise return false and do not change this 335 * rectangle. No check is performed to see if either rectangle is empty. 336 * To just test for intersection, use intersects() 337 * 338 * @param a The first rectangle being intersected with 339 * @param b The second rectangle being intersected with 340 * @return true iff the two specified rectangles intersect. If they do, set 341 * this rectangle to that intersection. If they do not, return 342 * false and do not change this rectangle. 343 */ 344 public boolean setIntersect(Rect a, Rect b) { 345 if (a.left < b.right && b.left < a.right 346 && a.top < b.bottom && b.top < a.bottom) { 347 left = Math.max(a.left, b.left); 348 top = Math.max(a.top, b.top); 349 right = Math.min(a.right, b.right); 350 bottom = Math.min(a.bottom, b.bottom); 351 return true; 352 } 353 return false; 354 } 355 356 /** 357 * Returns true if this rectangle intersects the specified rectangle. 358 * In no event is this rectangle modified. No check is performed to see 359 * if either rectangle is empty. To record the intersection, use intersect() 360 * or setIntersect(). 361 * 362 * @param left The left side of the rectangle being tested for intersection 363 * @param top The top of the rectangle being tested for intersection 364 * @param right The right side of the rectangle being tested for 365 * intersection 366 * @param bottom The bottom of the rectangle being tested for intersection 367 * @return true iff the specified rectangle intersects this rectangle. In 368 * no event is this rectangle modified. 369 */ 370 public boolean intersects(int left, int top, int right, int bottom) { 371 return this.left < right && left < this.right 372 && this.top < bottom && top < this.bottom; 373 } 374 375 /** 376 * Returns true iff the two specified rectangles intersect. In no event are 377 * either of the rectangles modified. To record the intersection, 378 * use intersect() or setIntersect(). 379 * 380 * @param a The first rectangle being tested for intersection 381 * @param b The second rectangle being tested for intersection 382 * @return true iff the two specified rectangles intersect. In no event are 383 * either of the rectangles modified. 384 */ 385 public static boolean intersects(Rect a, Rect b) { 386 return a.left < b.right && b.left < a.right 387 && a.top < b.bottom && b.top < a.bottom; 388 } 389 390 /** 391 * Update this Rect to enclose itself and the specified rectangle. If the 392 * specified rectangle is empty, nothing is done. If this rectangle is empty 393 * it is set to the specified rectangle. 394 * 395 * @param left The left edge being unioned with this rectangle 396 * @param top The top edge being unioned with this rectangle 397 * @param right The right edge being unioned with this rectangle 398 * @param bottom The bottom edge being unioned with this rectangle 399 */ 400 public void union(int left, int top, int right, int bottom) { 401 if ((left < right) && (top < bottom)) { 402 if ((this.left < this.right) && (this.top < this.bottom)) { 403 if (this.left > left) 404 this.left = left; 405 if (this.top > top) 406 this.top = top; 407 if (this.right < right) 408 this.right = right; 409 if (this.bottom < bottom) 410 this.bottom = bottom; 411 } else { 412 this.left = left; 413 this.top = top; 414 this.right = right; 415 this.bottom = bottom; 416 } 417 } 418 } 419 420 /** 421 * Update this Rect to enclose itself and the specified rectangle. If the 422 * specified rectangle is empty, nothing is done. If this rectangle is empty 423 * it is set to the specified rectangle. 424 * 425 * @param r The rectangle being unioned with this rectangle 426 */ 427 public void union(Rect r) { 428 union(r.left, r.top, r.right, r.bottom); 429 } 430 431 /** 432 * Update this Rect to enclose itself and the [x,y] coordinate. There is no 433 * check to see that this rectangle is non-empty. 434 * 435 * @param x The x coordinate of the point to add to the rectangle 436 * @param y The y coordinate of the point to add to the rectangle 437 */ 438 public void union(int x, int y) { 439 if (x < left) { 440 left = x; 441 } else if (x > right) { 442 right = x; 443 } 444 if (y < top) { 445 top = y; 446 } else if (y > bottom) { 447 bottom = y; 448 } 449 } 450 451 /** 452 * Swap top/bottom or left/right if there are flipped (i.e. left > right 453 * and/or top > bottom). This can be called if 454 * the edges are computed separately, and may have crossed over each other. 455 * If the edges are already correct (i.e. left <= right and top <= bottom) 456 * then nothing is done. 457 */ 458 public void sort() { 459 if (left > right) { 460 int temp = left; 461 left = right; 462 right = temp; 463 } 464 if (top > bottom) { 465 int temp = top; 466 top = bottom; 467 bottom = temp; 468 } 469 } 470 471 /** 472 * Parcelable interface methods 473 */ 474 public int describeContents() { 475 return 0; 476 } 477 478 /** 479 * Write this rectangle to the specified parcel. To restore a rectangle from 480 * a parcel, use readFromParcel() 481 * @param out The parcel to write the rectangle's coordinates into 482 */ 483 public void writeToParcel(Parcel out, int flags) { 484 out.writeInt(left); 485 out.writeInt(top); 486 out.writeInt(right); 487 out.writeInt(bottom); 488 } 489 490 public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() { 491 /** 492 * Return a new rectangle from the data in the specified parcel. 493 */ 494 public Rect createFromParcel(Parcel in) { 495 Rect r = new Rect(); 496 r.readFromParcel(in); 497 return r; 498 } 499 500 /** 501 * Return an array of rectangles of the specified size. 502 */ 503 public Rect[] newArray(int size) { 504 return new Rect[size]; 505 } 506 }; 507 508 /** 509 * Set the rectangle's coordinates from the data stored in the specified 510 * parcel. To write a rectangle to a parcel, call writeToParcel(). 511 * 512 * @param in The parcel to read the rectangle's coordinates from 513 */ 514 public void readFromParcel(Parcel in) { 515 left = in.readInt(); 516 top = in.readInt(); 517 right = in.readInt(); 518 bottom = in.readInt(); 519 } 520 521 /** 522 * Scales up the rect by the given scale. 523 * @hide 524 */ 525 public void scale(float scale) { 526 if (scale != 1.0f) { 527 left *= scale; 528 top *= scale; 529 right *= scale; 530 bottom*= scale; 531 } 532 } 533} 534