001    /* Rectangle.java -- represents a graphics rectangle
002       Copyright (C) 1999, 2000, 2001, 2002, 2006, Free Software Foundation
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.awt;
040    
041    import java.awt.geom.Rectangle2D;
042    import java.io.Serializable;
043    
044    /**
045     * This class represents a rectangle and all the interesting things you
046     * might want to do with it.  Note that the coordinate system uses
047     * the origin (0,0) as the top left of the screen, with the x and y
048     * values increasing as they move to the right and down respectively.
049     *
050     * <p>It is valid for a rectangle to have negative width or height; but it
051     * is considered to have no area or internal points. Therefore, the behavior
052     * in methods like <code>contains</code> or <code>intersects</code> is
053     * undefined unless the rectangle has positive width and height.
054     *
055     * <p>There are some public fields; if you mess with them in an inconsistent
056     * manner, it is your own fault when you get NullPointerException,
057     * ArrayIndexOutOfBoundsException, or invalid results. Also, this class is
058     * not threadsafe.
059     *
060     * @author Warren Levy  (warrenl@cygnus.com)
061     * @author Aaron M. Renn (arenn@urbanophile.com)
062     * @author Eric Blake (ebb9@email.byu.edu)
063     * @since 1.0
064     * @status updated to 1.4
065     */
066    public class Rectangle extends Rectangle2D implements Shape, Serializable
067    {
068      /**
069       * Compatible with JDK 1.0+.
070       */
071      private static final long serialVersionUID = -4345857070255674764L;
072    
073      /**
074       * The X coordinate of the top-left corner of the rectangle.
075       *
076       * @see #setLocation(int, int)
077       * @see #getLocation()
078       * @serial the x coordinate
079       */
080      public int x;
081    
082      /**
083       * The Y coordinate of the top-left corner of the rectangle.
084       *
085       * @see #setLocation(int, int)
086       * @see #getLocation()
087       * @serial the y coordinate
088       */
089      public int y;
090    
091      /**
092       * The width of the rectangle.
093       *
094       * @see #setSize(int, int)
095       * @see #getSize()
096       * @serial
097       */
098      public int width;
099    
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