Java tutorial
/******************************************************************************* * Copyright (c) 2000, 2010, 2012 IBM Corporation, Gerhardt Informatics Kft. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Mariot Chauvin <mariot.chauvin@obeo.fr> - bug 260740 * Gerhardt Informatics Kft. - GEFGWT port *******************************************************************************/ package org.eclipse.draw2d.geometry; import org.eclipse.draw2d.PositionConstants; /** * Represents a Rectangle(x, y, width, height). This class provides various * methods for manipulating this Rectangle or creating new derived geometrical * Objects. */ public class Rectangle implements Cloneable, java.io.Serializable, Translatable { private static final long serialVersionUID = 1L; /** * A singleton for use in short calculations. Use to avoid newing * unnecessary objects. */ public static final Rectangle SINGLETON = new Rectangle(); /** * The height */ public int height; /** * The width */ public int width; /** * The x value */ public int x; /** * The y value */ public int y; /** * Constructs a Rectangle at the origin with zero width and height. * * @since 2.0 */ public Rectangle() { } /** * Constructs a Rectangle with the provided values. * * @param x * X location * @param y * Y location * @param width * Width of the rectangle * @param height * Height of the rectangle * @since 2.0 */ public Rectangle(int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; } /** * Constructs a copy of the provided SWT * {@link org.eclipse.swt.graphics.Rectangle}. * * @param rect * The SWT Rectangle being copied * @since 2.0 */ public Rectangle(org.eclipse.swt.graphics.Rectangle rect) { this(rect.x, rect.y, rect.width, rect.height); } /** * Constructs a Rectangle given a location and size. * * @param p * the location * @param size * the size * @since 2.0 */ public Rectangle(Point p, Dimension size) { this(p.x(), p.y(), size.width(), size.height()); } /** * Constructs the smallest Rectangle that contains the specified Points. * * @param p1 * Upper left hand corner * @param p2 * Lower right hand corner * @since 2.0 */ public Rectangle(Point p1, Point p2) { this.x = Math.min(p1.x(), p2.x()); this.y = Math.min(p1.y(), p2.y()); this.width = Math.abs(p2.x() - p1.x()) + 1; this.height = Math.abs(p2.y() - p1.y()) + 1; } /** * Constructs a copy of the provided Rectangle. * * @param rect * Rectangle supplying the initial values * @since 2.0 */ public Rectangle(Rectangle rect) { this(rect.x(), rect.y(), rect.width(), rect.height()); } /** * Returns the y-coordinate of the bottom of this Rectangle. * * @return The Y coordinate of the bottom * @since 2.0 */ public int bottom() { return y + height; } /** * Returns whether the given coordinates are within the boundaries of this * Rectangle. The boundaries are inclusive of the top and left edges, but * exclusive of the bottom and right edges. * * @param x * X value * @param y * Y value * @return true if the coordinates are within this Rectangle * @since 2.0 */ public boolean contains(int x, int y) { return y >= this.y && y < this.y + this.height && x >= this.x && x < this.x + this.width; } /** * Returns whether the given point is within the boundaries of this * Rectangle. The boundaries are inclusive of the top and left edges, but * exclusive of the bottom and right edges. * * @param p * Point being tested for containment * @return true if the Point is within this Rectangle * @since 2.0 */ public boolean contains(Point p) { return contains(p.x(), p.y()); } /** * Returns <code>true</code> if the given rectangle is contained within the * boundaries of this Rectangle. * * @param rect * the Rectangle to test * @return true if the Rectangle is within this Rectangle */ public boolean contains(Rectangle rect) { return x <= rect.x() && y <= rect.y() && right() >= rect.right() && bottom() >= rect.bottom(); } /** * Crops this rectangle by the amount specified in <code>insets</code>. * * @param insets * Insets to be removed from the Rectangle * @return <code>this</code> for convenience * @since 2.0 * @deprecated Use {@link #shrink(Insets)} instead. */ public Rectangle crop(Insets insets) { return shrink(insets); } /** * Returns <code>true</code> if this Rectangle's x, y, width, and height * values are identical to the provided ones. * * @param x * The x value to test * @param y * The y value to test * @param width * The width value to test * @param height * The height value to test * @return <code>true</code> if this Rectangle's x, y, width, and height * values are identical to the provided ones, <code>false</code> * otherwise * @since 3.7 */ public boolean equals(int x, int y, int width, int height) { return this.x == x && this.y == y && this.width == width && this.height == height; } /** * Returns whether the input object is equal to this Rectangle or not. * Rectangles are equivalent if their x, y, height, and width values are the * same. * * @param o * Object being tested for equality * @return Returns the result of the equality test * @since 2.0 */ public boolean equals(Object o) { if (this == o) return true; if (o instanceof Rectangle) { Rectangle r = (Rectangle) o; return (x == r.x()) && (y == r.y()) && (width == r.width()) && (height == r.height()); } return false; } /** * Expands the horizontal and vertical sides of this Rectangle by the width * and height of the given Insets, and returns this for convenience. * * @param insets * contains the amounts to expand on each side * @return <code>this</code> for convenience * @since 2.0 */ public Rectangle expand(Insets insets) { x -= insets.left; y -= insets.top; width += insets.getWidth(); height += insets.getHeight(); return this; } /** * Expands the horizontal and vertical sides of this Rectangle with the * values provided as input, and returns this for convenience. The location * of its center is kept constant. * * @param h * Horizontal increment * @param v * Vertical increment * @return <code>this</code> for convenience * @since 2.0 */ public Rectangle expand(int h, int v) { return shrink(-h, -v); } /** * Returns a new Point representing the middle point of the bottom side of * this Rectangle. * * @return Point at the bottom of the Rectangle * @since 2.0 */ public Point getBottom() { return new Point(x + width / 2, bottom()); } /** * Returns a new Point representing the bottom left point of this Rectangle. * * @return Point at the bottom left of the rectangle * @since 2.0 */ public Point getBottomLeft() { return new Point(x, y + height); } /** * Returns a new Point representing the bottom right point of this * Rectangle. * * @return Point at the bottom right of the rectangle * @since 2.0 */ public Point getBottomRight() { return new Point(x + width, y + height); } /** * Returns a new point representing the center of this Rectangle. * * @return Point at the center of the rectangle */ public Point getCenter() { return new Point(x + width / 2, y + height / 2); } /** * Returns a new Rectangle which has the exact same parameters as this * Rectangle. * * @return Copy of this Rectangle * @since 2.0 */ public Rectangle getCopy() { // FIXME: This is inconsistent with the behavior of getCopy() within // Point and Dimension and should only return a new Rectangle, leaving // the property copying of others to subclasses. Clients should // not relay on this method performing a clone() if (getClass() == Rectangle.class) { /* avoid clone() call cost see bug #260740 */ return new Rectangle(this); } else { // try { // return (Rectangle) clone(); // } catch (CloneNotSupportedException exc) { return new Rectangle(this); // } } } /** * Returns a new Rectangle with the specified insets cropped. * * @param insets * Insets being cropped from the Rectangle * @return Cropped new Rectangle * @deprecated Use {@link #getShrinked(Insets)} instead. */ public Rectangle getCropped(Insets insets) { return getShrinked(insets); } /** * Creates and returns a new Rectangle with the bounds of <code>this</code> * Rectangle, expanded by the given Insets. * * @param insets * The insets used to expand this rectangle * @return A new expanded Rectangle * @since 2.0 */ public Rectangle getExpanded(Insets insets) { return getCopy().expand(insets); } /** * Returns a new incremented Rectangle, where the sides are expanded by the * horizontal and vertical values provided. The center of the Rectangle is * maintained constant. * * @param h * Horizontal increment * @param v * Vertical increment * @return A new expanded Rectangle * @since 2.0 */ public Rectangle getExpanded(int h, int v) { return getCopy().expand(h, v); } /** * Returns a new Rectangle which has the intersection of this Rectangle and * the rectangle provided as input. Returns an empty Rectangle if there is * no intersection. * * @param rect * Rectangle provided to test for intersection * @return A new Rectangle representing the intersection * @since 2.0 */ public Rectangle getIntersection(Rectangle rect) { return getCopy().intersect(rect); } /** * Returns a new Point representing the middle point of the left hand side * of this Rectangle. * * @return Point at the left of the Rectangle */ public Point getLeft() { return new Point(x, y + height / 2); } /** * Returns the upper left hand corner of the rectangle. * * @return Location of the rectangle * @see #setLocation(Point) */ public Point getLocation() { return new Point(x, y); } /** * <P> * Returns an integer which represents the position of the given point with * respect to this rectangle. Possible return values are bitwise ORs of the * constants WEST, EAST, NORTH, and SOUTH as found in * {@link org.eclipse.draw2d.PositionConstants}. * * <P> * Returns PositionConstant.NONE if the given point is inside this * Rectangle. * * @param p * The Point whose position has to be determined * @return An <code>int</code> which is a PositionConstant * @see org.eclipse.draw2d.PositionConstants * @since 2.0 */ public int getPosition(Point p) { int result = PositionConstants.NONE; if (contains(p)) return result; if (p.x() < x) result = PositionConstants.WEST; else if (p.x() >= (x + width)) result = PositionConstants.EAST; if (p.y() < y) result = result | PositionConstants.NORTH; else if (p.y() >= (y + height)) result = result | PositionConstants.SOUTH; return result; } /** * Returns a new Rectangle which is equivalent to this Rectangle with its * dimensions modified by the passed Dimension <i>d</i>. * * @param d * Dimensions by which the rectangle's size should be modified * @return The new rectangle with the modified dimensions * @since 2.0 */ public Rectangle getResized(Dimension d) { return getCopy().resize(d); } /** * Returns a new Rectangle which is equivalent to this Rectangle with its * dimensions modified by the passed width <i>w</i> and height <i>h</i>. * * @param w * Amount by which width is to be resized * @param h * Amount by which height is to be resized * @return a new rectangle with its width and height modified */ public Rectangle getResized(int w, int h) { return getCopy().resize(w, h); } /** * Returns a new Point which represents the middle point of the right hand * side of this Rectangle. * * @return Point at the right of the Rectangle * @since 2.0 */ public Point getRight() { return new Point(right(), y + height / 2); } /** * Returns a new Rectangle shrinked by the specified insets. * * @param insets * Insets being cropped from the Rectangle * @return Shrinked new Rectangle * @since 3.7 */ public Rectangle getShrinked(Insets insets) { return getCopy().shrink(insets); } /** * Returns a new Rectangle, where the sides are shrinked by the horizontal * and vertical values supplied. The center of this Rectangle is kept * constant. * * @param h * Horizontal reduction amount * @param v * Vertical reduction amount * @return <code>this</code> for convenience * @since 3.7 */ public Rectangle getShrinked(int h, int v) { return getCopy().shrink(h, v); } /** * Retuns the dimensions of this Rectangle. * * @return Size of this Rectangle as a Dimension * @since 2.0 */ public Dimension getSize() { return new Dimension(width, height); } /** * Returns a new Point which represents the middle point of the top side of * this Rectangle. * * @return Point at the top of the Rectangle * @since 2.0 */ public Point getTop() { return new Point(x + width / 2, y); } /** * Returns a new Point which represents the top left hand corner of this * Rectangle. * * @return Point at the top left of the rectangle * @since 2.0 */ public Point getTopLeft() { return new Point(x, y); } /** * Returns a new Point which represents the top right hand corner of this * Rectangle. * * @return Point at the top right of the rectangle * @since 2.0 */ public Point getTopRight() { return new Point(x + width, y); } /** * Returns a new Rectangle which is shifted along each axis by the passed * values. * * @param dx * Displacement along X axis * @param dy * Displacement along Y axis * @return The new translated rectangle * @since 2.0 */ public Rectangle getTranslated(int dx, int dy) { return getCopy().translate(dx, dy); } /** * Returns a new Rectangle which is shifted by the position of the given * Point. * * @param pt * Point providing the amount of shift along each axis * @return The new translated Rectangle * @since 2.0 */ public Rectangle getTranslated(Point pt) { return getCopy().translate(pt); } /** * Returns a new rectangle whose width and height have been interchanged, as * well as its x and y values. This can be useful in orientation changes. * * @return The transposed rectangle * @since 2.0 */ public Rectangle getTransposed() { return getCopy().transpose(); } /** * Returns a new Rectangle which contains both this Rectangle and the Point * supplied as input. * * @param p * Point for calculating union * @return A new unioned Rectangle * @since 3.7 */ public Rectangle getUnion(Point p) { Rectangle copy = getCopy(); copy.union(p); return copy; } /** * Returns a new Rectangle which contains both this Rectangle and the * Rectangle supplied as input. * * @param rect * Rectangle for calculating union * @return A new unioned Rectangle * @since 2.0 */ public Rectangle getUnion(Rectangle rect) { return getCopy().union(rect); } /** * @see java.lang.Object#hashCode() */ public int hashCode() { return (x + height + 1) * (y + width + 1) ^ x ^ y; } /** * Returns the current height of this Rectangle * * @return The current height * @since 3.7 */ public int height() { return height; } /** * Sets the size of this Rectangle to the intersection region with the * Rectangle supplied as input, and returns this for convenience. The * location and dimensions are set to zero if there is no intersection with * the input Rectangle. * * @param rect * Rectangle for the calculating intersection. * @return <code>this</code> for convenience * @since 2.0 */ public Rectangle intersect(Rectangle rect) { int x1 = Math.max(x, rect.x()); int x2 = Math.min(x + width, rect.x() + rect.width()); int y1 = Math.max(y, rect.y()); int y2 = Math.min(y + height, rect.y() + rect.height()); if (((x2 - x1) < 0) || ((y2 - y1) < 0)) return setBounds(0, 0, 0, 0); // no intersection else { return setBounds(x1, y1, x2 - x1, y2 - y1); } } /** * Returns <code>true</code> if the input Rectangle intersects this * Rectangle. * * @param rect * Rectangle for the intersection test * @return <code>true</code> if the input Rectangle intersects this * Rectangle * @since 2.0 */ public boolean intersects(Rectangle rect) { return !getIntersection(rect).isEmpty(); } /** * Returns <code>true</code> if this Rectangle's width or height is less * than or equal to 0. * * @return <code>true</code> if this Rectangle is empty * @since 2.0 */ public boolean isEmpty() { return width <= 0 || height <= 0; } /** * @see Translatable#performScale(double) */ public void performScale(double factor) { scale(factor); } /** * @see Translatable#performTranslate(int, int) */ public void performTranslate(int dx, int dy) { translate(dx, dy); } /** * Returns <code>double</code> height * * @return <code>double</code> height * @since 3.4 */ public double preciseHeight() { return height; } /** * Returns <code>double</code> width * * @return <code>double</code> width * @since 3.4 */ public double preciseWidth() { return width; } /** * Returns <code>double</code> x coordinate * * @return <code>double</code> x coordinate * @since 3.4 */ public double preciseX() { return x; } /** * Returns <code>double</code> y coordinate * * @return <code>double</code> y coordinate * @since 3.4 */ public double preciseY() { return y; } /** * Resizes this Rectangle by the Dimension provided as input and returns * this for convenience. This Rectange's width will become this.width + * sizeDelta.width. Likewise for height. * * @param d * Resize data as a Dimension * @return <code>this</code> for convenience * @since 2.0 */ public Rectangle resize(Dimension d) { width += d.width(); height += d.height(); return this; } /** * Resizes this Rectangle by the values supplied as input and returns this * for convenience. This Rectangle's width will become this.width + dw. This * Rectangle's height will become this.height + dh. * * @param w * Amount by which width is to be resized * @param h * Amount by which height is to be resized * @return <code>this</code> for convenience * @since 2.0 */ public Rectangle resize(int w, int h) { width += w; height += h; return this; } /** * Returns the x-coordinate of the right side of this Rectangle. * * @return The X coordinate of the right side * @since 2.0 */ public int right() { return x + width; } /** * Scales the location and size of this Rectangle by the given scale and * returns this for convenience. * * @param scaleFactor * The factor by which this rectangle will be scaled * @return <code>this</code> for convenience * @since 2.0 */ public final Rectangle scale(double scaleFactor) { return scale(scaleFactor, scaleFactor); } /** * Scales the location and size of this Rectangle by the given scales and * returns this for convenience. * * @param scaleX * the factor by which the X dimension has to be scaled * @param scaleY * the factor by which the Y dimension has to be scaled * @return <code>this</code> for convenience * @since 2.0 */ public Rectangle scale(double scaleX, double scaleY) { int oldX = x; int oldY = y; x = (int) (Math.floor(x * scaleX)); y = (int) (Math.floor(y * scaleY)); width = (int) (Math.ceil((oldX + width) * scaleX)) - x; height = (int) (Math.ceil((oldY + height) * scaleY)) - y; return this; } /** * Sets the x, y, width, and height values of this Rectangle to the provided * values. * * @param x * The new x * @param y * The new y * @param width * The new width * @param height * The new height * @return this for convenience * @since 3.7 */ public Rectangle setBounds(int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; return this; } /** * Sets the location and size of this rectangle to the provided ones. * * @param location * The new location * @param size * The new size * @return this for convenience * @since 3.7 */ public Rectangle setBounds(Point location, Dimension size) { return setBounds(location.x(), location.y(), size.width(), size.height()); } /** * Sets the parameters of this Rectangle from the Rectangle passed in and * returns this for convenience. * * @return <code>this</code> for convenience * @param rect * Rectangle providing the bounding values * @since 2.0 */ public Rectangle setBounds(Rectangle rect) { return setBounds(rect.x(), rect.y(), rect.width(), rect.height()); } /** * Sets the height of this Rectangle to the specified one. * * @param height * The new height * @return this for convenience. * @since 3.7 */ public Rectangle setHeight(int height) { this.height = height; return this; } /** * Sets the location of this Rectangle to the coordinates given as input and * returns this for convenience. * * @param x * The new X coordinate * @param y * The new Y coordinate * @return <code>this</code> for convenience * @since 2.0 */ public Rectangle setLocation(int x, int y) { this.x = x; this.y = y; return this; } /** * Sets the location of this Rectangle to the point given as input and * returns this for convenience. * * @return <code>this</code> for convenience * @param p * New position of this Rectangle * @since 2.0 */ public Rectangle setLocation(Point p) { return setLocation(p.x(), p.y()); } /** * Sets the width and height of this Rectangle to the width and height of * the given Dimension and returns this for convenience. * * @param d * The new Dimension * @return <code>this</code> for convenience * @since 2.0 */ public Rectangle setSize(Dimension d) { return setSize(d.width(), d.height()); } /** * Sets the width of this Rectangle to <i>w</i> and the height of this * Rectangle to <i>h</i> and returns this for convenience. * * @return <code>this</code> for convenience * @param w * The new width * @param h * The new height * @since 2.0 */ public Rectangle setSize(int w, int h) { width = w; height = h; return this; } /** * Sets the width of this Rectangle to the specified one. * * @param width * The new width * @return this for convenience. * @since 3.7 */ public Rectangle setWidth(int width) { this.width = width; return this; } /** * Sets the x value of the Rectangle and returns this for convenience. * * @return <code>this</code> for convenience * @param x * The new x value * @since 3.7 */ public Rectangle setX(int x) { this.x = x; return this; } /** * Sets the y value of the Rectangle and returns this for convenience. * * @return <code>this</code> for convenience * @param y * The new y value * @since 3.7 */ public Rectangle setY(int y) { this.y = y; return this; } /** * Shrinks this rectangle by the amount specified in <code>insets</code>. * * @param insets * Insets to be removed from the Rectangle * @return <code>this</code> for convenience * @since 3.7 */ public Rectangle shrink(Insets insets) { if (insets == null) return this; x += insets.left; y += insets.top; width -= (insets.getWidth()); height -= (insets.getHeight()); return this; } /** * Shrinks the sides of this Rectangle by the horizontal and vertical values * provided as input, and returns this Rectangle for convenience. The center * of this Rectangle is kept constant. * * @param h * Horizontal reduction amount * @param v * Vertical reduction amount * @return <code>this</code> for convenience * @since 2.0 */ public Rectangle shrink(int h, int v) { x += h; width -= (h + h); y += v; height -= (v + v); return this; } /** * Returns the description of this Rectangle. * * @return String containing the description * @since 2.0 */ public String toString() { return "Rectangle(" + x + ", " + y + ", " + //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ width + ", " + height + ")";//$NON-NLS-2$//$NON-NLS-1$ } /** * Returns <code>true</code> if the input Rectangle touches this Rectangle. * * @param rect * Rectangle being checked for contact * @return <code>true</code> if rect touches this Rectangle * @since 2.0 */ public boolean touches(Rectangle rect) { return rect.x() <= x + width && rect.y() <= y + height && rect.x() + rect.width() >= x && rect.y() + rect.height() >= y; } /** * Moves this Rectangle horizontally by dx and vertically by dy, then * returns this Rectangle for convenience. * * @param dx * Shift along X axis * @param dy * Shift along Y axis * @return <code>this</code> for convenience * @since 2.0 */ public Rectangle translate(int dx, int dy) { x += dx; y += dy; return this; } /** * Moves this Rectangle horizontally by the x value of the given Point and * vertically by the y value of the given Point, then returns this Rectangle * for convenience. * * @param p * Point which provides translation information * @return <code>this</code> for convenience */ public Rectangle translate(Point p) { x += p.x; y += p.y; return this; } /** * Switches the x and y values, as well as the width and height of this * Rectangle. Useful for orientation changes. * * @return <code>this</code> for convenience * @since 2.0 */ public Rectangle transpose() { int temp = x; x = y; y = temp; temp = width; width = height; height = temp; return this; } /** * Unions this Rectangle's width and height with the specified Dimension. * * @param d * Dimension being unioned * @return <code>this</code> for convenience * @since 2.0 * @deprecated Union with a dimension generally does not make much sense, * thus deprecating this. Use * {@link Dimension#max(Dimension, Dimension)} and * {@link #setSize(Dimension)} to implement the desired behavior * instead. */ public Rectangle union(Dimension d) { width = Math.max(width, d.width); height = Math.max(height, d.height); return this; } /** * Updates this Rectangle's bounds to the minimum size which can hold both * this Rectangle and the coordinate (x,y). * * @return <code>this</code> for convenience * @param x1 * X coordinate * @param y1 * Y coordinate * @since 2.0 */ public Rectangle union(int x1, int y1) { if (x1 < x) { width += (x - x1); x = x1; } else { int right = x + width; if (x1 >= right) { right = x1 + 1; width = right - x; } } if (y1 < y) { height += (y - y1); y = y1; } else { int bottom = y + height; if (y1 >= bottom) { bottom = y1 + 1; height = bottom - y; } } return this; } /** * Updates this Rectangle's dimensions to the minimum size which can hold * both this Rectangle and the rectangle (x, y, w, h). * * @param x * X coordinate of desired union. * @param y * Y coordinate of desired union. * @param w * Width of desired union. * @param h * Height of desired union. * @return <code>this</code> for convenience * @since 2.0 */ public Rectangle union(int x, int y, int w, int h) { int right = Math.max(this.x + width, x + w); int bottom = Math.max(this.y + height, y + h); this.x = Math.min(this.x, x); this.y = Math.min(this.y, y); this.width = right - this.x; this.height = bottom - this.y; return this; } /** * Updates this Rectangle's bounds to the minimum size which can hold both * this Rectangle and the given Point. * * @param p * Point to be unioned with this Rectangle * @since 2.0 */ public void union(Point p) { // TODO: This should for the sake of consistency also return this // by convenience; however, this is regarded as API break so it // may be done not sooner than in 4.0; if this is done, it has // to be ensured that the overwritten method in PrecisionRectangle // is adjusted as well. union(p.x(), p.y()); } /** * Updates this Rectangle's dimensions to the minimum size which can hold * both this Rectangle and the given Rectangle. * * @return <code>this</code> for convenience * @param rect * Rectangle to be unioned with this Rectangle * @since 2.0 */ public Rectangle union(Rectangle rect) { if (rect == null || rect.isEmpty()) return this; return union(rect.x, rect.y, rect.width, rect.height); } /** * Returns the current width of this Rectangle * * @return The current width * @since 3.7 */ public int width() { return width; } /** * Returns the x value of this Rectangle. * * @return The current x value * @since 3.7 */ public int x() { return x; } /** * Returns the y value of the Rectangle * * @return The current y value * @since 3.7 */ public int y() { return y; } }