Merge from the pain train
[official-gcc.git] / libjava / java / awt / geom / Rectangle2D.java
blobd8217fecdb5d8b6467c047440fa741b6062cb5c5
1 /* Rectangle2D.java -- generic rectangles in 2-D space
2 Copyright (C) 2000, 2001, 2002, 2004 Free Software Foundation
4 This file is part of GNU Classpath.
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
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.
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. */
39 package java.awt.geom;
41 import java.util.NoSuchElementException;
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.
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.
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
57 public abstract class Rectangle2D extends RectangularShape
59 /**
60 * The point lies left of the rectangle (p.x &lt; r.x).
62 * @see #outcode(double, double)
64 public static final int OUT_LEFT = 1;
66 /**
67 * The point lies above the rectangle (p.y &lt; r.y).
69 * @see #outcode(double, double)
71 public static final int OUT_TOP = 2;
73 /**
74 * The point lies right of the rectangle (p.x &gt; r.maxX).
76 * @see #outcode(double, double)
78 public static final int OUT_RIGHT = 4;
80 /**
81 * The point lies below of the rectangle (p.y &gt; r.maxY).
83 * @see #outcode(double, double)
85 public static final int OUT_BOTTOM = 8;
87 /**
88 * Default constructor.
90 protected Rectangle2D()
94 /**
95 * Set the bounding box of this rectangle.
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
102 public abstract void setRect(double x, double y, double w, double h);
105 * Set the bounding box of this rectangle from the given one.
107 * @param r rectangle to copy
108 * @throws NullPointerException if r is null
110 public void setRect(Rectangle2D r)
112 setRect(r.getX(), r.getY(), r.getWidth(), r.getHeight());
116 * Tests if the specified line intersects the interior of this rectangle.
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
124 public boolean intersectsLine(double x1, double y1, double x2, double y2)
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;
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;
138 double x3 = x + w;
139 double y3 = y + h;
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));
148 * Tests if the specified line intersects the interior of this rectangle.
150 * @param l the line segment
151 * @return true if the line intersects the rectangle
152 * @throws NullPointerException if l is null
154 public boolean intersectsLine(Line2D l)
156 return intersectsLine(l.getX1(), l.getY1(), l.getX2(), l.getY2());
160 * Determine where the point lies with respect to this rectangle. The
161 * result will be the binary OR of the appropriate bit masks.
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
171 public abstract int outcode(double x, double y);
174 * Determine where the point lies with respect to this rectangle. The
175 * result will be the binary OR of the appropriate bit masks.
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
185 public int outcode(Point2D p)
187 return outcode(p.getX(), p.getY());
191 * Set the bounding box of this rectangle.
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
198 public void setFrame(double x, double y, double w, double h)
200 setRect(x, y, w, h);
204 * Returns the bounds of this rectangle. A pretty useless method, as this
205 * is already a rectangle.
207 * @return a copy of this rectangle
209 public Rectangle2D getBounds2D()
211 return (Rectangle2D) clone();
215 * Test if the given point is contained in the rectangle.
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
221 public boolean contains(double x, double y)
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;
231 * Tests if the given rectangle intersects this one. In other words, test if
232 * the two rectangles share at least one internal point.
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
240 public boolean intersects(double x, double y, double w, double h)
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;
251 * Tests if this rectangle contains the given one. In other words, test if
252 * this rectangle contains all points in the given one.
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
260 public boolean contains(double x, double y, double w, double h)
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;
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.
274 * @param r the rectangle to be intersected
275 * @return the intersection
276 * @throws NullPointerException if r is null
278 public abstract Rectangle2D createIntersection(Rectangle2D r);
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.
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
291 public static void intersect(Rectangle2D src1, Rectangle2D src2,
292 Rectangle2D dest)
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);
302 * Return a new rectangle which is the union of this and the given one.
304 * @param r the rectangle to be merged
305 * @return the union
306 * @throws NullPointerException if r is null
308 public abstract Rectangle2D createUnion(Rectangle2D r);
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.
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
321 public static void union(Rectangle2D src1, Rectangle2D src2,
322 Rectangle2D dest)
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);
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.
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
341 public void add(double newx, double newy)
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);
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.
357 * @param p the point to add to this rectangle
358 * @throws NullPointerException if p is null
360 public void add(Point2D p)
362 add(p.getX(), p.getY());
366 * Modifies this rectangle so that it represents the smallest rectangle
367 * that contains both the existing rectangle and the specified rectangle.
369 * @param r the rectangle to add to this rectangle
370 * @throws NullPointerException if r is null
371 * @see #union(Rectangle2D, Rectangle2D, Rectangle2D)
373 public void add(Rectangle2D r)
375 union(this, r, this);
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.
385 * @param at an optional transform to apply to the iterator
386 * @return a new iterator over the boundary
387 * @since 1.2
389 public PathIterator getPathIterator(final AffineTransform at)
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()
397 /** Current coordinate. */
398 private int current = (maxx <= minx && maxy <= miny) ? 6 : 0;
400 public int getWindingRule()
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.
408 return WIND_NON_ZERO;
411 public boolean isDone()
413 return current > 5;
416 public void next()
418 current++;
421 public int currentSegment(float[] coords)
423 switch (current)
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");
447 if (at != null)
448 at.transform(coords, 0, coords, 0, 1);
449 return current == 0 ? SEG_MOVETO : SEG_LINETO;
452 public int currentSegment(double[] coords)
454 switch (current)
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");
478 if (at != null)
479 at.transform(coords, 0, coords, 0, 1);
480 return current == 0 ? SEG_MOVETO : SEG_LINETO;
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.
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
498 public PathIterator getPathIterator(AffineTransform at, double flatness)
500 return getPathIterator(at);
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>
514 * @return the hashcode
516 public int hashCode()
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);
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.
531 * @param obj the object to test against for equality
532 * @return true if the specified object is equal to this one
534 public boolean equals(Object obj)
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();
544 * This class defines a rectangle in <code>double</code> precision.
546 * @author Eric Blake (ebb9@email.byu.edu)
547 * @since 1.2
548 * @status updated to 1.4
550 public static class Double extends Rectangle2D
552 /** The x coordinate of the lower left corner. */
553 public double x;
555 /** The y coordinate of the lower left corner. */
556 public double y;
558 /** The width of the rectangle. */
559 public double width;
561 /** The height of the rectangle. */
562 public double height;
565 * Create a rectangle at (0,0) with width 0 and height 0.
567 public Double()
572 * Create a rectangle with the given values.
574 * @param x the x coordinate
575 * @param y the y coordinate
576 * @param w the width
577 * @param h the height
579 public Double(double x, double y, double w, double h)
581 this.x = x;
582 this.y = y;
583 width = w;
584 height = h;
588 * Return the X coordinate.
590 * @return the value of x
592 public double getX()
594 return x;
598 * Return the Y coordinate.
600 * @return the value of y
602 public double getY()
604 return y;
608 * Return the width.
610 * @return the value of width
612 public double getWidth()
614 return width;
618 * Return the height.
620 * @return the value of height
622 public double getHeight()
624 return height;
628 * Test if the rectangle is empty.
630 * @return true if width or height is not positive
632 public boolean isEmpty()
634 return width <= 0 || height <= 0;
638 * Set the contents of this rectangle to those specified.
640 * @param x the x coordinate
641 * @param y the y coordinate
642 * @param w the width
643 * @param h the height
645 public void setRect(double x, double y, double w, double h)
647 this.x = x;
648 this.y = y;
649 width = w;
650 height = h;
654 * Set the contents of this rectangle to those specified.
656 * @param r the rectangle to copy
657 * @throws NullPointerException if r is null
659 public void setRect(Rectangle2D r)
661 x = r.getX();
662 y = r.getY();
663 width = r.getWidth();
664 height = r.getHeight();
668 * Determine where the point lies with respect to this rectangle. The
669 * result will be the binary OR of the appropriate bit masks.
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
680 public int outcode(double x, double y)
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;
699 * Returns the bounds of this rectangle. A pretty useless method, as this
700 * is already a rectangle.
702 * @return a copy of this rectangle
704 public Rectangle2D getBounds2D()
706 return new Double(x, y, width, height);
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.
713 * @param r the rectangle to be intersected
714 * @return the intersection
715 * @throws NullPointerException if r is null
717 public Rectangle2D createIntersection(Rectangle2D r)
719 Double res = new Double();
720 intersect(this, r, res);
721 return res;
725 * Return a new rectangle which is the union of this and the given one.
727 * @param r the rectangle to be merged
728 * @return the union
729 * @throws NullPointerException if r is null
731 public Rectangle2D createUnion(Rectangle2D r)
733 Double res = new Double();
734 union(this, r, res);
735 return res;
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>.
743 * @return a string representation of this rectangle
745 public String toString()
747 return getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width
748 + ",h=" + height + ']';
753 * This class defines a rectangle in <code>float</code> precision.
755 * @author Eric Blake (ebb9@email.byu.edu)
756 * @since 1.2
757 * @status updated to 1.4
759 public static class Float extends Rectangle2D
761 /** The x coordinate of the lower left corner. */
762 public float x;
764 /** The y coordinate of the lower left corner. */
765 public float y;
767 /** The width of the rectangle. */
768 public float width;
770 /** The height of the rectangle. */
771 public float height;
774 * Create a rectangle at (0,0) with width 0 and height 0.
776 public Float()
781 * Create a rectangle with the given values.
783 * @param x the x coordinate
784 * @param y the y coordinate
785 * @param w the width
786 * @param h the height
788 public Float(float x, float y, float w, float h)
790 this.x = x;
791 this.y = y;
792 width = w;
793 height = h;
797 * Create a rectangle with the given values.
799 * @param x the x coordinate
800 * @param y the y coordinate
801 * @param w the width
802 * @param h the height
804 Float(double x, double y, double w, double h)
806 this.x = (float) x;
807 this.y = (float) y;
808 width = (float) w;
809 height = (float) h;
813 * Return the X coordinate.
815 * @return the value of x
817 public double getX()
819 return x;
823 * Return the Y coordinate.
825 * @return the value of y
827 public double getY()
829 return y;
833 * Return the width.
835 * @return the value of width
837 public double getWidth()
839 return width;
843 * Return the height.
845 * @return the value of height
847 public double getHeight()
849 return height;
853 * Test if the rectangle is empty.
855 * @return true if width or height is not positive
857 public boolean isEmpty()
859 return width <= 0 || height <= 0;
863 * Set the contents of this rectangle to those specified.
865 * @param x the x coordinate
866 * @param y the y coordinate
867 * @param w the width
868 * @param h the height
870 public void setRect(float x, float y, float w, float h)
872 this.x = x;
873 this.y = y;
874 width = w;
875 height = h;
879 * Set the contents of this rectangle to those specified.
881 * @param x the x coordinate
882 * @param y the y coordinate
883 * @param w the width
884 * @param h the height
886 public void setRect(double x, double y, double w, double h)
888 this.x = (float) x;
889 this.y = (float) y;
890 width = (float) w;
891 height = (float) h;
895 * Set the contents of this rectangle to those specified.
897 * @param r the rectangle to copy
898 * @throws NullPointerException if r is null
900 public void setRect(Rectangle2D r)
902 x = (float) r.getX();
903 y = (float) r.getY();
904 width = (float) r.getWidth();
905 height = (float) r.getHeight();
909 * Determine where the point lies with respect to this rectangle. The
910 * result will be the binary OR of the appropriate bit masks.
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
921 public int outcode(double x, double y)
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;
940 * Returns the bounds of this rectangle. A pretty useless method, as this
941 * is already a rectangle.
943 * @return a copy of this rectangle
945 public Rectangle2D getBounds2D()
947 return new Float(x, y, width, height);
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.
954 * @param r the rectangle to be intersected
955 * @return the intersection
956 * @throws NullPointerException if r is null
958 public Rectangle2D createIntersection(Rectangle2D r)
960 Float res = new Float();
961 intersect(this, r, res);
962 return res;
966 * Return a new rectangle which is the union of this and the given one.
968 * @param r the rectangle to be merged
969 * @return the union
970 * @throws NullPointerException if r is null
972 public Rectangle2D createUnion(Rectangle2D r)
974 Float res = new Float();
975 union(this, r, res);
976 return res;
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>.
984 * @return a string representation of this rectangle
986 public String toString()
988 return getClass().getName() + "[x=" + x + ",y=" + y + ",w=" + width
989 + ",h=" + height + ']';