Source for java.awt.geom.Rectangle2D

   1: /* Rectangle2D.java -- generic rectangles in 2-D space
   2:    Copyright (C) 2000, 2001, 2002, 2004  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.geom;
  40: 
  41: import java.util.NoSuchElementException;
  42: 
  43: /**
  44:  * This class describes a rectangle by a point (x,y) and dimension (w x h).
  45:  * The actual storage is left up to subclasses.
  46:  *
  47:  * <p>It is valid for a rectangle to have negative width or height; but it
  48:  * is considered to have no area or internal points. Therefore, the behavior
  49:  * in methods like <code>contains</code> or <code>intersects</code> is
  50:  * undefined unless the rectangle has positive width and height.
  51:  *
  52:  * @author Tom Tromey (tromey@cygnus.com)
  53:  * @author Eric Blake (ebb9@email.byu.edu)
  54:  * @since 1.2
  55:  * @status updated to 1.4
  56:  */
  57: public abstract class Rectangle2D extends RectangularShape
  58: {
  59:   /**
  60:    * The point lies left of the rectangle (p.x &lt; r.x).
  61:    *
  62:    * @see #outcode(double, double)
  63:    */
  64:   public static final int OUT_LEFT = 1;
  65: 
  66:   /**
  67:    * The point lies above the rectangle (p.y &lt; r.y).
  68:    *
  69:    * @see #outcode(double, double)
  70:    */
  71:   public static final int OUT_TOP = 2;
  72: 
  73:   /**
  74:    * The point lies right of the rectangle (p.x &gt; r.maxX).
  75:    *
  76:    * @see #outcode(double, double)
  77:    */
  78:   public static final int OUT_RIGHT = 4;
  79: 
  80:   /**
  81:    * The point lies below of the rectangle (p.y &gt; r.maxY).
  82:    *
  83:    * @see #outcode(double, double)
  84:    */
  85:   public static final int OUT_BOTTOM = 8;
  86: 
  87:   /**
  88:    * Default constructor.
  89:    */
  90:   protected Rectangle2D()
  91:   {
  92:   }
  93: 
  94:   /**
  95:    * Set the bounding box of this rectangle.
  96:    *
  97:    * @param x the new X coordinate
  98:    * @param y the new Y coordinate
  99:    * @param w the new width
 100:    * @param h the new height
 101:    */
 102:   public abstract void setRect(double x, double y, double w, double h);
 103: 
 104:   /**
 105:    * Set the bounding box of this rectangle from the given one.
 106:    *
 107:    * @param r rectangle to copy
 108:    * @throws NullPointerException if r is null
 109:    */
 110:   public void setRect(Rectangle2D r)
 111:   {
 112:     setRect(r.getX(), r.getY(), r.getWidth(), r.getHeight());
 113:   }
 114: 
 115:   /**
 116:    * Tests if the specified line intersects the interior of this rectangle.
 117:    *
 118:    * @param x1 the first x coordinate of line segment
 119:    * @param y1 the first y coordinate of line segment
 120:    * @param x2 the second x coordinate of line segment
 121:    * @param y2 the second y coordinate of line segment
 122:    * @return true if the line intersects the rectangle
 123:    */
 124:   public boolean intersectsLine(double x1, double y1, double x2, double y2)
 125:   {
 126:     double x = getX();
 127:     double y = getY();
 128:     double w = getWidth();
 129:     double h = getHeight();
 130:     if (w <= 0 || h <= 0)
 131:       return false;
 132: 
 133:     if (x1 >= x && x1 <= x + w && y1 >= y && y1 <= y + h)
 134:       return true;
 135:     if (x2 >= x && x2 <= x + w && y2 >= y && y2 <= y + h)
 136:       return true;
 137: 
 138:     double x3 = x + w;
 139:     double y3 = y + h;
 140: 
 141:     return (Line2D.linesIntersect(x1, y1, x2, y2, x, y, x, y3)
 142:             || Line2D.linesIntersect(x1, y1, x2, y2, x, y3, x3, y3)
 143:             || Line2D.linesIntersect(x1, y1, x2, y2, x3, y3, x3, y)
 144:             || Line2D.linesIntersect(x1, y1, x2, y2, x3, y, x, y));
 145:   }
 146: 
 147:   /**
 148:    * Tests if the specified line intersects the interior of this rectangle.
 149:    *
 150:    * @param l the line segment
 151:    * @return true if the line intersects the rectangle
 152:    * @throws NullPointerException if l is null
 153:    */
 154:   public boolean intersectsLine(Line2D l)
 155:   {
 156:     return intersectsLine(l.getX1(), l.getY1(), l.getX2(), l.getY2());
 157:   }
 158: 
 159:   /**
 160:    * Determine where the point lies with respect to this rectangle. The
 161:    * result will be the binary OR of the appropriate bit masks.
 162:    *
 163:    * @param x the x coordinate to check
 164:    * @param y the y coordinate to check
 165:    * @return the binary OR of the result
 166:    * @see #OUT_LEFT
 167:    * @see #OUT_TOP
 168:    * @see #OUT_RIGHT
 169:    * @see #OUT_BOTTOM
 170:    */
 171:   public abstract int outcode(double x, double y);
 172: 
 173:   /**
 174:    * Determine where the point lies with respect to this rectangle. The
 175:    * result will be the binary OR of the appropriate bit masks.
 176:    *
 177:    * @param p the point to check
 178:    * @return the binary OR of the result
 179:    * @throws NullPointerException if p is null
 180:    * @see #OUT_LEFT
 181:    * @see #OUT_TOP
 182:    * @see #OUT_RIGHT
 183:    * @see #OUT_BOTTOM
 184:    */
 185:   public int outcode(Point2D p)
 186:   {
 187:     return outcode(p.getX(), p.getY());
 188:   }
 189: 
 190:   /**
 191:    * Set the bounding box of this rectangle.
 192:    *
 193:    * @param x the new X coordinate
 194:    * @param y the new Y coordinate
 195:    * @param w the new width
 196:    * @param h the new height
 197:    */
 198:   public void setFrame(double x, double y, double w, double h)
 199:   {
 200:     setRect(x, y, w, h);
 201:   }
 202: 
 203:   /**
 204:    * Returns the bounds of this rectangle. A pretty useless method, as this
 205:    * is already a rectangle.
 206:    *
 207:    * @return a copy of this rectangle
 208:    */
 209:   public Rectangle2D getBounds2D()
 210:   {
 211:     return (Rectangle2D) clone();
 212:   }
 213: 
 214:   /**
 215:    * Test if the given point is contained in the rectangle.
 216:    *
 217:    * @param x the x coordinate of the point
 218:    * @param y the y coordinate of the point
 219:    * @return true if (x,y) is in the rectangle
 220:    */
 221:   public boolean contains(double x, double y)
 222:   {
 223:     double mx = getX();
 224:     double my = getY();
 225:     double w = getWidth();
 226:     double h = getHeight();
 227:     return w > 0 && h > 0 && x >= mx && x < mx + w && y >= my && y < my + h;
 228:   }
 229: 
 230:   /**
 231:    * Tests if the given rectangle intersects this one. In other words, test if
 232:    * the two rectangles share at least one internal point.
 233:    *
 234:    * @param x the x coordinate of the other rectangle
 235:    * @param y the y coordinate of the other rectangle
 236:    * @param w the width of the other rectangle
 237:    * @param h the height of the other rectangle
 238:    * @return true if the rectangles intersect
 239:    */
 240:   public boolean intersects(double x, double y, double w, double h)
 241:   {
 242:     double mx = getX();
 243:     double my = getY();
 244:     double mw = getWidth();
 245:     double mh = getHeight();
 246:     return w > 0 && h > 0 && mw > 0 && mh > 0
 247:       && x < mx + mw && x + w > mx && y < my + mh && y + h > my;
 248:   }
 249: 
 250:   /**
 251:    * Tests if this rectangle contains the given one. In other words, test if
 252:    * this rectangle contains all points in the given one.
 253:    *
 254:    * @param x the x coordinate of the other rectangle
 255:    * @param y the y coordinate of the other rectangle
 256:    * @param w the width of the other rectangle
 257:    * @param h the height of the other rectangle
 258:    * @return true if this rectangle contains the other
 259:    */
 260:   public boolean contains(double x, double y, double w, double h)
 261:   {
 262:     double mx = getX();
 263:     double my = getY();
 264:     double mw = getWidth();
 265:     double mh = getHeight();
 266:     return w > 0 && h > 0 && mw > 0 && mh > 0
 267:       && x >= mx && x + w <= mx + mw && y >= my && y + h <= my + mh;
 268:   }
 269: 
 270:   /**
 271:    * Return a new rectangle which is the intersection of this and the given
 272:    * one. The result will be empty if there is no intersection.
 273:    *
 274:    * @param r the rectangle to be intersected
 275:    * @return the intersection
 276:    * @throws NullPointerException if r is null
 277:    */
 278:   public abstract Rectangle2D createIntersection(Rectangle2D r);
 279: 
 280:   /**
 281:    * Intersects a pair of rectangles, and places the result in the
 282:    * destination; this can be used to avoid object creation. This method
 283:    * even works when the destination is also a source, although you stand
 284:    * to lose the original data.
 285:    *
 286:    * @param src1 the first source
 287:    * @param src2 the second source
 288:    * @param dest the destination for the intersection
 289:    * @throws NullPointerException if any rectangle is null
 290:    */
 291:   public static void intersect(Rectangle2D src1, Rectangle2D src2,
 292:                                Rectangle2D dest)
 293:   {
 294:     double x = Math.max(src1.getX(), src2.getX());
 295:     double y = Math.max(src1.getY(), src2.getY());
 296:     double maxx = Math.min(src1.getMaxX(), src2.getMaxX());
 297:     double maxy = Math.min(src1.getMaxY(), src2.getMaxY());
 298:     dest.setRect(x, y, maxx - x, maxy - y);
 299:   }
 300: 
 301:   /**
 302:    * Return a new rectangle which is the union of this and the given one.
 303:    *
 304:    * @param r the rectangle to be merged
 305:    * @return the union
 306:    * @throws NullPointerException if r is null
 307:    */
 308:   public abstract Rectangle2D createUnion(Rectangle2D r);
 309: 
 310:   /**
 311:    * Joins a pair of rectangles, and places the result in the destination;
 312:    * this can be used to avoid object creation. This method even works when
 313:    * the destination is also a source, although you stand to lose the
 314:    * original data.
 315:    *
 316:    * @param src1 the first source
 317:    * @param src2 the second source
 318:    * @param dest the destination for the union
 319:    * @throws NullPointerException if any rectangle is null
 320:    */
 321:   public static void union(Rectangle2D src1, Rectangle2D src2,
 322:                            Rectangle2D dest)
 323:   {
 324:     double x = Math.min(src1.getX(), src2.getX());
 325:     double y = Math.min(src1.getY(), src2.getY());
 326:     double maxx = Math.max(src1.getMaxX(), src2.getMaxX());
 327:     double maxy = Math.max(src1.getMaxY(), src2.getMaxY());
 328:     dest.setRect(x, y, maxx - x, maxy - y);
 329:   }
 330: 
 331:   /**
 332:    * Modifies this rectangle so that it represents the smallest rectangle
 333:    * that contains both the existing rectangle and the specified point.
 334:    * However, if the point falls on one of the two borders which are not
 335:    * inside the rectangle, a subsequent call to <code>contains</code> may
 336:    * return false.
 337:    *
 338:    * @param newx the X coordinate of the point to add to this rectangle
 339:    * @param newy the Y coordinate of the point to add to this rectangle
 340:    */
 341:   public void add(double newx, double newy)
 342:   {
 343:     double minx = Math.min(getX(), newx);
 344:     double maxx = Math.max(getMaxX(), newx);
 345:     double miny = Math.min(getY(), newy);
 346:     double maxy = Math.max(getMaxY(), newy);
 347:     setRect(minx, miny, maxx - minx, maxy - miny);
 348:   }
 349: 
 350:   /**
 351:    * Modifies this rectangle so that it represents the smallest rectangle
 352:    * that contains both the existing rectangle and the specified point.
 353:    * However, if the point falls on one of the two borders which are not
 354:    * inside the rectangle, a subsequent call to <code>contains</code> may
 355:    * return false.
 356:    *
 357:    * @param p the point to add to this rectangle
 358:    * @throws NullPointerException if p is null
 359:    */
 360:   public void add(Point2D p)
 361:   {
 362:     add(p.getX(), p.getY());
 363:   }
 364: 
 365:   /**
 366:    * Modifies this rectangle so that it represents the smallest rectangle
 367:    * that contains both the existing rectangle and the specified rectangle.
 368:    *
 369:    * @param r the rectangle to add to this rectangle
 370:    * @throws NullPointerException if r is null
 371:    * @see #union(Rectangle2D, Rectangle2D, Rectangle2D)
 372:    */
 373:   public void add(Rectangle2D r)
 374:   {
 375:     union(this, r, this);
 376:   }
 377: 
 378:   /**
 379:    * Return an iterator along the shape boundary. If the optional transform
 380:    * is provided, the iterator is transformed accordingly. Each call returns
 381:    * a new object, independent from others in use. This iterator is thread
 382:    * safe; modifications to the rectangle do not affect the results of this
 383:    * path instance.
 384:    *
 385:    * @param at an optional transform to apply to the iterator
 386:    * @return a new iterator over the boundary
 387:    * @since 1.2
 388:    */
 389:   public PathIterator getPathIterator(final AffineTransform at)
 390:   {
 391:     final double minx = getX();
 392:     final double miny = getY();
 393:     final double maxx = minx + getWidth();
 394:     final double maxy = miny + getHeight();
 395:     return new PathIterator()
 396:     {
 397:       /** Current coordinate. */
 398:       private int current = (maxx <= minx && maxy <= miny) ? 6 : 0;
 399: 
 400:       public int getWindingRule()
 401:       {
 402:         // A test program showed that Sun J2SE 1.3.1 and 1.4.1_01
 403:         // return WIND_NON_ZERO paths.  While this does not really
 404:         // make any difference for rectangles (because they are not
 405:         // self-intersecting), it seems appropriate to behave
 406:         // identically.
 407: 
 408:         return WIND_NON_ZERO;
 409:       }
 410: 
 411:       public boolean isDone()
 412:       {
 413:         return current > 5;
 414:       }
 415: 
 416:       public void next()
 417:       {
 418:         current++;
 419:       }
 420: 
 421:       public int currentSegment(float[] coords)
 422:       {
 423:         switch (current)
 424:           {
 425:           case 1:
 426:             coords[0] = (float) maxx;
 427:             coords[1] = (float) miny;
 428:             break;
 429:           case 2:
 430:             coords[0] = (float) maxx;
 431:             coords[1] = (float) maxy;
 432:             break;
 433:           case 3:
 434:             coords[0] = (float) minx;
 435:             coords[1] = (float) maxy;
 436:             break;
 437:           case 0:
 438:           case 4:
 439:             coords[0] = (float) minx;
 440:             coords[1] = (float) miny;
 441:             break;
 442:           case 5:
 443:             return SEG_CLOSE;
 444:           default:
 445:             throw new NoSuchElementException("rect iterator out of bounds");
 446:           }
 447:         if (at != null)
 448:           at.transform(coords, 0, coords, 0, 1);
 449:         return current == 0 ? SEG_MOVETO : SEG_LINETO;
 450:       }
 451: 
 452:       public int currentSegment(double[] coords)
 453:       {
 454:         switch (current)
 455:           {
 456:           case 1:
 457:             coords[0] = maxx;
 458:             coords[1] = miny;
 459:             break;
 460:           case 2:
 461:             coords[0] = maxx;
 462:             coords[1] = maxy;
 463:             break;
 464:           case 3:
 465:             coords[0] = minx;
 466:             coords[1] = maxy;
 467:             break;
 468:           case 0:
 469:           case 4:
 470:             coords[0] = minx;
 471:             coords[1] = miny;
 472:             break;
 473:           case 5:
 474:             return SEG_CLOSE;
 475:           default:
 476:             throw new NoSuchElementException("rect iterator out of bounds");
 477:           }
 478:         if (at != null)
 479:           at.transform(coords, 0, coords, 0, 1);
 480:         return current == 0 ? SEG_MOVETO : SEG_LINETO;
 481:       }
 482:     };
 483:   }
 484: 
 485:   /**
 486:    * Return an iterator along the shape boundary. If the optional transform
 487:    * is provided, the iterator is transformed accordingly. Each call returns
 488:    * a new object, independent from others in use. This iterator is thread
 489:    * safe; modifications to the rectangle do not affect the results of this
 490:    * path instance. As the rectangle is already flat, the flatness parameter
 491:    * is ignored.
 492:    *
 493:    * @param at an optional transform to apply to the iterator
 494:    * @param flatness the maximum distance for deviation from the real boundary
 495:    * @return a new iterator over the boundary
 496:    * @since 1.2
 497:    */
 498:   public PathIterator getPathIterator(AffineTransform at, double flatness)
 499:   {
 500:     return getPathIterator(at);
 501:   }
 502: 
 503:   /**
 504:    * Return the hashcode for this rectangle. The formula is not documented, but
 505:    * appears to be the same as:
 506:    * <pre>
 507:    * long l = Double.doubleToLongBits(getX())
 508:    *   + 37 * Double.doubleToLongBits(getY())
 509:    *   + 43 * Double.doubleToLongBits(getWidth())
 510:    *   + 47 * Double.doubleToLongBits(getHeight());
 511:    * return (int) ((l &gt;&gt; 32) ^ l);
 512:    * </pre>
 513:    *
 514:    * @return the hashcode
 515:    */
 516:   public int hashCode()
 517:   {
 518:     // Talk about a fun time reverse engineering this one!
 519:     long l = java.lang.Double.doubleToLongBits(getX())
 520:       + 37 * java.lang.Double.doubleToLongBits(getY())
 521:       + 43 * java.lang.Double.doubleToLongBits(getWidth())
 522:       + 47 * java.lang.Double.doubleToLongBits(getHeight());
 523:     return (int) ((l >> 32) ^ l);
 524:   }
 525: 
 526:   /**
 527:    * Tests this rectangle for equality against the specified object.  This
 528:    * will be true if an only if the specified object is an instance of
 529:    * Rectangle2D with the same coordinates and dimensions.
 530:    *
 531:    * @param obj the object to test against for equality
 532:    * @return true if the specified object is equal to this one
 533:    */
 534:   public boolean equals(Object obj)
 535:   {
 536:     if (! (obj instanceof Rectangle2D))
 537:       return false;
 538:     Rectangle2D r = (Rectangle2D) obj;
 539:     return r.getX() == getX() && r.getY() == getY()
 540:       && r.getWidth() == getWidth() && r.getHeight() == getHeight();
 541:   }
 542: 
 543:   /**
 544:    * This class defines a rectangle in <code>double</code> precision.
 545:    *
 546:    * @author Eric Blake (ebb9@email.byu.edu)
 547:    * @since 1.2
 548:    * @status updated to 1.4
 549:    */
 550:   public static class Double extends Rectangle2D
 551:   {
 552:     /** The x coordinate of the lower left corner. */
 553:     public double x;
 554: 
 555:     /** The y coordinate of the lower left corner. */
 556:     public double y;
 557: 
 558:     /** The width of the rectangle. */
 559:     public double width;
 560: 
 561:     /** The height of the rectangle. */
 562:     public double height;
 563: 
 564:     /**
 565:      * Create a rectangle at (0,0) with width 0 and height 0.
 566:      */
 567:     public Double()
 568:     {
 569:     }
 570: 
 571:     /**
 572:      * Create a rectangle with the given values.
 573:      *
 574:      * @param x the x coordinate
 575:      * @param y the y coordinate
 576:      * @param w the width
 577:      * @param h the height
 578:      */
 579:     public Double(double x, double y, double w, double h)
 580:     {
 581:       this.x = x;
 582:       this.y = y;
 583:       width = w;
 584:       height = h;
 585:     }
 586: 
 587:     /**
 588:      * Return the X coordinate.
 589:      *
 590:      * @return the value of x
 591:      */
 592:     public double getX()
 593:     {
 594:       return x;
 595:     }
 596: 
 597:     /**
 598:      * Return the Y coordinate.
 599:      *
 600:      * @return the value of y
 601:      */
 602:     public double getY()
 603:     {
 604:       return y;
 605:     }
 606: 
 607:     /**
 608:      * Return the width.
 609:      *
 610:      * @return the value of width
 611:      */
 612:     public double getWidth()
 613:     {
 614:       return width;
 615:     }
 616: 
 617:     /**
 618:      * Return the height.
 619:      *
 620:      * @return the value of height
 621:      */
 622:     public double getHeight()
 623:     {
 624:       return height;
 625:     }
 626: 
 627:     /**
 628:      * Test if the rectangle is empty.
 629:      *
 630:      * @return true if width or height is not positive
 631:      */
 632:     public boolean isEmpty()
 633:     {
 634:       return width <= 0 || height <= 0;
 635:     }
 636: 
 637:     /**
 638:      * Set the contents of this rectangle to those specified.
 639:      *
 640:      * @param x the x coordinate
 641:      * @param y the y coordinate
 642:      * @param w the width
 643:      * @param h the height
 644:      */
 645:     public void setRect(double x, double y, double w, double h)
 646:     {
 647:       this.x = x;
 648:       this.y = y;
 649:       width = w;
 650:       height = h;
 651:     }
 652: 
 653:     /**
 654:      * Set the contents of this rectangle to those specified.
 655:      *
 656:      * @param r the rectangle to copy
 657:      * @throws NullPointerException if r is null
 658:      */
 659:     public void setRect(Rectangle2D r)
 660:     {
 661:       x = r.getX();
 662:       y = r.getY();
 663:       width = r.getWidth();
 664:       height = r.getHeight();
 665:     }
 666: 
 667:     /**
 668:      * Determine where the point lies with respect to this rectangle. The
 669:      * result will be the binary OR of the appropriate bit masks.
 670:      *
 671:      * @param x the x coordinate to check
 672:      * @param y the y coordinate to check
 673:      * @return the binary OR of the result
 674:      * @see #OUT_LEFT
 675:      * @see #OUT_TOP
 676:      * @see #OUT_RIGHT
 677:      * @see #OUT_BOTTOM
 678:      * @since 1.2
 679:      */
 680:     public int outcode(double x, double y)
 681:     {
 682:       int result = 0;
 683:       if (width <= 0)
 684:         result |= OUT_LEFT | OUT_RIGHT;
 685:       else if (x < this.x)
 686:         result |= OUT_LEFT;
 687:       else if (x > this.x + width)
 688:         result |= OUT_RIGHT;
 689:       if (height <= 0)
 690:         result |= OUT_BOTTOM | OUT_TOP;
 691:       else if (y < this.y) // Remember that +y heads top-to-bottom.
 692:         result |= OUT_TOP;
 693:       else if (y > this.y + height)
 694:         result |= OUT_BOTTOM;
 695:       return result;
 696:     }
 697: 
 698:     /**
 699:      * Returns the bounds of this rectangle. A pretty useless method, as this
 700:      * is already a rectangle.
 701:      *
 702:      * @return a copy of this rectangle
 703:      */
 704:     public Rectangle2D getBounds2D()
 705:     {
 706:       return new Double(x, y, width, height);
 707:     }
 708: 
 709:     /**
 710:      * Return a new rectangle which is the intersection of this and the given
 711:      * one. The result will be empty if there is no intersection.
 712:      *
 713:      * @param r the rectangle to be intersected
 714:      * @return the intersection
 715:      * @throws NullPointerException if r is null
 716:      */
 717:     public Rectangle2D createIntersection(Rectangle2D r)
 718:     {
 719:       Double res = new Double();
 720:       intersect(this, r, res);
 721:       return res;
 722:     }
 723: 
 724:     /**
 725:      * Return a new rectangle which is the union of this and the given one.
 726:      *
 727:      * @param r the rectangle to be merged
 728:      * @return the union
 729:      * @throws NullPointerException if r is null
 730:      */
 731:     public Rectangle2D createUnion(Rectangle2D r)
 732:     {
 733:       Double res = new Double();
 734:       union(this, r, res);
 735:       return res;
 736:     }
 737: 
 738:     /**
 739:      * Returns a string representation of this rectangle. This is in the form
 740:      * <code>getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width
 741:      * + ",h=" + height + ']'</code>.
 742:      *
 743:      * @return a string representation of this rectangle
 744:      */
 745:     public String toString()
 746:     {
 747:       return getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width
 748:         + ",h=" + height + ']';
 749:     }
 750:   }
 751: 
 752:   /**
 753:    * This class defines a rectangle in <code>float</code> precision.
 754:    *
 755:    * @author Eric Blake (ebb9@email.byu.edu)
 756:    * @since 1.2
 757:    * @status updated to 1.4
 758:    */
 759:   public static class Float extends Rectangle2D
 760:   {
 761:     /** The x coordinate of the lower left corner. */
 762:     public float x;
 763: 
 764:     /** The y coordinate of the lower left corner. */
 765:     public float y;
 766: 
 767:     /** The width of the rectangle. */
 768:     public float width;
 769: 
 770:     /** The height of the rectangle. */
 771:     public float height;
 772: 
 773:     /**
 774:      * Create a rectangle at (0,0) with width 0 and height 0.
 775:      */
 776:     public Float()
 777:     {
 778:     }
 779: 
 780:     /**
 781:      * Create a rectangle with the given values.
 782:      *
 783:      * @param x the x coordinate
 784:      * @param y the y coordinate
 785:      * @param w the width
 786:      * @param h the height
 787:      */
 788:     public Float(float x, float y, float w, float h)
 789:     {
 790:       this.x = x;
 791:       this.y = y;
 792:       width = w;
 793:       height = h;
 794:     }
 795: 
 796:     /**
 797:      * Create a rectangle with the given values.
 798:      *
 799:      * @param x the x coordinate
 800:      * @param y the y coordinate
 801:      * @param w the width
 802:      * @param h the height
 803:      */
 804:     Float(double x, double y, double w, double h)
 805:     {
 806:       this.x = (float) x;
 807:       this.y = (float) y;
 808:       width = (float) w;
 809:       height = (float) h;
 810:     }
 811: 
 812:     /**
 813:      * Return the X coordinate.
 814:      *
 815:      * @return the value of x
 816:      */
 817:     public double getX()
 818:     {
 819:       return x;
 820:     }
 821: 
 822:     /**
 823:      * Return the Y coordinate.
 824:      *
 825:      * @return the value of y
 826:      */
 827:     public double getY()
 828:     {
 829:       return y;
 830:     }
 831: 
 832:     /**
 833:      * Return the width.
 834:      *
 835:      * @return the value of width
 836:      */
 837:     public double getWidth()
 838:     {
 839:       return width;
 840:     }
 841: 
 842:     /**
 843:      * Return the height.
 844:      *
 845:      * @return the value of height
 846:      */
 847:     public double getHeight()
 848:     {
 849:       return height;
 850:     }
 851: 
 852:     /**
 853:      * Test if the rectangle is empty.
 854:      *
 855:      * @return true if width or height is not positive
 856:      */
 857:     public boolean isEmpty()
 858:     {
 859:       return width <= 0 || height <= 0;
 860:     }
 861: 
 862:     /**
 863:      * Set the contents of this rectangle to those specified.
 864:      *
 865:      * @param x the x coordinate
 866:      * @param y the y coordinate
 867:      * @param w the width
 868:      * @param h the height
 869:      */
 870:     public void setRect(float x, float y, float w, float h)
 871:     {
 872:       this.x = x;
 873:       this.y = y;
 874:       width = w;
 875:       height = h;
 876:     }
 877: 
 878:     /**
 879:      * Set the contents of this rectangle to those specified.
 880:      *
 881:      * @param x the x coordinate
 882:      * @param y the y coordinate
 883:      * @param w the width
 884:      * @param h the height
 885:      */
 886:     public void setRect(double x, double y, double w, double h)
 887:     {
 888:       this.x = (float) x;
 889:       this.y = (float) y;
 890:       width = (float) w;
 891:       height = (float) h;
 892:     }
 893: 
 894:     /**
 895:      * Set the contents of this rectangle to those specified.
 896:      *
 897:      * @param r the rectangle to copy
 898:      * @throws NullPointerException if r is null
 899:      */
 900:     public void setRect(Rectangle2D r)
 901:     {
 902:       x = (float) r.getX();
 903:       y = (float) r.getY();
 904:       width = (float) r.getWidth();
 905:       height = (float) r.getHeight();
 906:     }
 907: 
 908:     /**
 909:      * Determine where the point lies with respect to this rectangle. The
 910:      * result will be the binary OR of the appropriate bit masks.
 911:      *
 912:      * @param x the x coordinate to check
 913:      * @param y the y coordinate to check
 914:      * @return the binary OR of the result
 915:      * @see #OUT_LEFT
 916:      * @see #OUT_TOP
 917:      * @see #OUT_RIGHT
 918:      * @see #OUT_BOTTOM
 919:      * @since 1.2
 920:      */
 921:     public int outcode(double x, double y)
 922:     {
 923:       int result = 0;
 924:       if (width <= 0)
 925:         result |= OUT_LEFT | OUT_RIGHT;
 926:       else if (x < this.x)
 927:         result |= OUT_LEFT;
 928:       else if (x > this.x + width)
 929:         result |= OUT_RIGHT;
 930:       if (height <= 0)
 931:         result |= OUT_BOTTOM | OUT_TOP;
 932:       else if (y < this.y) // Remember that +y heads top-to-bottom.
 933:         result |= OUT_TOP;
 934:       else if (y > this.y + height)
 935:         result |= OUT_BOTTOM;
 936:       return result;
 937:     }
 938: 
 939:     /**
 940:      * Returns the bounds of this rectangle. A pretty useless method, as this
 941:      * is already a rectangle.
 942:      *
 943:      * @return a copy of this rectangle
 944:      */
 945:     public Rectangle2D getBounds2D()
 946:     {
 947:       return new Float(x, y, width, height);
 948:     }
 949: 
 950:     /**
 951:      * Return a new rectangle which is the intersection of this and the given
 952:      * one. The result will be empty if there is no intersection.
 953:      *
 954:      * @param r the rectangle to be intersected
 955:      * @return the intersection
 956:      * @throws NullPointerException if r is null
 957:      */
 958:     public Rectangle2D createIntersection(Rectangle2D r)
 959:     {
 960:       Float res = new Float();
 961:       intersect(this, r, res);
 962:       return res;
 963:     }
 964: 
 965:     /**
 966:      * Return a new rectangle which is the union of this and the given one.
 967:      *
 968:      * @param r the rectangle to be merged
 969:      * @return the union
 970:      * @throws NullPointerException if r is null
 971:      */
 972:     public Rectangle2D createUnion(Rectangle2D r)
 973:     {
 974:       Float res = new Float();
 975:       union(this, r, res);
 976:       return res;
 977:     }
 978: 
 979:     /**
 980:      * Returns a string representation of this rectangle. This is in the form
 981:      * <code>getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width
 982:      * + ",h=" + height + ']'</code>.
 983:      *
 984:      * @return a string representation of this rectangle
 985:      */
 986:     public String toString()
 987:     {
 988:       return getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width
 989:         + ",h=" + height + ']';
 990:     }
 991:   }
 992: }