/** * {@collect.stats} Adds a <code>Rectangle</code> to this <code>Rectangle</code>. The resulting * <code>Rectangle</code> is the union of the two rectangles. * * <p>If either {@code Rectangle} has any dimension less than 0, the result will have the * dimensions of the other {@code Rectangle}. If both {@code Rectangle}s have at least one * dimension less than 0, the result will have at least one dimension less than 0. * * <p>If either {@code Rectangle} has one or both dimensions equal to 0, the result along those * axes with 0 dimensions will be equivalent to the results obtained by adding the corresponding * origin coordinate to the result rectangle along that axis, similar to the operation of the * {@link #add(Point)} method, but contribute no further dimension beyond that. * * <p>If the resulting {@code Rectangle} would have a dimension too large to be expressed as an * {@code int}, the result will have a dimension of {@code Integer.MAX_VALUE} along that * dimension. * * @param r the specified <code>Rectangle</code> */ public void add(Rectangle r) { long tx2 = this.width; long ty2 = this.height; if ((tx2 | ty2) < 0) { reshape(r.x, r.y, r.width, r.height); } long rx2 = r.width; long ry2 = r.height; if ((rx2 | ry2) < 0) { return; } int tx1 = this.x; int ty1 = this.y; tx2 += tx1; ty2 += ty1; int rx1 = r.x; int ry1 = r.y; rx2 += rx1; ry2 += ry1; if (tx1 > rx1) tx1 = rx1; if (ty1 > ry1) ty1 = ry1; if (tx2 < rx2) tx2 = rx2; if (ty2 < ry2) ty2 = ry2; tx2 -= tx1; ty2 -= ty1; // tx2,ty2 will never underflow since both original // rectangles were non-empty // they might overflow, though... if (tx2 > Integer.MAX_VALUE) tx2 = Integer.MAX_VALUE; if (ty2 > Integer.MAX_VALUE) ty2 = Integer.MAX_VALUE; reshape(tx1, ty1, (int) tx2, (int) ty2); }
/** * {@collect.stats} Sets the bounds of this {@code Rectangle} to the integer bounds which * encompass the specified {@code x}, {@code y}, {@code width}, and {@code height}. If the * parameters specify a {@code Rectangle} that exceeds the maximum range of integers, the result * will be the best representation of the specified {@code Rectangle} intersected with the maximum * integer bounds. * * @param x the X coordinate of the upper-left corner of the specified rectangle * @param y the Y coordinate of the upper-left corner of the specified rectangle * @param width the width of the specified rectangle * @param height the new height of the specified rectangle */ public void setRect(double x, double y, double width, double height) { int newx, newy, neww, newh; if (x > 2.0 * Integer.MAX_VALUE) { // Too far in positive X direction to represent... // We cannot even reach the left side of the specified // rectangle even with both x & width set to MAX_VALUE. // The intersection with the "maximal integer rectangle" // is non-existant so we should use a width < 0. // REMIND: Should we try to determine a more "meaningful" // adjusted value for neww than just "-1"? newx = Integer.MAX_VALUE; neww = -1; } else { newx = clip(x, false); if (width >= 0) width += x - newx; neww = clip(width, width >= 0); } if (y > 2.0 * Integer.MAX_VALUE) { // Too far in positive Y direction to represent... newy = Integer.MAX_VALUE; newh = -1; } else { newy = clip(y, false); if (height >= 0) height += y - newy; newh = clip(height, height >= 0); } reshape(newx, newy, neww, newh); }
/** * {@collect.stats} Resizes the <code>Rectangle</code> both horizontally and vertically. * * <p>This method modifies the <code>Rectangle</code> so that it is <code>h</code> units larger on * both the left and right side, and <code>v</code> units larger at both the top and bottom. * * <p>The new <code>Rectangle</code> has {@code (x - h, y - v)} as its upper-left corner, width of * {@code (width + 2h)}, and a height of {@code (height + 2v)}. * * <p>If negative values are supplied for <code>h</code> and <code>v</code>, the size of the * <code>Rectangle</code> decreases accordingly. The {@code grow} method will check for integer * overflow and underflow, but does not check whether the resulting values of {@code width} and * {@code height} grow from negative to non-negative or shrink from non-negative to negative. * * @param h the horizontal expansion * @param v the vertical expansion */ public void grow(int h, int v) { long x0 = this.x; long y0 = this.y; long x1 = this.width; long y1 = this.height; x1 += x0; y1 += y0; x0 -= h; y0 -= v; x1 += h; y1 += v; if (x1 < x0) { // Non-existant in X direction // Final width must remain negative so subtract x0 before // it is clipped so that we avoid the risk that the clipping // of x0 will reverse the ordering of x0 and x1. x1 -= x0; if (x1 < Integer.MIN_VALUE) x1 = Integer.MIN_VALUE; if (x0 < Integer.MIN_VALUE) x0 = Integer.MIN_VALUE; else if (x0 > Integer.MAX_VALUE) x0 = Integer.MAX_VALUE; } else { // (x1 >= x0) // Clip x0 before we subtract it from x1 in case the clipping // affects the representable area of the rectangle. if (x0 < Integer.MIN_VALUE) x0 = Integer.MIN_VALUE; else if (x0 > Integer.MAX_VALUE) x0 = Integer.MAX_VALUE; x1 -= x0; // The only way x1 can be negative now is if we clipped // x0 against MIN and x1 is less than MIN - in which case // we want to leave the width negative since the result // did not intersect the representable area. if (x1 < Integer.MIN_VALUE) x1 = Integer.MIN_VALUE; else if (x1 > Integer.MAX_VALUE) x1 = Integer.MAX_VALUE; } if (y1 < y0) { // Non-existant in Y direction y1 -= y0; if (y1 < Integer.MIN_VALUE) y1 = Integer.MIN_VALUE; if (y0 < Integer.MIN_VALUE) y0 = Integer.MIN_VALUE; else if (y0 > Integer.MAX_VALUE) y0 = Integer.MAX_VALUE; } else { // (y1 >= y0) if (y0 < Integer.MIN_VALUE) y0 = Integer.MIN_VALUE; else if (y0 > Integer.MAX_VALUE) y0 = Integer.MAX_VALUE; y1 -= y0; if (y1 < Integer.MIN_VALUE) y1 = Integer.MIN_VALUE; else if (y1 > Integer.MAX_VALUE) y1 = Integer.MAX_VALUE; } reshape((int) x0, (int) y0, (int) x1, (int) y1); }
/** * {@collect.stats} Adds a point, specified by the integer arguments {@code newx,newy} to the * bounds of this {@code Rectangle}. * * <p>If this {@code Rectangle} has any dimension less than zero, the rules for <a * href=#NonExistant>non-existant</a> rectangles apply. In that case, the new bounds of this * {@code Rectangle} will have a location equal to the specified coordinates and width and height * equal to zero. * * <p>After adding a point, a call to <code>contains</code> with the added point as an argument * does not necessarily return <code>true</code>. The <code>contains</code> method does not return * <code>true</code> for points on the right or bottom edges of a <code>Rectangle</code>. * Therefore, if the added point falls on the right or bottom edge of the enlarged <code>Rectangle * </code>, <code>contains</code> returns <code>false</code> for that point. If the specified * point must be contained within the new {@code Rectangle}, a 1x1 rectangle should be added * instead: * * <pre> * r.add(newx, newy, 1, 1); * </pre> * * @param newx the X coordinate of the new point * @param newy the Y coordinate of the new point */ public void add(int newx, int newy) { if ((width | height) < 0) { this.x = newx; this.y = newy; this.width = this.height = 0; return; } int x1 = this.x; int y1 = this.y; long x2 = this.width; long y2 = this.height; x2 += x1; y2 += y1; if (x1 > newx) x1 = newx; if (y1 > newy) y1 = newy; if (x2 < newx) x2 = newx; if (y2 < newy) y2 = newy; x2 -= x1; y2 -= y1; if (x2 > Integer.MAX_VALUE) x2 = Integer.MAX_VALUE; if (y2 > Integer.MAX_VALUE) y2 = Integer.MAX_VALUE; reshape(x1, y1, (int) x2, (int) y2); }
/** * Sets the bounding <code>Rectangle</code> of this <code>Rectangle</code> to the specified <code> * x</code>, <code>y</code>, <code>width</code>, and <code>height</code>. * * <p>This method is included for completeness, to parallel the <code>setBounds</code> method of * <code>Component</code>. * * @param x the new x coordinate for the top-left corner of this <code>Rectangle</code> * @param y the new y coordinate for the top-left corner of this <code>Rectangle</code> * @param width the new width for this <code>Rectangle</code> * @param height the new height for this <code>Rectangle</code> * @see #getBounds * @see java.awt.Component#setBounds(int, int, int, int) * @since JDK1.1 */ public void setBounds(int x, int y, int width, int height) { reshape(x, y, width, height); }