org.lwjgl.util.Rectangle Maven / Gradle / Ivy
Show all versions of lwjgl_util Show documentation
/*
* Copyright (c) 2002-2008 LWJGL Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'LWJGL' nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.lwjgl.util;
import java.io.Serializable;
/**
* A 2D integer Rectangle class which looks remarkably like an AWT one.
* @author $Author$
* @version $Revision$
* $Id$
*/
public final class Rectangle implements ReadableRectangle, WritableRectangle, Serializable {
static final long serialVersionUID = 1L;
/** Rectangle's bounds */
private int x, y, width, height;
/**
* Constructor for Rectangle.
*/
public Rectangle() {
super();
}
/**
* Constructor for Rectangle.
*/
public Rectangle(int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.width = w;
this.height = h;
}
/**
* Constructor for Rectangle.
*/
public Rectangle(ReadablePoint p, ReadableDimension d) {
x = p.getX();
y = p.getY();
width = d.getWidth();
height = d.getHeight();
}
/**
* Constructor for Rectangle.
*/
public Rectangle(ReadableRectangle r) {
x = r.getX();
y = r.getY();
width = r.getWidth();
height = r.getHeight();
}
public void setLocation(int x, int y) {
this.x = x;
this.y = y;
}
public void setLocation(ReadablePoint p) {
this.x = p.getX();
this.y = p.getY();
}
public void setSize(int w, int h) {
this.width = w;
this.height = h;
}
public void setSize(ReadableDimension d) {
this.width = d.getWidth();
this.height = d.getHeight();
}
public void setBounds(int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.width = w;
this.height = h;
}
public void setBounds(ReadablePoint p, ReadableDimension d) {
x = p.getX();
y = p.getY();
width = d.getWidth();
height = d.getHeight();
}
public void setBounds(ReadableRectangle r) {
x = r.getX();
y = r.getY();
width = r.getWidth();
height = r.getHeight();
}
/* (Overrides)
* @see com.shavenpuppy.jglib.ReadableRectangle#getBounds(com.shavenpuppy.jglib.Rectangle)
*/
public void getBounds(WritableRectangle dest) {
dest.setBounds(x, y, width, height);
}
/* (Overrides)
* @see com.shavenpuppy.jglib.ReadablePoint#getLocation(com.shavenpuppy.jglib.Point)
*/
public void getLocation(WritablePoint dest) {
dest.setLocation(x, y);
}
/* (Overrides)
* @see com.shavenpuppy.jglib.ReadableDimension#getSize(com.shavenpuppy.jglib.Dimension)
*/
public void getSize(WritableDimension dest) {
dest.setSize(width, height);
}
/**
* Translate the rectangle by an amount.
* @param x The translation amount on the x axis
* @param y The translation amount on the y axis
*/
public void translate(int x, int y) {
this.x += x;
this.y += y;
}
/**
* Translate the rectangle by an amount.
* @param point The translation amount
*/
public void translate(ReadablePoint point) {
this.x += point.getX();
this.y += point.getY();
}
/**
* Un-translate the rectangle by an amount.
* @param point The translation amount
*/
public void untranslate(ReadablePoint point) {
this.x -= point.getX();
this.y -= point.getY();
}
/**
* Checks whether or not this Rectangle
contains the
* specified Point
.
* @param p the Point
to test
* @return true
if the Point
* (x, y) is inside this
* Rectangle
;
* false
otherwise.
*/
public boolean contains(ReadablePoint p) {
return contains(p.getX(), p.getY());
}
/**
* Checks whether or not this Rectangle
contains the
* point at the specified location
* (x, y).
* @param X the specified x coordinate
* @param Y the specified y coordinate
* @return true
if the point
* (x, y) is inside this
* Rectangle
;
* false
otherwise.
*/
public boolean contains(int X, int Y) {
int w = this.width;
int h = this.height;
if ((w | h) < 0) {
// At least one of the dimensions is negative...
return false;
}
// Note: if either dimension is zero, tests below must return false...
int x = this.x;
int y = this.y;
if (X < x || Y < y) {
return false;
}
w += x;
h += y;
// overflow || intersect
return ((w < x || w > X) && (h < y || h > Y));
}
/**
* Checks whether or not this Rectangle
entirely contains
* the specified Rectangle
.
* @param r the specified Rectangle
* @return true
if the Rectangle
* is contained entirely inside this Rectangle
;
* false
otherwise.
*/
public boolean contains(ReadableRectangle r) {
return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
/**
* Checks whether this Rectangle
entirely contains
* the Rectangle
* at the specified location (X, Y) with the
* specified dimensions (W, H).
* @param X the specified x coordinate
* @param Y the specified y coordinate
* @param W the width of the Rectangle
* @param H the height of the Rectangle
* @return true
if the Rectangle
specified by
* (X, Y, W, H)
* is entirely enclosed inside this Rectangle
;
* false
otherwise.
*/
public boolean contains(int X, int Y, int W, int H) {
int w = this.width;
int h = this.height;
if ((w | h | W | H) < 0) {
// At least one of the dimensions is negative...
return false;
}
// Note: if any dimension is zero, tests below must return false...
int x = this.x;
int y = this.y;
if (X < x || Y < y) {
return false;
}
w += x;
W += X;
if (W <= X) {
// X+W overflowed or W was zero, return false if...
// either original w or W was zero or
// x+w did not overflow or
// the overflowed x+w is smaller than the overflowed X+W
if (w >= x || W > w)
return false;
} else {
// X+W did not overflow and W was not zero, return false if...
// original w was zero or
// x+w did not overflow and x+w is smaller than X+W
if (w >= x && W > w)
return false;
}
h += y;
H += Y;
if (H <= Y) {
if (h >= y || H > h)
return false;
} else {
if (h >= y && H > h)
return false;
}
return true;
}
/**
* Determines whether or not this Rectangle
and the specified
* Rectangle
intersect. Two rectangles intersect if
* their intersection is nonempty.
*
* @param r the specified Rectangle
* @return true
if the specified Rectangle
* and this Rectangle
intersect;
* false
otherwise.
*/
public boolean intersects(ReadableRectangle r) {
int tw = this.width;
int th = this.height;
int rw = r.getWidth();
int rh = r.getHeight();
if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) {
return false;
}
int tx = this.x;
int ty = this.y;
int rx = r.getX();
int ry = r.getY();
rw += rx;
rh += ry;
tw += tx;
th += ty;
// overflow || intersect
return ((rw < rx || rw > tx) && (rh < ry || rh > ty) && (tw < tx || tw > rx) && (th < ty || th > ry));
}
/**
* Computes the intersection of this Rectangle
with the
* specified Rectangle
. Returns a new Rectangle
* that represents the intersection of the two rectangles.
* If the two rectangles do not intersect, the result will be
* an empty rectangle.
*
* @param r the specified Rectangle
* @return the largest Rectangle
contained in both the
* specified Rectangle
and in
* this Rectangle
; or if the rectangles
* do not intersect, an empty rectangle.
*/
public Rectangle intersection(ReadableRectangle r, Rectangle dest) {
int tx1 = this.x;
int ty1 = this.y;
int rx1 = r.getX();
int ry1 = r.getY();
long tx2 = tx1;
tx2 += this.width;
long ty2 = ty1;
ty2 += this.height;
long rx2 = rx1;
rx2 += r.getWidth();
long ry2 = ry1;
ry2 += r.getHeight();
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 overflow (they will never be
// larger than the smallest of the two source w,h)
// they might underflow, though...
if (tx2 < Integer.MIN_VALUE)
tx2 = Integer.MIN_VALUE;
if (ty2 < Integer.MIN_VALUE)
ty2 = Integer.MIN_VALUE;
if (dest == null)
dest = new Rectangle(tx1, ty1, (int) tx2, (int) ty2);
else
dest.setBounds(tx1, ty1, (int) tx2, (int) ty2);
return dest;
}
/**
* Computes the union of this Rectangle
with the
* specified Rectangle
. Returns a new
* Rectangle
that
* represents the union of the two rectangles
* @param r the specified Rectangle
* @return the smallest Rectangle
containing both
* the specified Rectangle
and this
* Rectangle
.
*/
public WritableRectangle union(ReadableRectangle r, WritableRectangle dest) {
int x1 = Math.min(x, r.getX());
int x2 = Math.max(x + width, r.getX() + r.getWidth());
int y1 = Math.min(y, r.getY());
int y2 = Math.max(y + height, r.getY() + r.getHeight());
dest.setBounds(x1, y1, x2 - x1, y2 - y1);
return dest;
}
/**
* Adds a point, specified by the integer arguments newx
* and newy
, to this Rectangle
. The
* resulting Rectangle
is
* the smallest Rectangle
that contains both the
* original Rectangle
and the specified point.
*
* After adding a point, a call to contains
with the
* added point as an argument does not necessarily return
* true
. The contains
method does not
* return true
for points on the right or bottom
* edges of a Rectangle
. Therefore, if the added point
* falls on the right or bottom edge of the enlarged
* Rectangle
, contains
returns
* false
for that point.
* @param newx the x coordinates of the new point
* @param newy the y coordinates of the new point
*/
public void add(int newx, int newy) {
int x1 = Math.min(x, newx);
int x2 = Math.max(x + width, newx);
int y1 = Math.min(y, newy);
int y2 = Math.max(y + height, newy);
x = x1;
y = y1;
width = x2 - x1;
height = y2 - y1;
}
/**
* Adds the specified Point
to this
* Rectangle
. The resulting Rectangle
* is the smallest Rectangle
that contains both the
* original Rectangle
and the specified
* Point
.
*
* After adding a Point
, a call to contains
* with the added Point
as an argument does not
* necessarily return true
. The contains
* method does not return true
for points on the right
* or bottom edges of a Rectangle
. Therefore if the added
* Point
falls on the right or bottom edge of the
* enlarged Rectangle
, contains
returns
* false
for that Point
.
* @param pt the new Point
to add to this
* Rectangle
*/
public void add(ReadablePoint pt) {
add(pt.getX(), pt.getY());
}
/**
* Adds a Rectangle
to this Rectangle
.
* The resulting Rectangle
is the union of the two
* rectangles.
* @param r the specified Rectangle
*/
public void add(ReadableRectangle r) {
int x1 = Math.min(x, r.getX());
int x2 = Math.max(x + width, r.getX() + r.getWidth());
int y1 = Math.min(y, r.getY());
int y2 = Math.max(y + height, r.getY() + r.getHeight());
x = x1;
y = y1;
width = x2 - x1;
height = y2 - y1;
}
/**
* Resizes the Rectangle
both horizontally and vertically.
*
* This method modifies the Rectangle
so that it is
* h
units larger on both the left and right side,
* and v
units larger at both the top and bottom.
*
* The new Rectangle
has (x - h
,
* y - v
) as its top-left corner, a
* width of
* width
+
2h
,
* and a height of
* height
+
2v
.
*
* If negative values are supplied for h
and
* v
, the size of the Rectangle
* decreases accordingly.
* The grow
method does not check whether the resulting
* values of width
and height
are
* non-negative.
* @param h the horizontal expansion
* @param v the vertical expansion
*/
public void grow(int h, int v) {
x -= h;
y -= v;
width += h * 2;
height += v * 2;
}
/**
* Determines whether or not this Rectangle
is empty. A
* Rectangle
is empty if its width or its height is less
* than or equal to zero.
* @return true
if this Rectangle
is empty;
* false
otherwise.
*/
public boolean isEmpty() {
return (width <= 0) || (height <= 0);
}
/**
* Checks whether two rectangles are equal.
*
* The result is true
if and only if the argument is not
* null
and is a Rectangle
object that has the
* same top-left corner, width, and height as this Rectangle
.
* @param obj the Object
to compare with
* this Rectangle
* @return true
if the objects are equal;
* false
otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof Rectangle) {
Rectangle r = (Rectangle) obj;
return ((x == r.x) && (y == r.y) && (width == r.width) && (height == r.height));
}
return super.equals(obj);
}
/**
* Debugging
* @return a String
*/
public String toString() {
return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]";
}
/**
* Gets the height.
* @return Returns a int
*/
public int getHeight() {
return height;
}
/**
* Sets the height.
* @param height The height to set
*/
public void setHeight(int height) {
this.height = height;
}
/**
* Gets the width.
* @return Returns a int
*/
public int getWidth() {
return width;
}
/**
* Sets the width.
* @param width The width to set
*/
public void setWidth(int width) {
this.width = width;
}
/**
* Gets the x.
* @return Returns a int
*/
public int getX() {
return x;
}
/**
* Sets the x.
* @param x The x to set
*/
public void setX(int x) {
this.x = x;
}
/**
* Gets the y.
* @return Returns a int
*/
public int getY() {
return y;
}
/**
* Sets the y.
* @param y The y to set
*/
public void setY(int y) {
this.y = y;
}
}