0001: /*
0002: * Copyright 1995-2006 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package java.awt;
0027:
0028: import java.awt.geom.Rectangle2D;
0029:
0030: /**
0031: * A <code>Rectangle</code> specifies an area in a coordinate space that is
0032: * enclosed by the <code>Rectangle</code> object's upper-left point
0033: * {@code (x,y)}
0034: * in the coordinate space, its width, and its height.
0035: * <p>
0036: * A <code>Rectangle</code> object's <code>width</code> and
0037: * <code>height</code> are <code>public</code> fields. The constructors
0038: * that create a <code>Rectangle</code>, and the methods that can modify
0039: * one, do not prevent setting a negative value for width or height.
0040: * <p>
0041: * <a name="Empty">
0042: * A {@code Rectangle} whose width or height is exactly zero has location
0043: * along those axes with zero dimension, but is otherwise considered empty.
0044: * The {@link #isEmpty} method will return true for such a {@code Rectangle}.
0045: * Methods which test if an empty {@code Rectangle} contains or intersects
0046: * a point or rectangle will always return false if either dimension is zero.
0047: * Methods which combine such a {@code Rectangle} with a point or rectangle
0048: * will include the location of the {@code Rectangle} on that axis in the
0049: * result as if the {@link #add(Point)} method were being called.
0050: * </a>
0051: * <p>
0052: * <a name="NonExistant">
0053: * A {@code Rectangle} whose width or height is negative has neither
0054: * location nor dimension along those axes with negative dimensions.
0055: * Such a {@code Rectangle} is treated as non-existant along those axes.
0056: * Such a {@code Rectangle} is also empty with respect to containment
0057: * calculations and methods which test if it contains or intersects a
0058: * point or rectangle will always return false.
0059: * Methods which combine such a {@code Rectangle} with a point or rectangle
0060: * will ignore the {@code Rectangle} entirely in generating the result.
0061: * If two {@code Rectangle} objects are combined and each has a negative
0062: * dimension, the result will have at least one negative dimension.
0063: * </a>
0064: * <p>
0065: * Methods which affect only the location of a {@code Rectangle} will
0066: * operate on its location regardless of whether or not it has a negative
0067: * or zero dimension along either axis.
0068: * <p>
0069: * Note that a {@code Rectangle} constructed with the default no-argument
0070: * constructor will have dimensions of {@code 0x0} and therefore be empty.
0071: * That {@code Rectangle} will still have a location of {@code (0,0)} and
0072: * will contribute that location to the union and add operations.
0073: * Code attempting to accumulate the bounds of a set of points should
0074: * therefore initially construct the {@code Rectangle} with a specifically
0075: * negative width and height or it should use the first point in the set
0076: * to construct the {@code Rectangle}.
0077: * For example:
0078: * <pre>
0079: * Rectangle bounds = new Rectangle(0, 0, -1, -1);
0080: * for (int i = 0; i < points.length; i++) {
0081: * bounds.add(points[i]);
0082: * }
0083: * </pre>
0084: * or if we know that the points array contains at least one point:
0085: * <pre>
0086: * Rectangle bounds = new Rectangle(points[0]);
0087: * for (int i = 1; i < points.length; i++) {
0088: * bounds.add(points[i]);
0089: * }
0090: * </pre>
0091: * <p>
0092: * This class uses 32-bit integers to store its location and dimensions.
0093: * Frequently operations may produce a result that exceeds the range of
0094: * a 32-bit integer.
0095: * The methods will calculate their results in a way that avoids any
0096: * 32-bit overflow for intermediate results and then choose the best
0097: * representation to store the final results back into the 32-bit fields
0098: * which hold the location and dimensions.
0099: * The location of the result will be stored into the {@link #x} and
0100: * {@link #y} fields by clipping the true result to the nearest 32-bit value.
0101: * The values stored into the {@link #width} and {@link #height} dimension
0102: * fields will be chosen as the 32-bit values that encompass the largest
0103: * part of the true result as possible.
0104: * Generally this means that the dimension will be clipped independently
0105: * to the range of 32-bit integers except that if the location had to be
0106: * moved to store it into its pair of 32-bit fields then the dimensions
0107: * will be adjusted relative to the "best representation" of the location.
0108: * If the true result had a negative dimension and was therefore
0109: * non-existant along one or both axes, the stored dimensions will be
0110: * negative numbers in those axes.
0111: * If the true result had a location that could be represented within
0112: * the range of 32-bit integers, but zero dimension along one or both
0113: * axes, then the stored dimensions will be zero in those axes.
0114: *
0115: * @version 1.79, 05/05/07
0116: * @author Sami Shaio
0117: * @since 1.0
0118: */
0119: public class Rectangle extends Rectangle2D implements Shape,
0120: java.io.Serializable {
0121:
0122: /**
0123: * The X coordinate of the upper-left corner of the <code>Rectangle</code>.
0124: *
0125: * @serial
0126: * @see #setLocation(int, int)
0127: * @see #getLocation()
0128: * @since 1.0
0129: */
0130: public int x;
0131:
0132: /**
0133: * The Y coordinate of the upper-left corner of the <code>Rectangle</code>.
0134: *
0135: * @serial
0136: * @see #setLocation(int, int)
0137: * @see #getLocation()
0138: * @since 1.0
0139: */
0140: public int y;
0141:
0142: /**
0143: * The width of the <code>Rectangle</code>.
0144: * @serial
0145: * @see #setSize(int, int)
0146: * @see #getSize()
0147: * @since 1.0
0148: */
0149: public int width;
0150:
0151: /**
0152: * The height of the <code>Rectangle</code>.
0153: *
0154: * @serial
0155: * @see #setSize(int, int)
0156: * @see #getSize()
0157: * @since 1.0
0158: */
0159: public int height;
0160:
0161: /*
0162: * JDK 1.1 serialVersionUID
0163: */
0164: private static final long serialVersionUID = -4345857070255674764L;
0165:
0166: /**
0167: * Initialize JNI field and method IDs
0168: */
0169: private static native void initIDs();
0170:
0171: static {
0172: /* ensure that the necessary native libraries are loaded */
0173: Toolkit.loadLibraries();
0174: if (!GraphicsEnvironment.isHeadless()) {
0175: initIDs();
0176: }
0177: }
0178:
0179: /**
0180: * Constructs a new <code>Rectangle</code> whose upper-left corner
0181: * is at (0, 0) in the coordinate space, and whose width and
0182: * height are both zero.
0183: */
0184: public Rectangle() {
0185: this (0, 0, 0, 0);
0186: }
0187:
0188: /**
0189: * Constructs a new <code>Rectangle</code>, initialized to match
0190: * the values of the specified <code>Rectangle</code>.
0191: * @param r the <code>Rectangle</code> from which to copy initial values
0192: * to a newly constructed <code>Rectangle</code>
0193: * @since 1.1
0194: */
0195: public Rectangle(Rectangle r) {
0196: this (r.x, r.y, r.width, r.height);
0197: }
0198:
0199: /**
0200: * Constructs a new <code>Rectangle</code> whose upper-left corner is
0201: * specified as
0202: * {@code (x,y)} and whose width and height
0203: * are specified by the arguments of the same name.
0204: * @param x the specified X coordinate
0205: * @param y the specified Y coordinate
0206: * @param width the width of the <code>Rectangle</code>
0207: * @param height the height of the <code>Rectangle</code>
0208: * @since 1.0
0209: */
0210: public Rectangle(int x, int y, int width, int height) {
0211: this .x = x;
0212: this .y = y;
0213: this .width = width;
0214: this .height = height;
0215: }
0216:
0217: /**
0218: * Constructs a new <code>Rectangle</code> whose upper-left corner
0219: * is at (0, 0) in the coordinate space, and whose width and
0220: * height are specified by the arguments of the same name.
0221: * @param width the width of the <code>Rectangle</code>
0222: * @param height the height of the <code>Rectangle</code>
0223: */
0224: public Rectangle(int width, int height) {
0225: this (0, 0, width, height);
0226: }
0227:
0228: /**
0229: * Constructs a new <code>Rectangle</code> whose upper-left corner is
0230: * specified by the {@link Point} argument, and
0231: * whose width and height are specified by the
0232: * {@link Dimension} argument.
0233: * @param p a <code>Point</code> that is the upper-left corner of
0234: * the <code>Rectangle</code>
0235: * @param d a <code>Dimension</code>, representing the
0236: * width and height of the <code>Rectangle</code>
0237: */
0238: public Rectangle(Point p, Dimension d) {
0239: this (p.x, p.y, d.width, d.height);
0240: }
0241:
0242: /**
0243: * Constructs a new <code>Rectangle</code> whose upper-left corner is the
0244: * specified <code>Point</code>, and whose width and height are both zero.
0245: * @param p a <code>Point</code> that is the top left corner
0246: * of the <code>Rectangle</code>
0247: */
0248: public Rectangle(Point p) {
0249: this (p.x, p.y, 0, 0);
0250: }
0251:
0252: /**
0253: * Constructs a new <code>Rectangle</code> whose top left corner is
0254: * (0, 0) and whose width and height are specified
0255: * by the <code>Dimension</code> argument.
0256: * @param d a <code>Dimension</code>, specifying width and height
0257: */
0258: public Rectangle(Dimension d) {
0259: this (0, 0, d.width, d.height);
0260: }
0261:
0262: /**
0263: * Returns the X coordinate of the bounding <code>Rectangle</code> in
0264: * <code>double</code> precision.
0265: * @return the X coordinate of the bounding <code>Rectangle</code>.
0266: */
0267: public double getX() {
0268: return x;
0269: }
0270:
0271: /**
0272: * Returns the Y coordinate of the bounding <code>Rectangle</code> in
0273: * <code>double</code> precision.
0274: * @return the Y coordinate of the bounding <code>Rectangle</code>.
0275: */
0276: public double getY() {
0277: return y;
0278: }
0279:
0280: /**
0281: * Returns the width of the bounding <code>Rectangle</code> in
0282: * <code>double</code> precision.
0283: * @return the width of the bounding <code>Rectangle</code>.
0284: */
0285: public double getWidth() {
0286: return width;
0287: }
0288:
0289: /**
0290: * Returns the height of the bounding <code>Rectangle</code> in
0291: * <code>double</code> precision.
0292: * @return the height of the bounding <code>Rectangle</code>.
0293: */
0294: public double getHeight() {
0295: return height;
0296: }
0297:
0298: /**
0299: * Gets the bounding <code>Rectangle</code> of this <code>Rectangle</code>.
0300: * <p>
0301: * This method is included for completeness, to parallel the
0302: * <code>getBounds</code> method of
0303: * {@link Component}.
0304: * @return a new <code>Rectangle</code>, equal to the
0305: * bounding <code>Rectangle</code> for this <code>Rectangle</code>.
0306: * @see java.awt.Component#getBounds
0307: * @see #setBounds(Rectangle)
0308: * @see #setBounds(int, int, int, int)
0309: * @since 1.1
0310: */
0311: public Rectangle getBounds() {
0312: return new Rectangle(x, y, width, height);
0313: }
0314:
0315: /**
0316: * {@inheritDoc}
0317: * @since 1.2
0318: */
0319: public Rectangle2D getBounds2D() {
0320: return new Rectangle(x, y, width, height);
0321: }
0322:
0323: /**
0324: * Sets the bounding <code>Rectangle</code> of this <code>Rectangle</code>
0325: * to match the specified <code>Rectangle</code>.
0326: * <p>
0327: * This method is included for completeness, to parallel the
0328: * <code>setBounds</code> method of <code>Component</code>.
0329: * @param r the specified <code>Rectangle</code>
0330: * @see #getBounds
0331: * @see java.awt.Component#setBounds(java.awt.Rectangle)
0332: * @since 1.1
0333: */
0334: public void setBounds(Rectangle r) {
0335: setBounds(r.x, r.y, r.width, r.height);
0336: }
0337:
0338: /**
0339: * Sets the bounding <code>Rectangle</code> of this
0340: * <code>Rectangle</code> to the specified
0341: * <code>x</code>, <code>y</code>, <code>width</code>,
0342: * and <code>height</code>.
0343: * <p>
0344: * This method is included for completeness, to parallel the
0345: * <code>setBounds</code> method of <code>Component</code>.
0346: * @param x the new X coordinate for the upper-left
0347: * corner of this <code>Rectangle</code>
0348: * @param y the new Y coordinate for the upper-left
0349: * corner of this <code>Rectangle</code>
0350: * @param width the new width for this <code>Rectangle</code>
0351: * @param height the new height for this <code>Rectangle</code>
0352: * @see #getBounds
0353: * @see java.awt.Component#setBounds(int, int, int, int)
0354: * @since 1.1
0355: */
0356: public void setBounds(int x, int y, int width, int height) {
0357: reshape(x, y, width, height);
0358: }
0359:
0360: /**
0361: * Sets the bounds of this {@code Rectangle} to the integer bounds
0362: * which encompass the specified {@code x}, {@code y}, {@code width},
0363: * and {@code height}.
0364: * If the parameters specify a {@code Rectangle} that exceeds the
0365: * maximum range of integers, the result will be the best
0366: * representation of the specified {@code Rectangle} intersected
0367: * with the maximum integer bounds.
0368: * @param x the X coordinate of the upper-left corner of
0369: * the specified rectangle
0370: * @param y the Y coordinate of the upper-left corner of
0371: * the specified rectangle
0372: * @param width the width of the specified rectangle
0373: * @param height the new height of the specified rectangle
0374: */
0375: public void setRect(double x, double y, double width, double height) {
0376: int newx, newy, neww, newh;
0377:
0378: if (x > 2.0 * Integer.MAX_VALUE) {
0379: // Too far in positive X direction to represent...
0380: // We cannot even reach the left side of the specified
0381: // rectangle even with both x & width set to MAX_VALUE.
0382: // The intersection with the "maximal integer rectangle"
0383: // is non-existant so we should use a width < 0.
0384: // REMIND: Should we try to determine a more "meaningful"
0385: // adjusted value for neww than just "-1"?
0386: newx = Integer.MAX_VALUE;
0387: neww = -1;
0388: } else {
0389: newx = clip(x, false);
0390: if (width >= 0)
0391: width += x - newx;
0392: neww = clip(width, width >= 0);
0393: }
0394:
0395: if (y > 2.0 * Integer.MAX_VALUE) {
0396: // Too far in positive Y direction to represent...
0397: newy = Integer.MAX_VALUE;
0398: newh = -1;
0399: } else {
0400: newy = clip(y, false);
0401: if (height >= 0)
0402: height += y - newy;
0403: newh = clip(height, height >= 0);
0404: }
0405:
0406: reshape(newx, newy, neww, newh);
0407: }
0408:
0409: // Return best integer representation for v, clipped to integer
0410: // range and floor-ed or ceiling-ed, depending on the boolean.
0411: private static int clip(double v, boolean doceil) {
0412: if (v <= Integer.MIN_VALUE) {
0413: return Integer.MIN_VALUE;
0414: }
0415: if (v >= Integer.MAX_VALUE) {
0416: return Integer.MAX_VALUE;
0417: }
0418: return (int) (doceil ? Math.ceil(v) : Math.floor(v));
0419: }
0420:
0421: /**
0422: * Sets the bounding <code>Rectangle</code> of this
0423: * <code>Rectangle</code> to the specified
0424: * <code>x</code>, <code>y</code>, <code>width</code>,
0425: * and <code>height</code>.
0426: * <p>
0427: * @param x the new X coordinate for the upper-left
0428: * corner of this <code>Rectangle</code>
0429: * @param y the new Y coordinate for the upper-left
0430: * corner of this <code>Rectangle</code>
0431: * @param width the new width for this <code>Rectangle</code>
0432: * @param height the new height for this <code>Rectangle</code>
0433: * @deprecated As of JDK version 1.1,
0434: * replaced by <code>setBounds(int, int, int, int)</code>.
0435: */
0436: @Deprecated
0437: public void reshape(int x, int y, int width, int height) {
0438: this .x = x;
0439: this .y = y;
0440: this .width = width;
0441: this .height = height;
0442: }
0443:
0444: /**
0445: * Returns the location of this <code>Rectangle</code>.
0446: * <p>
0447: * This method is included for completeness, to parallel the
0448: * <code>getLocation</code> method of <code>Component</code>.
0449: * @return the <code>Point</code> that is the upper-left corner of
0450: * this <code>Rectangle</code>.
0451: * @see java.awt.Component#getLocation
0452: * @see #setLocation(Point)
0453: * @see #setLocation(int, int)
0454: * @since 1.1
0455: */
0456: public Point getLocation() {
0457: return new Point(x, y);
0458: }
0459:
0460: /**
0461: * Moves this <code>Rectangle</code> to the specified location.
0462: * <p>
0463: * This method is included for completeness, to parallel the
0464: * <code>setLocation</code> method of <code>Component</code>.
0465: * @param p the <code>Point</code> specifying the new location
0466: * for this <code>Rectangle</code>
0467: * @see java.awt.Component#setLocation(java.awt.Point)
0468: * @see #getLocation
0469: * @since 1.1
0470: */
0471: public void setLocation(Point p) {
0472: setLocation(p.x, p.y);
0473: }
0474:
0475: /**
0476: * Moves this <code>Rectangle</code> to the specified location.
0477: * <p>
0478: * This method is included for completeness, to parallel the
0479: * <code>setLocation</code> method of <code>Component</code>.
0480: * @param x the X coordinate of the new location
0481: * @param y the Y coordinate of the new location
0482: * @see #getLocation
0483: * @see java.awt.Component#setLocation(int, int)
0484: * @since 1.1
0485: */
0486: public void setLocation(int x, int y) {
0487: move(x, y);
0488: }
0489:
0490: /**
0491: * Moves this <code>Rectangle</code> to the specified location.
0492: * <p>
0493: * @param x the X coordinate of the new location
0494: * @param y the Y coordinate of the new location
0495: * @deprecated As of JDK version 1.1,
0496: * replaced by <code>setLocation(int, int)</code>.
0497: */
0498: @Deprecated
0499: public void move(int x, int y) {
0500: this .x = x;
0501: this .y = y;
0502: }
0503:
0504: /**
0505: * Translates this <code>Rectangle</code> the indicated distance,
0506: * to the right along the X coordinate axis, and
0507: * downward along the Y coordinate axis.
0508: * @param dx the distance to move this <code>Rectangle</code>
0509: * along the X axis
0510: * @param dy the distance to move this <code>Rectangle</code>
0511: * along the Y axis
0512: * @see java.awt.Rectangle#setLocation(int, int)
0513: * @see java.awt.Rectangle#setLocation(java.awt.Point)
0514: */
0515: public void translate(int dx, int dy) {
0516: int oldv = this .x;
0517: int newv = oldv + dx;
0518: if (dx < 0) {
0519: // moving leftward
0520: if (newv > oldv) {
0521: // negative overflow
0522: // Only adjust width if it was valid (>= 0).
0523: if (width >= 0) {
0524: // The right edge is now conceptually at
0525: // newv+width, but we may move newv to prevent
0526: // overflow. But we want the right edge to
0527: // remain at its new location in spite of the
0528: // clipping. Think of the following adjustment
0529: // conceptually the same as:
0530: // width += newv; newv = MIN_VALUE; width -= newv;
0531: width += newv - Integer.MIN_VALUE;
0532: // width may go negative if the right edge went past
0533: // MIN_VALUE, but it cannot overflow since it cannot
0534: // have moved more than MIN_VALUE and any non-negative
0535: // number + MIN_VALUE does not overflow.
0536: }
0537: newv = Integer.MIN_VALUE;
0538: }
0539: } else {
0540: // moving rightward (or staying still)
0541: if (newv < oldv) {
0542: // positive overflow
0543: if (width >= 0) {
0544: // Conceptually the same as:
0545: // width += newv; newv = MAX_VALUE; width -= newv;
0546: width += newv - Integer.MAX_VALUE;
0547: // With large widths and large displacements
0548: // we may overflow so we need to check it.
0549: if (width < 0)
0550: width = Integer.MAX_VALUE;
0551: }
0552: newv = Integer.MAX_VALUE;
0553: }
0554: }
0555: this .x = newv;
0556:
0557: oldv = this .y;
0558: newv = oldv + dy;
0559: if (dy < 0) {
0560: // moving upward
0561: if (newv > oldv) {
0562: // negative overflow
0563: if (height >= 0) {
0564: height += newv - Integer.MIN_VALUE;
0565: // See above comment about no overflow in this case
0566: }
0567: newv = Integer.MIN_VALUE;
0568: }
0569: } else {
0570: // moving downward (or staying still)
0571: if (newv < oldv) {
0572: // positive overflow
0573: if (height >= 0) {
0574: height += newv - Integer.MAX_VALUE;
0575: if (height < 0)
0576: height = Integer.MAX_VALUE;
0577: }
0578: newv = Integer.MAX_VALUE;
0579: }
0580: }
0581: this .y = newv;
0582: }
0583:
0584: /**
0585: * Gets the size of this <code>Rectangle</code>, represented by
0586: * the returned <code>Dimension</code>.
0587: * <p>
0588: * This method is included for completeness, to parallel the
0589: * <code>getSize</code> method of <code>Component</code>.
0590: * @return a <code>Dimension</code>, representing the size of
0591: * this <code>Rectangle</code>.
0592: * @see java.awt.Component#getSize
0593: * @see #setSize(Dimension)
0594: * @see #setSize(int, int)
0595: * @since 1.1
0596: */
0597: public Dimension getSize() {
0598: return new Dimension(width, height);
0599: }
0600:
0601: /**
0602: * Sets the size of this <code>Rectangle</code> to match the
0603: * specified <code>Dimension</code>.
0604: * <p>
0605: * This method is included for completeness, to parallel the
0606: * <code>setSize</code> method of <code>Component</code>.
0607: * @param d the new size for the <code>Dimension</code> object
0608: * @see java.awt.Component#setSize(java.awt.Dimension)
0609: * @see #getSize
0610: * @since 1.1
0611: */
0612: public void setSize(Dimension d) {
0613: setSize(d.width, d.height);
0614: }
0615:
0616: /**
0617: * Sets the size of this <code>Rectangle</code> to the specified
0618: * width and height.
0619: * <p>
0620: * This method is included for completeness, to parallel the
0621: * <code>setSize</code> method of <code>Component</code>.
0622: * @param width the new width for this <code>Rectangle</code>
0623: * @param height the new height for this <code>Rectangle</code>
0624: * @see java.awt.Component#setSize(int, int)
0625: * @see #getSize
0626: * @since 1.1
0627: */
0628: public void setSize(int width, int height) {
0629: resize(width, height);
0630: }
0631:
0632: /**
0633: * Sets the size of this <code>Rectangle</code> to the specified
0634: * width and height.
0635: * <p>
0636: * @param width the new width for this <code>Rectangle</code>
0637: * @param height the new height for this <code>Rectangle</code>
0638: * @deprecated As of JDK version 1.1,
0639: * replaced by <code>setSize(int, int)</code>.
0640: */
0641: @Deprecated
0642: public void resize(int width, int height) {
0643: this .width = width;
0644: this .height = height;
0645: }
0646:
0647: /**
0648: * Checks whether or not this <code>Rectangle</code> contains the
0649: * specified <code>Point</code>.
0650: * @param p the <code>Point</code> to test
0651: * @return <code>true</code> if the specified <code>Point</code>
0652: * is inside this <code>Rectangle</code>;
0653: * <code>false</code> otherwise.
0654: * @since 1.1
0655: */
0656: public boolean contains(Point p) {
0657: return contains(p.x, p.y);
0658: }
0659:
0660: /**
0661: * Checks whether or not this <code>Rectangle</code> contains the
0662: * point at the specified location {@code (x,y)}.
0663: *
0664: * @param x the specified X coordinate
0665: * @param y the specified Y coordinate
0666: * @return <code>true</code> if the point
0667: * {@code (x,y)} is inside this
0668: * <code>Rectangle</code>;
0669: * <code>false</code> otherwise.
0670: * @since 1.1
0671: */
0672: public boolean contains(int x, int y) {
0673: return inside(x, y);
0674: }
0675:
0676: /**
0677: * Checks whether or not this <code>Rectangle</code> entirely contains
0678: * the specified <code>Rectangle</code>.
0679: *
0680: * @param r the specified <code>Rectangle</code>
0681: * @return <code>true</code> if the <code>Rectangle</code>
0682: * is contained entirely inside this <code>Rectangle</code>;
0683: * <code>false</code> otherwise
0684: * @since 1.2
0685: */
0686: public boolean contains(Rectangle r) {
0687: return contains(r.x, r.y, r.width, r.height);
0688: }
0689:
0690: /**
0691: * Checks whether this <code>Rectangle</code> entirely contains
0692: * the <code>Rectangle</code>
0693: * at the specified location {@code (X,Y)} with the
0694: * specified dimensions {@code (W,H)}.
0695: * @param X the specified X coordinate
0696: * @param Y the specified Y coordinate
0697: * @param W the width of the <code>Rectangle</code>
0698: * @param H the height of the <code>Rectangle</code>
0699: * @return <code>true</code> if the <code>Rectangle</code> specified by
0700: * {@code (X, Y, W, H)}
0701: * is entirely enclosed inside this <code>Rectangle</code>;
0702: * <code>false</code> otherwise.
0703: * @since 1.1
0704: */
0705: public boolean contains(int X, int Y, int W, int H) {
0706: int w = this .width;
0707: int h = this .height;
0708: if ((w | h | W | H) < 0) {
0709: // At least one of the dimensions is negative...
0710: return false;
0711: }
0712: // Note: if any dimension is zero, tests below must return false...
0713: int x = this .x;
0714: int y = this .y;
0715: if (X < x || Y < y) {
0716: return false;
0717: }
0718: w += x;
0719: W += X;
0720: if (W <= X) {
0721: // X+W overflowed or W was zero, return false if...
0722: // either original w or W was zero or
0723: // x+w did not overflow or
0724: // the overflowed x+w is smaller than the overflowed X+W
0725: if (w >= x || W > w)
0726: return false;
0727: } else {
0728: // X+W did not overflow and W was not zero, return false if...
0729: // original w was zero or
0730: // x+w did not overflow and x+w is smaller than X+W
0731: if (w >= x && W > w)
0732: return false;
0733: }
0734: h += y;
0735: H += Y;
0736: if (H <= Y) {
0737: if (h >= y || H > h)
0738: return false;
0739: } else {
0740: if (h >= y && H > h)
0741: return false;
0742: }
0743: return true;
0744: }
0745:
0746: /**
0747: * Checks whether or not this <code>Rectangle</code> contains the
0748: * point at the specified location {@code (X,Y)}.
0749: *
0750: * @param X the specified X coordinate
0751: * @param Y the specified Y coordinate
0752: * @return <code>true</code> if the point
0753: * {@code (X,Y)} is inside this
0754: * <code>Rectangle</code>;
0755: * <code>false</code> otherwise.
0756: * @deprecated As of JDK version 1.1,
0757: * replaced by <code>contains(int, int)</code>.
0758: */
0759: @Deprecated
0760: public boolean inside(int X, int Y) {
0761: int w = this .width;
0762: int h = this .height;
0763: if ((w | h) < 0) {
0764: // At least one of the dimensions is negative...
0765: return false;
0766: }
0767: // Note: if either dimension is zero, tests below must return false...
0768: int x = this .x;
0769: int y = this .y;
0770: if (X < x || Y < y) {
0771: return false;
0772: }
0773: w += x;
0774: h += y;
0775: // overflow || intersect
0776: return ((w < x || w > X) && (h < y || h > Y));
0777: }
0778:
0779: /**
0780: * Determines whether or not this <code>Rectangle</code> and the specified
0781: * <code>Rectangle</code> intersect. Two rectangles intersect if
0782: * their intersection is nonempty.
0783: *
0784: * @param r the specified <code>Rectangle</code>
0785: * @return <code>true</code> if the specified <code>Rectangle</code>
0786: * and this <code>Rectangle</code> intersect;
0787: * <code>false</code> otherwise.
0788: */
0789: public boolean intersects(Rectangle r) {
0790: int tw = this .width;
0791: int th = this .height;
0792: int rw = r.width;
0793: int rh = r.height;
0794: if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) {
0795: return false;
0796: }
0797: int tx = this .x;
0798: int ty = this .y;
0799: int rx = r.x;
0800: int ry = r.y;
0801: rw += rx;
0802: rh += ry;
0803: tw += tx;
0804: th += ty;
0805: // overflow || intersect
0806: return ((rw < rx || rw > tx) && (rh < ry || rh > ty)
0807: && (tw < tx || tw > rx) && (th < ty || th > ry));
0808: }
0809:
0810: /**
0811: * Computes the intersection of this <code>Rectangle</code> with the
0812: * specified <code>Rectangle</code>. Returns a new <code>Rectangle</code>
0813: * that represents the intersection of the two rectangles.
0814: * If the two rectangles do not intersect, the result will be
0815: * an empty rectangle.
0816: *
0817: * @param r the specified <code>Rectangle</code>
0818: * @return the largest <code>Rectangle</code> contained in both the
0819: * specified <code>Rectangle</code> and in
0820: * this <code>Rectangle</code>; or if the rectangles
0821: * do not intersect, an empty rectangle.
0822: */
0823: public Rectangle intersection(Rectangle r) {
0824: int tx1 = this .x;
0825: int ty1 = this .y;
0826: int rx1 = r.x;
0827: int ry1 = r.y;
0828: long tx2 = tx1;
0829: tx2 += this .width;
0830: long ty2 = ty1;
0831: ty2 += this .height;
0832: long rx2 = rx1;
0833: rx2 += r.width;
0834: long ry2 = ry1;
0835: ry2 += r.height;
0836: if (tx1 < rx1)
0837: tx1 = rx1;
0838: if (ty1 < ry1)
0839: ty1 = ry1;
0840: if (tx2 > rx2)
0841: tx2 = rx2;
0842: if (ty2 > ry2)
0843: ty2 = ry2;
0844: tx2 -= tx1;
0845: ty2 -= ty1;
0846: // tx2,ty2 will never overflow (they will never be
0847: // larger than the smallest of the two source w,h)
0848: // they might underflow, though...
0849: if (tx2 < Integer.MIN_VALUE)
0850: tx2 = Integer.MIN_VALUE;
0851: if (ty2 < Integer.MIN_VALUE)
0852: ty2 = Integer.MIN_VALUE;
0853: return new Rectangle(tx1, ty1, (int) tx2, (int) ty2);
0854: }
0855:
0856: /**
0857: * Computes the union of this <code>Rectangle</code> with the
0858: * specified <code>Rectangle</code>. Returns a new
0859: * <code>Rectangle</code> that
0860: * represents the union of the two rectangles.
0861: * <p>
0862: * If either {@code Rectangle} has any dimension less than zero
0863: * the rules for <a href=#NonExistant>non-existant</a> rectangles
0864: * apply.
0865: * If only one has a dimension less than zero, then the result
0866: * will be a copy of the other {@code Rectangle}.
0867: * If both have dimension less than zero, then the result will
0868: * have at least one dimension less than zero.
0869: * <p>
0870: * If the resulting {@code Rectangle} would have a dimension
0871: * too large to be expressed as an {@code int}, the result
0872: * will have a dimension of {@code Integer.MAX_VALUE} along
0873: * that dimension.
0874: * @param r the specified <code>Rectangle</code>
0875: * @return the smallest <code>Rectangle</code> containing both
0876: * the specified <code>Rectangle</code> and this
0877: * <code>Rectangle</code>.
0878: */
0879: public Rectangle union(Rectangle r) {
0880: long tx2 = this .width;
0881: long ty2 = this .height;
0882: if ((tx2 | ty2) < 0) {
0883: // This rectangle has negative dimensions...
0884: // If r has non-negative dimensions then it is the answer.
0885: // If r is non-existant (has a negative dimension), then both
0886: // are non-existant and we can return any non-existant rectangle
0887: // as an answer. Thus, returning r meets that criterion.
0888: // Either way, r is our answer.
0889: return new Rectangle(r);
0890: }
0891: long rx2 = r.width;
0892: long ry2 = r.height;
0893: if ((rx2 | ry2) < 0) {
0894: return new Rectangle(this );
0895: }
0896: int tx1 = this .x;
0897: int ty1 = this .y;
0898: tx2 += tx1;
0899: ty2 += ty1;
0900: int rx1 = r.x;
0901: int ry1 = r.y;
0902: rx2 += rx1;
0903: ry2 += ry1;
0904: if (tx1 > rx1)
0905: tx1 = rx1;
0906: if (ty1 > ry1)
0907: ty1 = ry1;
0908: if (tx2 < rx2)
0909: tx2 = rx2;
0910: if (ty2 < ry2)
0911: ty2 = ry2;
0912: tx2 -= tx1;
0913: ty2 -= ty1;
0914: // tx2,ty2 will never underflow since both original rectangles
0915: // were already proven to be non-empty
0916: // they might overflow, though...
0917: if (tx2 > Integer.MAX_VALUE)
0918: tx2 = Integer.MAX_VALUE;
0919: if (ty2 > Integer.MAX_VALUE)
0920: ty2 = Integer.MAX_VALUE;
0921: return new Rectangle(tx1, ty1, (int) tx2, (int) ty2);
0922: }
0923:
0924: /**
0925: * Adds a point, specified by the integer arguments {@code newx,newy}
0926: * to the bounds of this {@code Rectangle}.
0927: * <p>
0928: * If this {@code Rectangle} has any dimension less than zero,
0929: * the rules for <a href=#NonExistant>non-existant</a>
0930: * rectangles apply.
0931: * In that case, the new bounds of this {@code Rectangle} will
0932: * have a location equal to the specified coordinates and
0933: * width and height equal to zero.
0934: * <p>
0935: * After adding a point, a call to <code>contains</code> with the
0936: * added point as an argument does not necessarily return
0937: * <code>true</code>. The <code>contains</code> method does not
0938: * return <code>true</code> for points on the right or bottom
0939: * edges of a <code>Rectangle</code>. Therefore, if the added point
0940: * falls on the right or bottom edge of the enlarged
0941: * <code>Rectangle</code>, <code>contains</code> returns
0942: * <code>false</code> for that point.
0943: * If the specified point must be contained within the new
0944: * {@code Rectangle}, a 1x1 rectangle should be added instead:
0945: * <pre>
0946: * r.add(newx, newy, 1, 1);
0947: * </pre>
0948: * @param newx the X coordinate of the new point
0949: * @param newy the Y coordinate of the new point
0950: */
0951: public void add(int newx, int newy) {
0952: if ((width | height) < 0) {
0953: this .x = newx;
0954: this .y = newy;
0955: this .width = this .height = 0;
0956: return;
0957: }
0958: int x1 = this .x;
0959: int y1 = this .y;
0960: long x2 = this .width;
0961: long y2 = this .height;
0962: x2 += x1;
0963: y2 += y1;
0964: if (x1 > newx)
0965: x1 = newx;
0966: if (y1 > newy)
0967: y1 = newy;
0968: if (x2 < newx)
0969: x2 = newx;
0970: if (y2 < newy)
0971: y2 = newy;
0972: x2 -= x1;
0973: y2 -= y1;
0974: if (x2 > Integer.MAX_VALUE)
0975: x2 = Integer.MAX_VALUE;
0976: if (y2 > Integer.MAX_VALUE)
0977: y2 = Integer.MAX_VALUE;
0978: reshape(x1, y1, (int) x2, (int) y2);
0979: }
0980:
0981: /**
0982: * Adds the specified {@code Point} to the bounds of this
0983: * {@code Rectangle}.
0984: * <p>
0985: * If this {@code Rectangle} has any dimension less than zero,
0986: * the rules for <a href=#NonExistant>non-existant</a>
0987: * rectangles apply.
0988: * In that case, the new bounds of this {@code Rectangle} will
0989: * have a location equal to the coordinates of the specified
0990: * {@code Point} and width and height equal to zero.
0991: * <p>
0992: * After adding a <code>Point</code>, a call to <code>contains</code>
0993: * with the added <code>Point</code> as an argument does not
0994: * necessarily return <code>true</code>. The <code>contains</code>
0995: * method does not return <code>true</code> for points on the right
0996: * or bottom edges of a <code>Rectangle</code>. Therefore if the added
0997: * <code>Point</code> falls on the right or bottom edge of the
0998: * enlarged <code>Rectangle</code>, <code>contains</code> returns
0999: * <code>false</code> for that <code>Point</code>.
1000: * If the specified point must be contained within the new
1001: * {@code Rectangle}, a 1x1 rectangle should be added instead:
1002: * <pre>
1003: * r.add(pt.x, pt.y, 1, 1);
1004: * </pre>
1005: * @param pt the new <code>Point</code> to add to this
1006: * <code>Rectangle</code>
1007: */
1008: public void add(Point pt) {
1009: add(pt.x, pt.y);
1010: }
1011:
1012: /**
1013: * Adds a <code>Rectangle</code> to this <code>Rectangle</code>.
1014: * The resulting <code>Rectangle</code> is the union of the two
1015: * rectangles.
1016: * <p>
1017: * If either {@code Rectangle} has any dimension less than 0, the
1018: * result will have the dimensions of the other {@code Rectangle}.
1019: * If both {@code Rectangle}s have at least one dimension less
1020: * than 0, the result will have at least one dimension less than 0.
1021: * <p>
1022: * If either {@code Rectangle} has one or both dimensions equal
1023: * to 0, the result along those axes with 0 dimensions will be
1024: * equivalent to the results obtained by adding the corresponding
1025: * origin coordinate to the result rectangle along that axis,
1026: * similar to the operation of the {@link #add(Point)} method,
1027: * but contribute no further dimension beyond that.
1028: * <p>
1029: * If the resulting {@code Rectangle} would have a dimension
1030: * too large to be expressed as an {@code int}, the result
1031: * will have a dimension of {@code Integer.MAX_VALUE} along
1032: * that dimension.
1033: * @param r the specified <code>Rectangle</code>
1034: */
1035: public void add(Rectangle r) {
1036: long tx2 = this .width;
1037: long ty2 = this .height;
1038: if ((tx2 | ty2) < 0) {
1039: reshape(r.x, r.y, r.width, r.height);
1040: }
1041: long rx2 = r.width;
1042: long ry2 = r.height;
1043: if ((rx2 | ry2) < 0) {
1044: return;
1045: }
1046: int tx1 = this .x;
1047: int ty1 = this .y;
1048: tx2 += tx1;
1049: ty2 += ty1;
1050: int rx1 = r.x;
1051: int ry1 = r.y;
1052: rx2 += rx1;
1053: ry2 += ry1;
1054: if (tx1 > rx1)
1055: tx1 = rx1;
1056: if (ty1 > ry1)
1057: ty1 = ry1;
1058: if (tx2 < rx2)
1059: tx2 = rx2;
1060: if (ty2 < ry2)
1061: ty2 = ry2;
1062: tx2 -= tx1;
1063: ty2 -= ty1;
1064: // tx2,ty2 will never underflow since both original
1065: // rectangles were non-empty
1066: // they might overflow, though...
1067: if (tx2 > Integer.MAX_VALUE)
1068: tx2 = Integer.MAX_VALUE;
1069: if (ty2 > Integer.MAX_VALUE)
1070: ty2 = Integer.MAX_VALUE;
1071: reshape(tx1, ty1, (int) tx2, (int) ty2);
1072: }
1073:
1074: /**
1075: * Resizes the <code>Rectangle</code> both horizontally and vertically.
1076: * <p>
1077: * This method modifies the <code>Rectangle</code> so that it is
1078: * <code>h</code> units larger on both the left and right side,
1079: * and <code>v</code> units larger at both the top and bottom.
1080: * <p>
1081: * The new <code>Rectangle</code> has {@code (x - h, y - v)}
1082: * as its upper-left corner,
1083: * width of {@code (width + 2h)},
1084: * and a height of {@code (height + 2v)}.
1085: * <p>
1086: * If negative values are supplied for <code>h</code> and
1087: * <code>v</code>, the size of the <code>Rectangle</code>
1088: * decreases accordingly.
1089: * The {@code grow} method will check for integer overflow
1090: * and underflow, but does not check whether the resulting
1091: * values of {@code width} and {@code height} grow
1092: * from negative to non-negative or shrink from non-negative
1093: * to negative.
1094: * @param h the horizontal expansion
1095: * @param v the vertical expansion
1096: */
1097: public void grow(int h, int v) {
1098: long x0 = this .x;
1099: long y0 = this .y;
1100: long x1 = this .width;
1101: long y1 = this .height;
1102: x1 += x0;
1103: y1 += y0;
1104:
1105: x0 -= h;
1106: y0 -= v;
1107: x1 += h;
1108: y1 += v;
1109:
1110: if (x1 < x0) {
1111: // Non-existant in X direction
1112: // Final width must remain negative so subtract x0 before
1113: // it is clipped so that we avoid the risk that the clipping
1114: // of x0 will reverse the ordering of x0 and x1.
1115: x1 -= x0;
1116: if (x1 < Integer.MIN_VALUE)
1117: x1 = Integer.MIN_VALUE;
1118: if (x0 < Integer.MIN_VALUE)
1119: x0 = Integer.MIN_VALUE;
1120: else if (x0 > Integer.MAX_VALUE)
1121: x0 = Integer.MAX_VALUE;
1122: } else { // (x1 >= x0)
1123: // Clip x0 before we subtract it from x1 in case the clipping
1124: // affects the representable area of the rectangle.
1125: if (x0 < Integer.MIN_VALUE)
1126: x0 = Integer.MIN_VALUE;
1127: else if (x0 > Integer.MAX_VALUE)
1128: x0 = Integer.MAX_VALUE;
1129: x1 -= x0;
1130: // The only way x1 can be negative now is if we clipped
1131: // x0 against MIN and x1 is less than MIN - in which case
1132: // we want to leave the width negative since the result
1133: // did not intersect the representable area.
1134: if (x1 < Integer.MIN_VALUE)
1135: x1 = Integer.MIN_VALUE;
1136: else if (x1 > Integer.MAX_VALUE)
1137: x1 = Integer.MAX_VALUE;
1138: }
1139:
1140: if (y1 < y0) {
1141: // Non-existant in Y direction
1142: y1 -= y0;
1143: if (y1 < Integer.MIN_VALUE)
1144: y1 = Integer.MIN_VALUE;
1145: if (y0 < Integer.MIN_VALUE)
1146: y0 = Integer.MIN_VALUE;
1147: else if (y0 > Integer.MAX_VALUE)
1148: y0 = Integer.MAX_VALUE;
1149: } else { // (y1 >= y0)
1150: if (y0 < Integer.MIN_VALUE)
1151: y0 = Integer.MIN_VALUE;
1152: else if (y0 > Integer.MAX_VALUE)
1153: y0 = Integer.MAX_VALUE;
1154: y1 -= y0;
1155: if (y1 < Integer.MIN_VALUE)
1156: y1 = Integer.MIN_VALUE;
1157: else if (y1 > Integer.MAX_VALUE)
1158: y1 = Integer.MAX_VALUE;
1159: }
1160:
1161: reshape((int) x0, (int) y0, (int) x1, (int) y1);
1162: }
1163:
1164: /**
1165: * {@inheritDoc}
1166: * @since 1.2
1167: */
1168: public boolean isEmpty() {
1169: return (width <= 0) || (height <= 0);
1170: }
1171:
1172: /**
1173: * {@inheritDoc}
1174: * @since 1.2
1175: */
1176: public int outcode(double x, double y) {
1177: /*
1178: * Note on casts to double below. If the arithmetic of
1179: * x+w or y+h is done in int, then we may get integer
1180: * overflow. By converting to double before the addition
1181: * we force the addition to be carried out in double to
1182: * avoid overflow in the comparison.
1183: *
1184: * See bug 4320890 for problems that this can cause.
1185: */
1186: int out = 0;
1187: if (this .width <= 0) {
1188: out |= OUT_LEFT | OUT_RIGHT;
1189: } else if (x < this .x) {
1190: out |= OUT_LEFT;
1191: } else if (x > this .x + (double) this .width) {
1192: out |= OUT_RIGHT;
1193: }
1194: if (this .height <= 0) {
1195: out |= OUT_TOP | OUT_BOTTOM;
1196: } else if (y < this .y) {
1197: out |= OUT_TOP;
1198: } else if (y > this .y + (double) this .height) {
1199: out |= OUT_BOTTOM;
1200: }
1201: return out;
1202: }
1203:
1204: /**
1205: * {@inheritDoc}
1206: * @since 1.2
1207: */
1208: public Rectangle2D createIntersection(Rectangle2D r) {
1209: if (r instanceof Rectangle) {
1210: return intersection((Rectangle) r);
1211: }
1212: Rectangle2D dest = new Rectangle2D.Double();
1213: Rectangle2D.intersect(this , r, dest);
1214: return dest;
1215: }
1216:
1217: /**
1218: * {@inheritDoc}
1219: * @since 1.2
1220: */
1221: public Rectangle2D createUnion(Rectangle2D r) {
1222: if (r instanceof Rectangle) {
1223: return union((Rectangle) r);
1224: }
1225: Rectangle2D dest = new Rectangle2D.Double();
1226: Rectangle2D.union(this , r, dest);
1227: return dest;
1228: }
1229:
1230: /**
1231: * Checks whether two rectangles are equal.
1232: * <p>
1233: * The result is <code>true</code> if and only if the argument is not
1234: * <code>null</code> and is a <code>Rectangle</code> object that has the
1235: * same upper-left corner, width, and height as
1236: * this <code>Rectangle</code>.
1237: * @param obj the <code>Object</code> to compare with
1238: * this <code>Rectangle</code>
1239: * @return <code>true</code> if the objects are equal;
1240: * <code>false</code> otherwise.
1241: */
1242: public boolean equals(Object obj) {
1243: if (obj instanceof Rectangle) {
1244: Rectangle r = (Rectangle) obj;
1245: return ((x == r.x) && (y == r.y) && (width == r.width) && (height == r.height));
1246: }
1247: return super .equals(obj);
1248: }
1249:
1250: /**
1251: * Returns a <code>String</code> representing this
1252: * <code>Rectangle</code> and its values.
1253: * @return a <code>String</code> representing this
1254: * <code>Rectangle</code> object's coordinate and size values.
1255: */
1256: public String toString() {
1257: return getClass().getName() + "[x=" + x + ",y=" + y + ",width="
1258: + width + ",height=" + height + "]";
1259: }
1260: }
|