1 /* Rectangle.java -- represents a graphics rectangle 2 Copyright (C) 1999, 2000, 2001, 2002, 2006, Free Software Foundation 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package java.awt; 40 41 import java.awt.geom.Rectangle2D; 42 import java.io.Serializable; 43 44 /** 45 * This class represents a rectangle and all the interesting things you 46 * might want to do with it. Note that the coordinate system uses 47 * the origin (0,0) as the top left of the screen, with the x and y 48 * values increasing as they move to the right and down respectively. 49 * 50 * <p>It is valid for a rectangle to have negative width or height; but it 51 * is considered to have no area or internal points. Therefore, the behavior 52 * in methods like <code>contains</code> or <code>intersects</code> is 53 * undefined unless the rectangle has positive width and height. 54 * 55 * <p>There are some public fields; if you mess with them in an inconsistent 56 * manner, it is your own fault when you get NullPointerException, 57 * ArrayIndexOutOfBoundsException, or invalid results. Also, this class is 58 * not threadsafe. 59 * 60 * @author Warren Levy (warrenl@cygnus.com) 61 * @author Aaron M. Renn (arenn@urbanophile.com) 62 * @author Eric Blake (ebb9@email.byu.edu) 63 * @since 1.0 64 * @status updated to 1.4 65 */ 66 public class Rectangle extends Rectangle2D implements Shape, Serializable 67 { 68 /** 69 * Compatible with JDK 1.0+. 70 */ 71 private static final long serialVersionUID = -4345857070255674764L; 72 73 /** 74 * The X coordinate of the top-left corner of the rectangle. 75 * 76 * @see #setLocation(int, int) 77 * @see #getLocation() 78 * @serial the x coordinate 79 */ 80 public int x; 81 82 /** 83 * The Y coordinate of the top-left corner of the rectangle. 84 * 85 * @see #setLocation(int, int) 86 * @see #getLocation() 87 * @serial the y coordinate 88 */ 89 public int y; 90 91 /** 92 * The width of the rectangle. 93 * 94 * @see #setSize(int, int) 95 * @see #getSize() 96 * @serial 97 */ 98 public int width; 99 100 /** 101 * The height of the rectangle. 102 * 103 * @see #setSize(int, int) 104 * @see #getSize() 105 * @serial 106 */ 107 public int height; 108 109 /** 110 * Initializes a new instance of <code>Rectangle</code> with a top 111 * left corner at (0,0) and a width and height of 0. 112 */ Rectangle()113 public Rectangle() 114 { 115 } 116 117 /** 118 * Initializes a new instance of <code>Rectangle</code> from the 119 * coordinates of the specified rectangle. 120 * 121 * @param r the rectangle to copy from 122 * @since 1.1 123 */ Rectangle(Rectangle r)124 public Rectangle(Rectangle r) 125 { 126 x = r.x; 127 y = r.y; 128 width = r.width; 129 height = r.height; 130 } 131 132 /** 133 * Initializes a new instance of <code>Rectangle</code> from the specified 134 * inputs. 135 * 136 * @param x the X coordinate of the top left corner 137 * @param y the Y coordinate of the top left corner 138 * @param width the width of the rectangle 139 * @param height the height of the rectangle 140 */ Rectangle(int x, int y, int width, int height)141 public Rectangle(int x, int y, int width, int height) 142 { 143 this.x = x; 144 this.y = y; 145 this.width = width; 146 this.height = height; 147 } 148 149 /** 150 * Initializes a new instance of <code>Rectangle</code> with the specified 151 * width and height. The upper left corner of the rectangle will be at 152 * the origin (0,0). 153 * 154 * @param width the width of the rectangle 155 * @param height the height of the rectange 156 */ Rectangle(int width, int height)157 public Rectangle(int width, int height) 158 { 159 this.width = width; 160 this.height = height; 161 } 162 163 /** 164 * Initializes a new instance of <code>Rectangle</code> with a top-left 165 * corner represented by the specified point and the width and height 166 * represented by the specified dimension. 167 * 168 * @param p the upper left corner of the rectangle 169 * @param d the width and height of the rectangle 170 */ Rectangle(Point p, Dimension d)171 public Rectangle(Point p, Dimension d) 172 { 173 x = p.x; 174 y = p.y; 175 width = d.width; 176 height = d.height; 177 } 178 179 /** 180 * Initializes a new instance of <code>Rectangle</code> with a top left 181 * corner at the specified point and a width and height of zero. 182 * 183 * @param p the upper left corner of the rectangle 184 */ Rectangle(Point p)185 public Rectangle(Point p) 186 { 187 x = p.x; 188 y = p.y; 189 } 190 191 /** 192 * Initializes a new instance of <code>Rectangle</code> with an 193 * upper left corner at the origin (0,0) and a width and height represented 194 * by the specified dimension. 195 * 196 * @param d the width and height of the rectangle 197 */ Rectangle(Dimension d)198 public Rectangle(Dimension d) 199 { 200 width = d.width; 201 height = d.height; 202 } 203 204 /** 205 * Get the X coordinate of the upper-left corner. 206 * 207 * @return the value of x, as a double 208 */ getX()209 public double getX() 210 { 211 return x; 212 } 213 214 /** 215 * Get the Y coordinate of the upper-left corner. 216 * 217 * @return the value of y, as a double 218 */ getY()219 public double getY() 220 { 221 return y; 222 } 223 224 /** 225 * Get the width of the rectangle. 226 * 227 * @return the value of width, as a double 228 */ getWidth()229 public double getWidth() 230 { 231 return width; 232 } 233 234 /** 235 * Get the height of the rectangle. 236 * 237 * @return the value of height, as a double 238 */ getHeight()239 public double getHeight() 240 { 241 return height; 242 } 243 244 /** 245 * Returns the bounds of this rectangle. A pretty useless method, as this 246 * is already a rectangle; it is included to mimic the 247 * <code>getBounds</code> method in Component. 248 * 249 * @return a copy of this rectangle 250 * @see #setBounds(Rectangle) 251 * @since 1.1 252 */ getBounds()253 public Rectangle getBounds() 254 { 255 return new Rectangle(this); 256 } 257 258 /** 259 * Returns the high-precision bounds of this rectangle. A pretty useless 260 * method, as this is already a rectangle. 261 * 262 * @return a copy of this rectangle 263 * @see #setBounds(Rectangle) 264 * @since 1.2 265 */ getBounds2D()266 public Rectangle2D getBounds2D() 267 { 268 return new Rectangle(x, y, width, height); 269 } 270 271 /** 272 * Updates this rectangle to match the dimensions of the specified 273 * rectangle. 274 * 275 * @param r the rectangle to update from 276 * @throws NullPointerException if r is null 277 * @see #setBounds(int, int, int, int) 278 * @since 1.1 279 */ setBounds(Rectangle r)280 public void setBounds(Rectangle r) 281 { 282 setBounds (r.x, r.y, r.width, r.height); 283 } 284 285 /** 286 * Updates this rectangle to have the specified dimensions. 287 * 288 * @param x the new X coordinate of the upper left hand corner 289 * @param y the new Y coordinate of the upper left hand corner 290 * @param width the new width of this rectangle 291 * @param height the new height of this rectangle 292 * @since 1.1 293 */ setBounds(int x, int y, int width, int height)294 public void setBounds(int x, int y, int width, int height) 295 { 296 reshape (x, y, width, height); 297 } 298 299 /** 300 * Updates this rectangle to have the specified dimensions, rounded to the 301 * integer precision used by this class (the values are rounded "outwards" so 302 * that the stored rectangle completely encloses the specified double 303 * precision rectangle). 304 * 305 * @param x the new X coordinate of the upper left hand corner 306 * @param y the new Y coordinate of the upper left hand corner 307 * @param width the new width of this rectangle 308 * @param height the new height of this rectangle 309 * @since 1.2 310 */ setRect(double x, double y, double width, double height)311 public void setRect(double x, double y, double width, double height) 312 { 313 this.x = (int) Math.floor(x); 314 this.y = (int) Math.floor(y); 315 this.width = (int) Math.ceil(x + width) - this.x; 316 this.height = (int) Math.ceil(y + height) - this.y; 317 } 318 319 /** 320 * Updates this rectangle to have the specified dimensions. 321 * 322 * @param x the new X coordinate of the upper left hand corner 323 * @param y the new Y coordinate of the upper left hand corner 324 * @param width the new width of this rectangle 325 * @param height the new height of this rectangle 326 * @deprecated use {@link #setBounds(int, int, int, int)} instead 327 */ reshape(int x, int y, int width, int height)328 public void reshape(int x, int y, int width, int height) 329 { 330 this.x = x; 331 this.y = y; 332 this.width = width; 333 this.height = height; 334 } 335 336 /** 337 * Returns the location of this rectangle, which is the coordinates of 338 * its upper left corner. 339 * 340 * @return the point where this rectangle is located 341 * @see #setLocation(Point) 342 * @since 1.1 343 */ getLocation()344 public Point getLocation() 345 { 346 return new Point(x,y); 347 } 348 349 /** 350 * Moves the location of this rectangle by setting its upper left 351 * corner to the specified point. 352 * 353 * @param p the point to move the rectangle to 354 * @throws NullPointerException if p is null 355 * @see #getLocation() 356 * @since 1.1 357 */ setLocation(Point p)358 public void setLocation(Point p) 359 { 360 setLocation (p.x, p.y); 361 } 362 363 /** 364 * Moves the location of this rectangle by setting its upper left 365 * corner to the specified coordinates. 366 * 367 * @param x the new X coordinate for this rectangle 368 * @param y the new Y coordinate for this rectangle 369 * @since 1.1 370 */ setLocation(int x, int y)371 public void setLocation(int x, int y) 372 { 373 move (x, y); 374 } 375 376 /** 377 * Moves the location of this rectangle by setting its upper left 378 * corner to the specified coordinates. 379 * 380 * @param x the new X coordinate for this rectangle 381 * @param y the new Y coordinate for this rectangle 382 * @deprecated use {@link #setLocation(int, int)} instead 383 */ move(int x, int y)384 public void move(int x, int y) 385 { 386 this.x = x; 387 this.y = y; 388 } 389 390 /** 391 * Translate the location of this rectangle by the given amounts. 392 * 393 * @param dx the x distance to move by 394 * @param dy the y distance to move by 395 * @see #setLocation(int, int) 396 */ translate(int dx, int dy)397 public void translate(int dx, int dy) 398 { 399 x += dx; 400 y += dy; 401 } 402 403 /** 404 * Returns the size of this rectangle. 405 * 406 * @return the size of this rectangle 407 * @see #setSize(Dimension) 408 * @since 1.1 409 */ getSize()410 public Dimension getSize() 411 { 412 return new Dimension(width, height); 413 } 414 415 /** 416 * Sets the size of this rectangle based on the specified dimensions. 417 * 418 * @param d the new dimensions of the rectangle 419 * @throws NullPointerException if d is null 420 * @see #getSize() 421 * @since 1.1 422 */ setSize(Dimension d)423 public void setSize(Dimension d) 424 { 425 setSize (d.width, d.height); 426 } 427 428 /** 429 * Sets the size of this rectangle based on the specified dimensions. 430 * 431 * @param width the new width of the rectangle 432 * @param height the new height of the rectangle 433 * @since 1.1 434 */ setSize(int width, int height)435 public void setSize(int width, int height) 436 { 437 resize (width, height); 438 } 439 440 /** 441 * Sets the size of this rectangle based on the specified dimensions. 442 * 443 * @param width the new width of the rectangle 444 * @param height the new height of the rectangle 445 * @deprecated use {@link #setSize(int, int)} instead 446 */ resize(int width, int height)447 public void resize(int width, int height) 448 { 449 this.width = width; 450 this.height = height; 451 } 452 453 /** 454 * Tests whether or not the specified point is inside this rectangle. 455 * According to the contract of Shape, a point on the border is in only if 456 * it has an adjacent point inside the rectangle in either the increasing 457 * x or y direction. 458 * 459 * @param p the point to test 460 * @return true if the point is inside the rectangle 461 * @throws NullPointerException if p is null 462 * @see #contains(int, int) 463 * @since 1.1 464 */ contains(Point p)465 public boolean contains(Point p) 466 { 467 return contains (p.x, p.y); 468 } 469 470 /** 471 * Tests whether or not the specified point is inside this rectangle. 472 * According to the contract of Shape, a point on the border is in only if 473 * it has an adjacent point inside the rectangle in either the increasing 474 * x or y direction. 475 * 476 * @param x the X coordinate of the point to test 477 * @param y the Y coordinate of the point to test 478 * @return true if the point is inside the rectangle 479 * @since 1.1 480 */ contains(int x, int y)481 public boolean contains(int x, int y) 482 { 483 return inside (x, y); 484 } 485 486 /** 487 * Checks whether all points in the given rectangle are contained in this 488 * rectangle. 489 * 490 * @param r the rectangle to check 491 * @return true if r is contained in this rectangle 492 * @throws NullPointerException if r is null 493 * @see #contains(int, int, int, int) 494 * @since 1.1 495 */ contains(Rectangle r)496 public boolean contains(Rectangle r) 497 { 498 return contains (r.x, r.y, r.width, r.height); 499 } 500 501 /** 502 * Checks whether all points in the given rectangle are contained in this 503 * rectangle. 504 * 505 * @param x the x coordinate of the rectangle to check 506 * @param y the y coordinate of the rectangle to check 507 * @param w the width of the rectangle to check 508 * @param h the height of the rectangle to check 509 * @return true if the parameters are contained in this rectangle 510 * @since 1.1 511 */ contains(int x, int y, int w, int h)512 public boolean contains(int x, int y, int w, int h) 513 { 514 return width > 0 && height > 0 && w > 0 && h > 0 515 && x >= this.x && x + w <= this.x + this.width 516 && y >= this.y && y + h <= this.y + this.height; 517 } 518 519 /** 520 * Tests whether or not the specified point is inside this rectangle. 521 * 522 * @param x the X coordinate of the point to test 523 * @param y the Y coordinate of the point to test 524 * @return true if the point is inside the rectangle 525 * @deprecated use {@link #contains(int, int)} instead 526 */ inside(int x, int y)527 public boolean inside(int x, int y) 528 { 529 return width > 0 && height > 0 530 && x >= this.x && x < this.x + width 531 && y >= this.y && y < this.y + height; 532 } 533 534 /** 535 * Tests whether or not the specified rectangle intersects this rectangle. 536 * This means the two rectangles share at least one internal point. 537 * 538 * @param r the rectangle to test against 539 * @return true if the specified rectangle intersects this one 540 * @throws NullPointerException if r is null 541 * @since 1.2 542 */ intersects(Rectangle r)543 public boolean intersects(Rectangle r) 544 { 545 return r.width > 0 && r.height > 0 && width > 0 && height > 0 546 && r.x < x + width && r.x + r.width > x 547 && r.y < y + height && r.y + r.height > y; 548 } 549 550 /** 551 * Determines the rectangle which is formed by the intersection of this 552 * rectangle with the specified rectangle. If the two do not intersect, 553 * an empty rectangle will be returned (meaning the width and/or height 554 * will be non-positive). 555 * 556 * @param r the rectange to calculate the intersection with 557 * @return a new rectangle bounding the intersection 558 * @throws NullPointerException if r is null 559 */ intersection(Rectangle r)560 public Rectangle intersection(Rectangle r) 561 { 562 Rectangle res = new Rectangle(); 563 intersect(this, r, res); 564 return res; 565 } 566 567 /** 568 * Returns the smallest rectangle that contains both this rectangle 569 * and the specified rectangle. 570 * 571 * @param r the rectangle to compute the union with 572 * @return the smallest rectangle containing both rectangles 573 * @throws NullPointerException if r is null 574 */ union(Rectangle r)575 public Rectangle union(Rectangle r) 576 { 577 Rectangle res = new Rectangle(); 578 union(this, r, res); 579 return res; 580 } 581 582 /** 583 * Modifies this rectangle so that it represents the smallest rectangle 584 * that contains both the existing rectangle and the specified point. 585 * However, if the point falls on one of the two borders which are not 586 * inside the rectangle, a subsequent call to <code>contains</code> may 587 * return false. 588 * 589 * @param x the X coordinate of the point to add to this rectangle 590 * @param y the Y coordinate of the point to add to this rectangle 591 */ add(int x, int y)592 public void add(int x, int y) 593 { 594 add((double) x, (double) y); 595 } 596 597 /** 598 * Modifies this rectangle so that it represents the smallest rectangle 599 * that contains both the existing rectangle and the specified point. 600 * However, if the point falls on one of the two borders which are not 601 * inside the rectangle, a subsequent call to <code>contains</code> may 602 * return false. 603 * 604 * @param p the point to add to this rectangle 605 * @throws NullPointerException if p is null 606 */ add(Point p)607 public void add(Point p) 608 { 609 add((double) p.x, (double) p.y); 610 } 611 612 /** 613 * Modifies this rectangle so that it represents the smallest rectangle 614 * that contains both the existing rectangle and the specified rectangle. 615 * 616 * @param r the rectangle to add to this rectangle 617 * @throws NullPointerException if r is null 618 * @see #union(Rectangle) 619 */ add(Rectangle r)620 public void add(Rectangle r) 621 { 622 union(this, r, this); 623 } 624 625 /** 626 * Expands the rectangle by the specified amount. The horizontal 627 * and vertical expansion values are applied both to the X,Y coordinate 628 * of this rectangle, and its width and height. Thus the width and 629 * height will increase by 2h and 2v accordingly. 630 * 631 * @param h the horizontal expansion value 632 * @param v the vertical expansion value 633 */ grow(int h, int v)634 public void grow(int h, int v) 635 { 636 x -= h; 637 y -= v; 638 width += h + h; 639 height += v + v; 640 } 641 642 /** 643 * Tests whether or not this rectangle is empty. An empty rectangle 644 * has a non-positive width or height. 645 * 646 * @return true if the rectangle is empty 647 */ isEmpty()648 public boolean isEmpty() 649 { 650 return width <= 0 || height <= 0; 651 } 652 653 /** 654 * Determine where the point lies with respect to this rectangle. The 655 * result will be the binary OR of the appropriate bit masks. 656 * 657 * @param x the x coordinate to check 658 * @param y the y coordinate to check 659 * @return the binary OR of the result 660 * @see #OUT_LEFT 661 * @see #OUT_TOP 662 * @see #OUT_RIGHT 663 * @see #OUT_BOTTOM 664 * @since 1.2 665 */ outcode(double x, double y)666 public int outcode(double x, double y) 667 { 668 int result = 0; 669 if (width <= 0) 670 result |= OUT_LEFT | OUT_RIGHT; 671 else if (x < this.x) 672 result |= OUT_LEFT; 673 else if (x > this.x + width) 674 result |= OUT_RIGHT; 675 if (height <= 0) 676 result |= OUT_BOTTOM | OUT_TOP; 677 else if (y < this.y) // Remember that +y heads top-to-bottom. 678 result |= OUT_TOP; 679 else if (y > this.y + height) 680 result |= OUT_BOTTOM; 681 return result; 682 } 683 684 /** 685 * Determines the rectangle which is formed by the intersection of this 686 * rectangle with the specified rectangle. If the two do not intersect, 687 * an empty rectangle will be returned (meaning the width and/or height 688 * will be non-positive). 689 * 690 * @param r the rectange to calculate the intersection with 691 * @return a new rectangle bounding the intersection 692 * @throws NullPointerException if r is null 693 * @since 1.2 694 */ createIntersection(Rectangle2D r)695 public Rectangle2D createIntersection(Rectangle2D r) 696 { 697 // Favor runtime type of other rectangle. 698 Rectangle2D res = r.getBounds2D(); 699 intersect(this, r, res); 700 return res; 701 } 702 703 /** 704 * Returns the smallest rectangle that contains both this rectangle 705 * and the specified rectangle. 706 * 707 * @param r the rectangle to compute the union with 708 * @return the smallest rectangle containing both rectangles 709 * @throws NullPointerException if r is null 710 * @since 1.2 711 */ createUnion(Rectangle2D r)712 public Rectangle2D createUnion(Rectangle2D r) 713 { 714 // Favor runtime type of other rectangle. 715 Rectangle2D res = r.getBounds2D(); 716 union(this, r, res); 717 return res; 718 } 719 720 /** 721 * Tests this rectangle for equality against the specified object. This 722 * will be true if an only if the specified object is an instance of 723 * Rectangle2D with the same coordinates and dimensions. 724 * 725 * @param obj the object to test against for equality 726 * @return true if the specified object is equal to this one 727 */ equals(Object obj)728 public boolean equals(Object obj) 729 { 730 // NOTE: No special hashCode() method is required for this class, 731 // as this equals() implementation is functionally equivalent to 732 // super.equals(), which does define a proper hashCode(). 733 734 if (! (obj instanceof Rectangle2D)) 735 return false; 736 Rectangle2D r = (Rectangle2D) obj; 737 return r.getX() == x && r.getY() == y 738 && r.getWidth() == width && r.getHeight() == height; 739 } 740 741 /** 742 * Returns a string representation of this rectangle. This is in the form 743 * <code>getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width 744 * + ",height=" + height + ']'</code>. 745 * 746 * @return a string representation of this rectangle 747 */ toString()748 public String toString() 749 { 750 return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width 751 + ",height=" + height + ']'; 752 } 753 } // class Rectangle 754