diff --git a/src/main/java/pythagoras/i/AbstractDimension.java b/src/main/java/pythagoras/i/AbstractDimension.java
new file mode 100644
index 0000000..469352d
--- /dev/null
+++ b/src/main/java/pythagoras/i/AbstractDimension.java
@@ -0,0 +1,39 @@
+//
+// Pythagoras - a collection of geometry classes
+// http://github.com/samskivert/pythagoras
+
+package pythagoras.i;
+
+/**
+ * Provides most of the implementation of {@link IDimension}, obtaining only width and height from
+ * the derived class.
+ */
+public abstract class AbstractDimension implements IDimension
+{
+ @Override // from interface IDimension
+ public Dimension clone () {
+ return new Dimension(this);
+ }
+
+ @Override
+ public int hashCode () {
+ return getWidth() ^ getHeight();
+ }
+
+ @Override
+ public boolean equals (Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof AbstractDimension) {
+ AbstractDimension d = (AbstractDimension)obj;
+ return (d.getWidth() == getWidth() && d.getHeight() == getHeight());
+ }
+ return false;
+ }
+
+ @Override
+ public String toString () {
+ return Dimensions.dimenToString(getWidth(), getHeight());
+ }
+}
diff --git a/src/main/java/pythagoras/i/AbstractPoint.java b/src/main/java/pythagoras/i/AbstractPoint.java
new file mode 100644
index 0000000..db1d342
--- /dev/null
+++ b/src/main/java/pythagoras/i/AbstractPoint.java
@@ -0,0 +1,59 @@
+//
+// Pythagoras - a collection of geometry classes
+// http://github.com/samskivert/pythagoras
+
+package pythagoras.i;
+
+/**
+ * Provides most of the implementation of {@link IPoint}, obtaining only the location from the
+ * derived class.
+ */
+public abstract class AbstractPoint implements IPoint
+{
+ @Override // from interface IPoint
+ public int distanceSq (int px, int py) {
+ return Points.distanceSq(getX(), getY(), px, py);
+ }
+
+ @Override // from interface IPoint
+ public int distanceSq (IPoint p) {
+ return Points.distanceSq(getX(), getY(), p.getX(), p.getY());
+ }
+
+ @Override // from interface IPoint
+ public int distance (int px, int py) {
+ return Points.distance(getX(), getY(), px, py);
+ }
+
+ @Override // from interface IPoint
+ public int distance (IPoint p) {
+ return Points.distance(getX(), getY(), p.getX(), p.getY());
+ }
+
+ @Override // from interface IPoint
+ public Point clone () {
+ return new Point(this);
+ }
+
+ @Override
+ public boolean equals (Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof AbstractPoint) {
+ AbstractPoint p = (AbstractPoint)obj;
+ return getX() == p.getX() && getY() == p.getY();
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode () {
+ return getX() ^ getY();
+ }
+
+ @Override
+ public String toString () {
+ return Points.pointToString(getX(), getY());
+ }
+}
diff --git a/src/main/java/pythagoras/i/AbstractRectangle.java b/src/main/java/pythagoras/i/AbstractRectangle.java
new file mode 100644
index 0000000..5b66437
--- /dev/null
+++ b/src/main/java/pythagoras/i/AbstractRectangle.java
@@ -0,0 +1,193 @@
+//
+// Pythagoras - a collection of geometry classes
+// http://github.com/samskivert/pythagoras
+
+package pythagoras.i;
+
+import java.util.NoSuchElementException;
+
+/**
+ * Provides most of the implementation of {@link IRectangle}, obtaining only the location and
+ * dimensions from the derived class.
+ */
+public abstract class AbstractRectangle implements IRectangle
+{
+ @Override // from IRectangle
+ public int getMinX () {
+ return getX();
+ }
+
+ @Override // from IRectangle
+ public int getMinY () {
+ return getY();
+ }
+
+ @Override // from IRectangle
+ public int getMaxX () {
+ return getX() + getWidth() - 1;
+ }
+
+ @Override // from IRectangle
+ public int getMaxY () {
+ return getY() + getHeight() - 1;
+ }
+
+ @Override // from interface IRectangle
+ public Point getLocation () {
+ return getLocation(new Point());
+ }
+
+ @Override // from interface IRectangle
+ public Point getLocation (Point target) {
+ target.setLocation(getX(), getY());
+ return target;
+ }
+
+ @Override // from interface IRectangle
+ public Dimension getSize () {
+ return getSize(new Dimension());
+ }
+
+ @Override // from interface IRectangle
+ public Dimension getSize (Dimension target) {
+ target.setSize(getWidth(), getHeight());
+ return target;
+ }
+
+ @Override // from interface IRectangle
+ public Rectangle intersection (int rx, int ry, int rw, int rh) {
+ int x1 = Math.max(getX(), rx);
+ int y1 = Math.max(getY(), ry);
+ int x2 = Math.min(getMaxX(), rx + rw - 1);
+ int y2 = Math.min(getMaxY(), ry + rh - 1);
+ return new Rectangle(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ @Override // from interface IRectangle
+ public Rectangle intersection (IRectangle r) {
+ return intersection(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ @Override // from interface IRectangle
+ public Rectangle union (IRectangle r) {
+ Rectangle rect = new Rectangle(this);
+ rect.add(r);
+ return rect;
+ }
+
+ @Override // from interface IRectangle
+ public int outcode (int px, int py) {
+ int code = 0;
+
+ if (getWidth() <= 0) {
+ code |= OUT_LEFT | OUT_RIGHT;
+ } else if (px < getX()) {
+ code |= OUT_LEFT;
+ } else if (px > getMaxX()) {
+ code |= OUT_RIGHT;
+ }
+
+ if (getHeight() <= 0) {
+ code |= OUT_TOP | OUT_BOTTOM;
+ } else if (py < getY()) {
+ code |= OUT_TOP;
+ } else if (py > getMaxY()) {
+ code |= OUT_BOTTOM;
+ }
+
+ return code;
+ }
+
+ @Override // from interface IRectangle
+ public int outcode (IPoint p) {
+ return outcode(p.getX(), p.getY());
+ }
+
+ @Override // from interface IRectangle
+ public Rectangle clone () {
+ return new Rectangle(this);
+ }
+
+ @Override // from interface IShape
+ public boolean isEmpty () {
+ return getWidth() <= 0 || getHeight() <= 0;
+ }
+
+ @Override // from interface IShape
+ public boolean contains (int px, int py) {
+ if (isEmpty()) return false;
+
+ int x = getX(), y = getY();
+ if (px < x || py < y) return false;
+
+ px -= x;
+ py -= y;
+ return px < getWidth() && py < getHeight();
+ }
+
+ @Override // from interface IShape
+ public boolean contains (IPoint point) {
+ return contains(point.getX(), point.getY());
+ }
+
+ @Override // from interface IShape
+ public boolean contains (int rx, int ry, int rw, int rh) {
+ if (isEmpty()) return false;
+
+ int x1 = getX(), y1 = getY(), x2 = x1 + getWidth(), y2 = y1 + getHeight();
+ return (x1 <= rx) && (rx + rw <= x2) && (y1 <= ry) && (ry + rh <= y2);
+ }
+
+ @Override // from interface IShape
+ public boolean contains (IRectangle rect) {
+ return contains(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ @Override // from interface IShape
+ public boolean intersects (int rx, int ry, int rw, int rh) {
+ if (isEmpty()) return false;
+
+ int x1 = getX(), y1 = getY(), x2 = x1 + getWidth(), y2 = y1 + getHeight();
+ return (rx + rw > x1) && (rx < x2) && (ry + rh > y1) && (ry < y2);
+ }
+
+ @Override // from interface IShape
+ public boolean intersects (IRectangle rect) {
+ return intersects(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ @Override // from interface IShape
+ public Rectangle getBounds () {
+ return getBounds(new Rectangle());
+ }
+
+ @Override // from interface IShape
+ public Rectangle getBounds (Rectangle target) {
+ target.setBounds(getX(), getY(), getWidth(), getHeight());
+ return target;
+ }
+
+ @Override // from Object
+ public boolean equals (Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof AbstractRectangle) {
+ AbstractRectangle r = (AbstractRectangle)obj;
+ return r.getX() == getX() && r.getY() == getY() &&
+ r.getWidth() == getWidth() && r.getHeight() == getHeight();
+ }
+ return false;
+ }
+
+ @Override // from Object
+ public int hashCode () {
+ return getX() ^ getY() ^ getWidth() ^ getHeight();
+ }
+
+ @Override // from Object
+ public String toString () {
+ return Dimensions.dimenToString(getWidth(), getHeight()) +
+ Points.pointToString(getX(), getY());
+ }
+}
diff --git a/src/main/java/pythagoras/i/Dimension.java b/src/main/java/pythagoras/i/Dimension.java
new file mode 100644
index 0000000..1d0ed0f
--- /dev/null
+++ b/src/main/java/pythagoras/i/Dimension.java
@@ -0,0 +1,65 @@
+//
+// Pythagoras - a collection of geometry classes
+// http://github.com/samskivert/pythagoras
+
+package pythagoras.i;
+
+import java.io.Serializable;
+
+/**
+ * Represents a magnitude in two dimensions.
+ */
+public class Dimension extends AbstractDimension implements Serializable
+{
+ /** The magnitude in the x-dimension. */
+ public int width;
+
+ /** The magnitude in the y-dimension. */
+ public int height;
+
+ /**
+ * Creates a dimension with magnitude (0, 0).
+ */
+ public Dimension () {
+ this(0, 0);
+ }
+
+ /**
+ * Creates a dimension with the specified width and height.
+ */
+ public Dimension (int width, int height) {
+ setSize(width, height);
+ }
+
+ /**
+ * Creates a dimension with width and height equal to the supplied dimension.
+ */
+ public Dimension (IDimension d) {
+ this(d.getWidth(), d.getHeight());
+ }
+
+ /**
+ * Sets the magnitudes of this dimension to the specified width and height.
+ */
+ public void setSize (int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * Sets the magnitudes of this dimension to be equal to the supplied dimension.
+ */
+ public void setSize (IDimension d) {
+ setSize(d.getWidth(), d.getHeight());
+ }
+
+ @Override // from interface IDimension
+ public int getWidth () {
+ return width;
+ }
+
+ @Override // from interface IDimension
+ public int getHeight () {
+ return height;
+ }
+}
diff --git a/src/main/java/pythagoras/i/Dimensions.java b/src/main/java/pythagoras/i/Dimensions.java
new file mode 100644
index 0000000..8536d11
--- /dev/null
+++ b/src/main/java/pythagoras/i/Dimensions.java
@@ -0,0 +1,18 @@
+//
+// Pythagoras - a collection of geometry classes
+// http://github.com/samskivert/pythagoras
+
+package pythagoras.i;
+
+/**
+ * Dimension-related utility methods.
+ */
+public class Dimensions
+{
+ /**
+ * Returns a string describing the supplied dimension, of the form {@code widthxheight}.
+ */
+ public static String dimenToString (int width, int height) {
+ return width + "x" + height;
+ }
+}
diff --git a/src/main/java/pythagoras/i/IDimension.java b/src/main/java/pythagoras/i/IDimension.java
new file mode 100644
index 0000000..2fdfc5f
--- /dev/null
+++ b/src/main/java/pythagoras/i/IDimension.java
@@ -0,0 +1,26 @@
+//
+// Pythagoras - a collection of geometry classes
+// http://github.com/samskivert/pythagoras
+
+package pythagoras.i;
+
+/**
+ * Provides read-only access to a {@link Dimension}.
+ */
+public interface IDimension extends Cloneable
+{
+ /**
+ * Returns the magnitude in the x-dimension.
+ */
+ int getWidth ();
+
+ /**
+ * Returns the magnitude in the y-dimension.
+ */
+ int getHeight ();
+
+ /**
+ * Returns a mutable copy of this dimension.
+ */
+ Dimension clone ();
+}
diff --git a/src/main/java/pythagoras/i/IPoint.java b/src/main/java/pythagoras/i/IPoint.java
new file mode 100644
index 0000000..b9e8f7b
--- /dev/null
+++ b/src/main/java/pythagoras/i/IPoint.java
@@ -0,0 +1,32 @@
+//
+// Pythagoras - a collection of geometry classes
+// http://github.com/samskivert/pythagoras
+
+package pythagoras.i;
+
+/**
+ * Provides read-only access to a {@link Point}.
+ */
+public interface IPoint extends Cloneable
+{
+ /** Returns this point's x-coordinate. */
+ int getX ();
+
+ /** Returns this point's y-coordinate. */
+ int getY ();
+
+ /** Returns the squared Euclidian distance between this point and the specified point. */
+ int distanceSq (int px, int py);
+
+ /** Returns the squared Euclidian distance between this point and the supplied point. */
+ int distanceSq (IPoint p);
+
+ /** Returns the Euclidian distance between this point and the specified point. */
+ int distance (int px, int py);
+
+ /** Returns the Euclidian distance between this point and the supplied point. */
+ int distance (IPoint p);
+
+ /** Returns a mutable copy of this point. */
+ Point clone ();
+}
diff --git a/src/main/java/pythagoras/i/IRectangle.java b/src/main/java/pythagoras/i/IRectangle.java
new file mode 100644
index 0000000..a0641ab
--- /dev/null
+++ b/src/main/java/pythagoras/i/IRectangle.java
@@ -0,0 +1,90 @@
+//
+// Pythagoras - a collection of geometry classes
+// http://github.com/samskivert/pythagoras
+
+package pythagoras.i;
+
+/**
+ * Provides read-only access to a {@link Rectangle}.
+ */
+public interface IRectangle extends IShape, Cloneable
+{
+ /** The bitmask that indicates that a point lies to the left of this rectangle. See
+ * {@link #outcode}. */
+ int OUT_LEFT = 1;
+
+ /** The bitmask that indicates that a point lies above this rectangle. See {@link #outcode}. */
+ int OUT_TOP = 2;
+
+ /** The bitmask that indicates that a point lies to the right of this rectangle. See
+ * {@link #outcode}. */
+ int OUT_RIGHT = 4;
+
+ /** The bitmask that indicates that a point lies below this rectangle. See {@link #outcode}. */
+ int OUT_BOTTOM = 8;
+
+ /** Returns the x-coordinate of the upper-left corner of the framing rectangle. */
+ int getX ();
+
+ /** Returns the y-coordinate of the upper-left corner of the framing rectangle. */
+ int getY ();
+
+ /** Returns the width of the framing rectangle. */
+ int getWidth ();
+
+ /** Returns the height of the framing rectangle. */
+ int getHeight ();
+
+ /** Returns the minimum x-coordinate of the framing rectangle. */
+ int getMinX ();
+
+ /** Returns the minimum y-coordinate of the framing rectangle. */
+ int getMinY ();
+
+ /** Returns the maximum x-coordinate of the framing rectangle. Note: this method
+ * differs from its inting-point counterparts in that it considers {@code (x + width - 1)} to
+ * be a rectangle's maximum x-coordinate. */
+ int getMaxX ();
+
+ /** Returns the maximum y-coordinate of the framing rectangle. Note: this method
+ * differs from its inting-point counterparts in that it considers {@code (y + height - 1)}
+ * to be a rectangle's maximum x-coordinate. */
+ int getMaxY ();
+
+ /** Returns a copy of this rectangle's upper-left corner. */
+ Point getLocation ();
+
+ /** Initializes the supplied point with this rectangle's upper-left corner.
+ * @return the supplied point. */
+ Point getLocation (Point target);
+
+ /** Returns a copy of this rectangle's size. */
+ Dimension getSize ();
+
+ /** Initializes the supplied dimension with this rectangle's size.
+ * @return the supplied dimension. */
+ Dimension getSize (Dimension target);
+
+ /** Returns the intersection of the specified rectangle and this rectangle (i.e. the largest
+ * rectangle contained in both this and the specified rectangle). */
+ Rectangle intersection (int rx, int ry, int rw, int rh);
+
+ /** Returns the intersection of the supplied rectangle and this rectangle (i.e. the largest
+ * rectangle contained in both this and the supplied rectangle). */
+ Rectangle intersection (IRectangle r);
+
+ /** Returns the union of the supplied rectangle and this rectangle (i.e. the smallest rectangle
+ * that contains both this and the supplied rectangle). */
+ Rectangle union (IRectangle r);
+
+ /** Returns a set of flags indicating where the specified point lies in relation to the bounds
+ * of this rectangle. See {@link #OUT_LEFT}, etc. */
+ int outcode (int px, int py);
+
+ /** Returns a set of flags indicating where the supplied point lies in relation to the bounds of
+ * this rectangle. See {@link #OUT_LEFT}, etc. */
+ int outcode (IPoint point);
+
+ /** Returns a mutable copy of this rectangle. */
+ Rectangle clone ();
+}
diff --git a/src/main/java/pythagoras/i/IShape.java b/src/main/java/pythagoras/i/IShape.java
new file mode 100644
index 0000000..a97ba0a
--- /dev/null
+++ b/src/main/java/pythagoras/i/IShape.java
@@ -0,0 +1,39 @@
+//
+// Pythagoras - a collection of geometry classes
+// http://github.com/samskivert/pythagoras
+
+package pythagoras.i;
+
+/**
+ * An interface provided by all shapes.
+ */
+public interface IShape
+{
+ /** Returns true if this shape encloses no area. */
+ boolean isEmpty ();
+
+ /** Returns true if this shape contains the specified point. */
+ boolean contains (int x, int y);
+
+ /** Returns true if this shape contains the supplied point. */
+ boolean contains (IPoint point);
+
+ /** Returns true if this shape completely contains the specified rectangle. */
+ boolean contains (int x, int y, int width, int height);
+
+ /** Returns true if this shape completely contains the supplied rectangle. */
+ boolean contains (IRectangle r);
+
+ /** Returns true if this shape intersects the specified rectangle. */
+ boolean intersects (int x, int y, int width, int height);
+
+ /** Returns true if this shape intersects the supplied rectangle. */
+ boolean intersects (IRectangle r);
+
+ /** Returns a copy of the bounding rectangle for this shape. */
+ Rectangle getBounds ();
+
+ /** Initializes the supplied rectangle with this shape's bounding rectangle.
+ * @return the supplied rectangle. */
+ Rectangle getBounds (Rectangle target);
+}
diff --git a/src/main/java/pythagoras/i/Point.java b/src/main/java/pythagoras/i/Point.java
new file mode 100644
index 0000000..6871ccd
--- /dev/null
+++ b/src/main/java/pythagoras/i/Point.java
@@ -0,0 +1,79 @@
+//
+// Pythagoras - a collection of geometry classes
+// http://github.com/samskivert/pythagoras
+
+package pythagoras.i;
+
+import java.io.Serializable;
+
+/**
+ * Represents a point on a plane.
+ */
+public class Point extends AbstractPoint implements Serializable
+{
+ /** The x-coordinate of the point. */
+ public int x;
+
+ /** The y-coordinate of the point. */
+ public int y;
+
+ /**
+ * Constructs a point at (0, 0).
+ */
+ public Point () {
+ }
+
+ /**
+ * Constructs a point at the specified coordinates.
+ */
+ public Point (int x, int y) {
+ setLocation(x, y);
+ }
+
+ /**
+ * Constructs a point with coordinates equal to the supplied point.
+ */
+ public Point (IPoint p) {
+ setLocation(p.getX(), p.getY());
+ }
+
+ /**
+ * Sets the coordinates of this point to be equal to those of the supplied point.
+ */
+ public void setLocation (IPoint p) {
+ setLocation(p.getX(), p.getY());
+ }
+
+ /**
+ * Sets the coordinates of this point to the supplied values.
+ */
+ public void setLocation (int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * A synonym for {@link #setLocation}.
+ */
+ public void move (int x, int y) {
+ setLocation(x, y);
+ }
+
+ /**
+ * Translates this point by the specified offset.
+ */
+ public void translate (int dx, int dy) {
+ x += dx;
+ y += dy;
+ }
+
+ @Override // from interface IPoint
+ public int getX () {
+ return x;
+ }
+
+ @Override // from interface IPoint
+ public int getY () {
+ return y;
+ }
+}
diff --git a/src/main/java/pythagoras/i/Points.java b/src/main/java/pythagoras/i/Points.java
new file mode 100644
index 0000000..bfc6a9d
--- /dev/null
+++ b/src/main/java/pythagoras/i/Points.java
@@ -0,0 +1,49 @@
+//
+// Pythagoras - a collection of geometry classes
+// http://github.com/samskivert/pythagoras
+
+package pythagoras.i;
+
+/**
+ * Point-related utility methods.
+ */
+public class Points
+{
+ /**
+ * Returns the squared Euclidian distance between the specified two points.
+ */
+ public static int distanceSq (int x1, int y1, int x2, int y2) {
+ x2 -= x1;
+ y2 -= y1;
+ return x2 * x2 + y2 * y2;
+ }
+
+ /**
+ * Returns the Euclidian distance between the specified two points, truncated to the nearest
+ * integer.
+ */
+ public static int distance (int x1, int y1, int x2, int y2) {
+ return (int)Math.sqrt(distanceSq(x1, y1, x2, y2));
+ }
+
+ /**
+ * Returns the Manhattan distance between the specified two points.
+ */
+ public static int manhattanDistance (int x1, int y1, int x2, int y2)
+ {
+ return Math.abs(x2 - x1) + Math.abs(y2 - y1);
+ }
+
+ /**
+ * Returns a string describing the supplied point, of the form {@code +x+y}, {@code +x-y},
+ * {@code -x-y}, etc.
+ */
+ public static String pointToString (int x, int y) {
+ StringBuilder buf = new StringBuilder();
+ if (x >= 0) buf.append("+");
+ buf.append(x);
+ if (y >= 0) buf.append("+");
+ buf.append(y);
+ return buf.toString();
+ }
+}
diff --git a/src/main/java/pythagoras/i/Rectangle.java b/src/main/java/pythagoras/i/Rectangle.java
new file mode 100644
index 0000000..19cbbbf
--- /dev/null
+++ b/src/main/java/pythagoras/i/Rectangle.java
@@ -0,0 +1,183 @@
+//
+// Pythagoras - a collection of geometry classes
+// http://github.com/samskivert/pythagoras
+
+package pythagoras.i;
+
+import java.io.Serializable;
+
+/**
+ * Represents an area in two dimensions.
+ */
+public class Rectangle extends AbstractRectangle implements Serializable
+{
+ /** The x-coordinate of the rectangle's upper left corner. */
+ public int x;
+
+ /** The y-coordinate of the rectangle's upper left corner. */
+ public int y;
+
+ /** The width of the rectangle. */
+ public int width;
+
+ /** The height of the rectangle. */
+ public int height;
+
+ /**
+ * Constructs a rectangle at (0,0) and with dimensions (0,0).
+ */
+ public Rectangle () {
+ }
+
+ /**
+ * Constructs a rectangle with the supplied upper-left corner and dimensions (0,0).
+ */
+ public Rectangle (IPoint p) {
+ setBounds(p.getX(), p.getY(), 0, 0);
+ }
+
+ /**
+ * Constructs a rectangle with upper-left corner at (0,) and the supplied dimensions.
+ */
+ public Rectangle (IDimension d) {
+ setBounds(0, 0, d.getWidth(), d.getHeight());
+ }
+
+ /**
+ * Constructs a rectangle with upper-left corner at the supplied point and with the supplied
+ * dimensions.
+ */
+ public Rectangle (IPoint p, IDimension d) {
+ setBounds(p.getX(), p.getY(), d.getWidth(), d.getHeight());
+ }
+
+ /**
+ * Constructs a rectangle with the specified upper-left corner and dimensions.
+ */
+ public Rectangle (int x, int y, int width, int height) {
+ setBounds(x, y, width, height);
+ }
+
+ /**
+ * Constructs a rectangle with bounds equal to the supplied rectangle.
+ */
+ public Rectangle (IRectangle r) {
+ setBounds(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ /**
+ * Sets the upper-left corner of this rectangle to the specified point.
+ */
+ public void setLocation (int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Sets the upper-left corner of this rectangle to the supplied point.
+ */
+ public void setLocation (IPoint p) {
+ setLocation(p.getX(), p.getY());
+ }
+
+ /**
+ * Sets the size of this rectangle to the specified dimensions.
+ */
+ public void setSize (int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * Sets the size of this rectangle to the supplied dimensions.
+ */
+ public void setSize (IDimension d) {
+ setSize(d.getWidth(), d.getHeight());
+ }
+
+ /**
+ * Sets the bounds of this rectangle to the specified bounds.
+ */
+ public void setBounds (int x, int y, int width, int height) {
+ this.x = x;
+ this.y = y;
+ this.height = height;
+ this.width = width;
+ }
+
+ /**
+ * Sets the bounds of this rectangle to those of the supplied rectangle.
+ */
+ public void setBounds (IRectangle r) {
+ setBounds(r.getX(), r.getY(), r.getWidth(), r.getHeight());
+ }
+
+ /**
+ * Grows the bounds of this rectangle by the specified amount (i.e. the upper-left corner moves
+ * by the specified amount in the negative x and y direction and the width and height grow by
+ * twice the specified amount).
+ */
+ public void grow (int dx, int dy) {
+ x -= dx;
+ y -= dy;
+ width += dx + dx;
+ height += dy + dy;
+ }
+
+ /**
+ * Translates the upper-left corner of this rectangle by the specified amount.
+ */
+ public void translate (int mx, int my) {
+ x += mx;
+ y += my;
+ }
+
+ /**
+ * Expands the bounds of this rectangle to contain the specified point.
+ */
+ public void add (int px, int py) {
+ int x1 = Math.min(x, px);
+ int x2 = Math.max(x + width, px);
+ int y1 = Math.min(y, py);
+ int y2 = Math.max(y + height, py);
+ setBounds(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Expands the bounds of this rectangle to contain the supplied point.
+ */
+ public void add (IPoint p) {
+ add(p.getX(), p.getY());
+ }
+
+ /**
+ * Expands the bounds of this rectangle to contain the supplied rectangle.
+ */
+ public void add (IRectangle 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());
+ setBounds(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ @Override // from interface IRectangle
+ public int getX () {
+ return x;
+ }
+
+ @Override // from interface IRectangle
+ public int getY () {
+ return y;
+ }
+
+ @Override // from interface IRectangle
+ public int getWidth () {
+ return width;
+ }
+
+ @Override // from interface IRectangle
+ public int getHeight () {
+ return height;
+ }
+}
diff --git a/src/main/java/pythagoras/i/Rectangles.java b/src/main/java/pythagoras/i/Rectangles.java
new file mode 100644
index 0000000..0eee539
--- /dev/null
+++ b/src/main/java/pythagoras/i/Rectangles.java
@@ -0,0 +1,33 @@
+//
+// Pythagoras - a collection of geometry classes
+// http://github.com/samskivert/pythagoras
+
+package pythagoras.i;
+
+/**
+ * Rectangle-related utility methods.
+ */
+public class Rectangles
+{
+ /**
+ * Intersects the supplied two rectangles, writing the result into {@code dst}.
+ */
+ public static void intersect (IRectangle src1, IRectangle src2, Rectangle dst) {
+ int x1 = Math.max(src1.getMinX(), src2.getMinX());
+ int y1 = Math.max(src1.getMinY(), src2.getMinY());
+ int x2 = Math.min(src1.getMaxX(), src2.getMaxX());
+ int y2 = Math.min(src1.getMaxY(), src2.getMaxY());
+ dst.setBounds(x1, y1, x2 - x1, y2 - y1);
+ }
+
+ /**
+ * Unions the supplied two rectangles, writing the result into {@code dst}.
+ */
+ public static void union (IRectangle src1, IRectangle src2, Rectangle dst) {
+ int x1 = Math.min(src1.getMinX(), src2.getMinX());
+ int y1 = Math.min(src1.getMinY(), src2.getMinY());
+ int x2 = Math.max(src1.getMaxX(), src2.getMaxX());
+ int y2 = Math.max(src1.getMaxY(), src2.getMaxY());
+ dst.setBounds(x1, y1, x2 - x1, y2 - y1);
+ }
+}