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