001/* Rectangle2D.java -- generic rectangles in 2-D space
002   Copyright (C) 2000, 2001, 2002, 2004  Free Software Foundation
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package java.awt.geom;
040
041import java.util.NoSuchElementException;
042
043/**
044 * This class describes a rectangle by a point (x,y) and dimension (w x h).
045 * The actual storage is left up to subclasses.
046 *
047 * <p>It is valid for a rectangle to have negative width or height; but it
048 * is considered to have no area or internal points. Therefore, the behavior
049 * in methods like <code>contains</code> or <code>intersects</code> is
050 * undefined unless the rectangle has positive width and height.
051 *
052 * @author Tom Tromey (tromey@cygnus.com)
053 * @author Eric Blake (ebb9@email.byu.edu)
054 * @since 1.2
055 * @status updated to 1.4
056 */
057public abstract class Rectangle2D extends RectangularShape
058{
059  /**
060   * The point lies left of the rectangle (p.x &lt; r.x).
061   *
062   * @see #outcode(double, double)
063   */
064  public static final int OUT_LEFT = 1;
065
066  /**
067   * The point lies above the rectangle (p.y &lt; r.y).
068   *
069   * @see #outcode(double, double)
070   */
071  public static final int OUT_TOP = 2;
072
073  /**
074   * The point lies right of the rectangle (p.x &gt; r.maxX).
075   *
076   * @see #outcode(double, double)
077   */
078  public static final int OUT_RIGHT = 4;
079
080  /**
081   * The point lies below of the rectangle (p.y &gt; r.maxY).
082   *
083   * @see #outcode(double, double)
084   */
085  public static final int OUT_BOTTOM = 8;
086
087  /**
088   * Default constructor.
089   */
090  protected Rectangle2D()
091  {
092  }
093
094  /**
095   * Set the bounding box of this rectangle.
096   *
097   * @param x the new X coordinate
098   * @param y the new Y coordinate
099   * @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}