Frames | No Frames |
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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 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: */ 748: public String toString() 749: { 750: return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width 751: + ",height=" + height + ']'; 752: } 753: } // class Rectangle