RectF.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
10529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch/* 20529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * Copyright (C) 2006 The Android Open Source Project 30529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * 40529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * Licensed under the Apache License, Version 2.0 (the "License"); 50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * you may not use this file except in compliance with the License. 60529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * You may obtain a copy of the License at 70529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * 80529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * http://www.apache.org/licenses/LICENSE-2.0 90529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * 100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * Unless required by applicable law or agreed to in writing, software 110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * distributed under the License is distributed on an "AS IS" BASIS, 120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * See the License for the specific language governing permissions and 140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * limitations under the License. 150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch */ 160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochpackage android.graphics; 180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.util.FloatMath; 200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport com.android.internal.util.FastMath; 210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch/** 230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * RectF holds four float coordinates for a rectangle. The rectangle is 240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * represented by the coordinates of its 4 edges (left, top, right bottom). 250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * These fields can be accessed directly. Use width() and height() to retrieve 260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * the rectangle's width and height. Note: most methods do not check to see that 270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * the coordinates are sorted correctly (i.e. left <= right and top <= bottom). 280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch */ 290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochpublic class RectF { 300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch public float left; 310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch public float top; 320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch public float right; 330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch public float bottom; 340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch /** 360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * Create a new empty RectF. All coordinates are initialized to 0. 370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch */ 380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch public RectF() {} 390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch /** 410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * Create a new rectangle with the specified coordinates. Note: no range 420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * checking is performed, so the caller must ensure that left <= right and 430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * top <= bottom. 44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * 45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param left The X coordinate of the left side of the rectagle 460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * @param top The Y coordinate of the top of the rectangle 470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * @param right The X coordinate of the right side of the rectagle 480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * @param bottom The Y coordinate of the bottom of the rectangle 490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch */ 500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch public RectF(float left, float top, float right, float bottom) { 510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch this.left = left; 520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch this.top = top; 530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch this.right = right; 540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch this.bottom = bottom; 550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch } 560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch /** 580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * Create a new rectangle, initialized with the values in the specified 590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * rectangle (which is left unmodified). 600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * 610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * @param r The rectangle whose coordinates are copied into the new 620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch * rectangle. 630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch */ 640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch public RectF(RectF r) { 650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch left = r.left; 660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch top = r.top; 670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch right = r.right; 680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch bottom = r.bottom; 690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch } 700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch public RectF(Rect r) { 720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch left = r.left; 73 top = r.top; 74 right = r.right; 75 bottom = r.bottom; 76 } 77 78 public String toString() { 79 return "RectF(" + left + ", " + top + ", " 80 + right + ", " + bottom + ")"; 81 } 82 83 /** 84 * Returns true if the rectangle is empty (left >= right or top >= bottom) 85 */ 86 public final boolean isEmpty() { 87 return left >= right || top >= bottom; 88 } 89 90 /** 91 * @return the rectangle's width. This does not check for a valid rectangle 92 * (i.e. left <= right) so the result may be negative. 93 */ 94 public final float width() { 95 return right - left; 96 } 97 98 /** 99 * @return the rectangle's height. This does not check for a valid rectangle 100 * (i.e. top <= bottom) so the result may be negative. 101 */ 102 public final float height() { 103 return bottom - top; 104 } 105 106 /** 107 * @return the horizontal center of the rectangle. This does not check for 108 * a valid rectangle (i.e. left <= right) 109 */ 110 public final float centerX() { 111 return (left + right) * 0.5f; 112 } 113 114 /** 115 * @return the vertical center of the rectangle. This does not check for 116 * a valid rectangle (i.e. top <= bottom) 117 */ 118 public final float centerY() { 119 return (top + bottom) * 0.5f; 120 } 121 122 /** 123 * Set the rectangle to (0,0,0,0) 124 */ 125 public void setEmpty() { 126 left = right = top = bottom = 0; 127 } 128 129 /** 130 * Set the rectangle's coordinates to the specified values. Note: no range 131 * checking is performed, so it is up to the caller to ensure that 132 * left <= right and top <= bottom. 133 * 134 * @param left The X coordinate of the left side of the rectagle 135 * @param top The Y coordinate of the top of the rectangle 136 * @param right The X coordinate of the right side of the rectagle 137 * @param bottom The Y coordinate of the bottom of the rectangle 138 */ 139 public void set(float left, float top, float right, float bottom) { 140 this.left = left; 141 this.top = top; 142 this.right = right; 143 this.bottom = bottom; 144 } 145 146 /** 147 * Copy the coordinates from src into this rectangle. 148 * 149 * @param src The rectangle whose coordinates are copied into this 150 * rectangle. 151 */ 152 public void set(RectF src) { 153 this.left = src.left; 154 this.top = src.top; 155 this.right = src.right; 156 this.bottom = src.bottom; 157 } 158 159 /** 160 * Copy the coordinates from src into this rectangle. 161 * 162 * @param src The rectangle whose coordinates are copied into this 163 * rectangle. 164 */ 165 public void set(Rect src) { 166 this.left = src.left; 167 this.top = src.top; 168 this.right = src.right; 169 this.bottom = src.bottom; 170 } 171 172 /** 173 * Offset the rectangle by adding dx to its left and right coordinates, and 174 * adding dy to its top and bottom coordinates. 175 * 176 * @param dx The amount to add to the rectangle's left and right coordinates 177 * @param dy The amount to add to the rectangle's top and bottom coordinates 178 */ 179 public void offset(float dx, float dy) { 180 left += dx; 181 top += dy; 182 right += dx; 183 bottom += dy; 184 } 185 186 /** 187 * Offset the rectangle to a specific (left, top) position, 188 * keeping its width and height the same. 189 * 190 * @param newLeft The new "left" coordinate for the rectangle 191 * @param newTop The new "top" coordinate for the rectangle 192 */ 193 public void offsetTo(float newLeft, float newTop) { 194 right += newLeft - left; 195 bottom += newTop - top; 196 left = newLeft; 197 top = newTop; 198 } 199 200 /** 201 * Inset the rectangle by (dx,dy). If dx is positive, then the sides are 202 * moved inwards, making the rectangle narrower. If dx is negative, then the 203 * sides are moved outwards, making the rectangle wider. The same holds true 204 * for dy and the top and bottom. 205 * 206 * @param dx The amount to add(subtract) from the rectangle's left(right) 207 * @param dy The amount to add(subtract) from the rectangle's top(bottom) 208 */ 209 public void inset(float dx, float dy) { 210 left += dx; 211 top += dy; 212 right -= dx; 213 bottom -= dy; 214 } 215 216 /** 217 * Returns true if (x,y) is inside the rectangle. The left and top are 218 * considered to be inside, while the right and bottom are not. This means 219 * that for a x,y to be contained: left <= x < right and top <= y < bottom. 220 * An empty rectangle never contains any point. 221 * 222 * @param x The X coordinate of the point being tested for containment 223 * @param y The Y coordinate of the point being tested for containment 224 * @return true iff (x,y) are contained by the rectangle, where containment 225 * means left <= x < right and top <= y < bottom 226 */ 227 public boolean contains(float x, float y) { 228 return left < right && top < bottom // check for empty first 229 && x >= left && x < right && y >= top && y < bottom; 230 } 231 232 /** 233 * Returns true iff the 4 specified sides of a rectangle are inside or equal 234 * to this rectangle. i.e. is this rectangle a superset of the specified 235 * rectangle. An empty rectangle never contains another rectangle. 236 * 237 * @param left The left side of the rectangle being tested for containment 238 * @param top The top of the rectangle being tested for containment 239 * @param right The right side of the rectangle being tested for containment 240 * @param bottom The bottom of the rectangle being tested for containment 241 * @return true iff the the 4 specified sides of a rectangle are inside or 242 * equal to this rectangle 243 */ 244 public boolean contains(float left, float top, float right, float bottom) { 245 // check for empty first 246 return this.left < this.right && this.top < this.bottom 247 // now check for containment 248 && this.left <= left && this.top <= top 249 && this.right >= right && this.bottom >= bottom; 250 } 251 252 /** 253 * Returns true iff the specified rectangle r is inside or equal to this 254 * rectangle. An empty rectangle never contains another rectangle. 255 * 256 * @param r The rectangle being tested for containment. 257 * @return true iff the specified rectangle r is inside or equal to this 258 * rectangle 259 */ 260 public boolean contains(RectF r) { 261 // check for empty first 262 return this.left < this.right && this.top < this.bottom 263 // now check for containment 264 && left <= r.left && top <= r.top 265 && right >= r.right && bottom >= r.bottom; 266 } 267 268 /** 269 * If the rectangle specified by left,top,right,bottom intersects this 270 * rectangle, return true and set this rectangle to that intersection, 271 * otherwise return false and do not change this rectangle. No check is 272 * performed to see if either rectangle is empty. Note: To just test for 273 * intersection, use intersects() 274 * 275 * @param left The left side of the rectangle being intersected with this 276 * rectangle 277 * @param top The top of the rectangle being intersected with this rectangle 278 * @param right The right side of the rectangle being intersected with this 279 * rectangle. 280 * @param bottom The bottom of the rectangle being intersected with this 281 * rectangle. 282 * @return true if the specified rectangle and this rectangle intersect 283 * (and this rectangle is then set to that intersection) else 284 * return false and do not change this rectangle. 285 */ 286 public boolean intersect(float left, float top, float right, float bottom) { 287 if (this.left < right && left < this.right 288 && this.top < bottom && top < this.bottom) { 289 if (this.left < left) { 290 this.left = left; 291 } 292 if (this.top < top) { 293 this.top = top; 294 } 295 if (this.right > right) { 296 this.right = right; 297 } 298 if (this.bottom > bottom) { 299 this.bottom = bottom; 300 } 301 return true; 302 } 303 return false; 304 } 305 306 /** 307 * If the specified rectangle intersects this rectangle, return true and set 308 * this rectangle to that intersection, otherwise return false and do not 309 * change this rectangle. No check is performed to see if either rectangle 310 * is empty. To just test for intersection, use intersects() 311 * 312 * @param r The rectangle being intersected with this rectangle. 313 * @return true if the specified rectangle and this rectangle intersect 314 * (and this rectangle is then set to that intersection) else 315 * return false and do not change this rectangle. 316 */ 317 public boolean intersect(RectF r) { 318 return intersect(r.left, r.top, r.right, r.bottom); 319 } 320 321 /** 322 * If rectangles a and b intersect, return true and set this rectangle to 323 * that intersection, otherwise return false and do not change this 324 * rectangle. No check is performed to see if either rectangle is empty. 325 * To just test for intersection, use intersects() 326 * 327 * @param a The first rectangle being intersected with 328 * @param b The second rectangle being intersected with 329 * @return true iff the two specified rectangles intersect. If they do, set 330 * this rectangle to that intersection. If they do not, return 331 * false and do not change this rectangle. 332 */ 333 public boolean setIntersect(RectF a, RectF b) { 334 if (a.left < b.right && b.left < a.right 335 && a.top < b.bottom && b.top < a.bottom) { 336 left = Math.max(a.left, b.left); 337 top = Math.max(a.top, b.top); 338 right = Math.min(a.right, b.right); 339 bottom = Math.min(a.bottom, b.bottom); 340 return true; 341 } 342 return false; 343 } 344 345 /** 346 * Returns true if this rectangle intersects the specified rectangle. 347 * In no event is this rectangle modified. No check is performed to see 348 * if either rectangle is empty. To record the intersection, use intersect() 349 * or setIntersect(). 350 * 351 * @param left The left side of the rectangle being tested for intersection 352 * @param top The top of the rectangle being tested for intersection 353 * @param right The right side of the rectangle being tested for 354 * intersection 355 * @param bottom The bottom of the rectangle being tested for intersection 356 * @return true iff the specified rectangle intersects this rectangle. In 357 * no event is this rectangle modified. 358 */ 359 public boolean intersects(float left, float top, float right, 360 float bottom) { 361 return this.left < right && left < this.right 362 && this.top < bottom && top < this.bottom; 363 } 364 365 /** 366 * Returns true iff the two specified rectangles intersect. In no event are 367 * either of the rectangles modified. To record the intersection, 368 * use intersect() or setIntersect(). 369 * 370 * @param a The first rectangle being tested for intersection 371 * @param b The second rectangle being tested for intersection 372 * @return true iff the two specified rectangles intersect. In no event are 373 * either of the rectangles modified. 374 */ 375 public static boolean intersects(RectF a, RectF b) { 376 return a.left < b.right && b.left < a.right 377 && a.top < b.bottom && b.top < a.bottom; 378 } 379 380 /** 381 * Set the dst integer Rect by rounding this rectangle's coordinates 382 * to their nearest integer values. 383 */ 384 public void round(Rect dst) { 385 dst.set(FastMath.round(left), FastMath.round(top), 386 FastMath.round(right), FastMath.round(bottom)); 387 } 388 389 /** 390 * Set the dst integer Rect by rounding "out" this rectangle, choosing the 391 * floor of top and left, and the ceiling of right and bottom. 392 */ 393 public void roundOut(Rect dst) { 394 dst.set((int) FloatMath.floor(left), (int) FloatMath.floor(top), 395 (int) FloatMath.ceil(right), (int) FloatMath.ceil(bottom)); 396 } 397 398 /** 399 * Update this Rect to enclose itself and the specified rectangle. If the 400 * specified rectangle is empty, nothing is done. If this rectangle is empty 401 * it is set to the specified rectangle. 402 * 403 * @param left The left edge being unioned with this rectangle 404 * @param top The top edge being unioned with this rectangle 405 * @param right The right edge being unioned with this rectangle 406 * @param bottom The bottom edge being unioned with this rectangle 407 */ 408 public void union(float left, float top, float right, float bottom) { 409 if ((left < right) && (top < bottom)) { 410 if ((this.left < this.right) && (this.top < this.bottom)) { 411 if (this.left > left) 412 this.left = left; 413 if (this.top > top) 414 this.top = top; 415 if (this.right < right) 416 this.right = right; 417 if (this.bottom < bottom) 418 this.bottom = bottom; 419 } else { 420 this.left = left; 421 this.top = top; 422 this.right = right; 423 this.bottom = bottom; 424 } 425 } 426 } 427 428 /** 429 * Update this Rect to enclose itself and the specified rectangle. If the 430 * specified rectangle is empty, nothing is done. If this rectangle is empty 431 * it is set to the specified rectangle. 432 * 433 * @param r The rectangle being unioned with this rectangle 434 */ 435 public void union(RectF r) { 436 union(r.left, r.top, r.right, r.bottom); 437 } 438 439 /** 440 * Update this Rect to enclose itself and the [x,y] coordinate. There is no 441 * check to see that this rectangle is non-empty. 442 * 443 * @param x The x coordinate of the point to add to the rectangle 444 * @param y The y coordinate of the point to add to the rectangle 445 */ 446 public void union(float x, float y) { 447 if (x < left) { 448 left = x; 449 } else if (x > right) { 450 right = x; 451 } 452 if (y < top) { 453 top = y; 454 } else if (y > bottom) { 455 bottom = y; 456 } 457 } 458 459 /** 460 * Swap top/bottom or left/right if there are flipped (i.e. left > right 461 * and/or top > bottom). This can be called if 462 * the edges are computed separately, and may have crossed over each other. 463 * If the edges are already correct (i.e. left <= right and top <= bottom) 464 * then nothing is done. 465 */ 466 public void sort() { 467 if (left > right) { 468 float temp = left; 469 left = right; 470 right = temp; 471 } 472 if (top > bottom) { 473 float temp = top; 474 top = bottom; 475 bottom = temp; 476 } 477 } 478} 479