--- /dev/null
+// Rectangle.java
+// Java Spatial Index Library
+// Copyright (C) 2002 Infomatiq Limited
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+package com.infomatiq.jsi;
+
+import java.util.Arrays;
+
+/**
+ * Currently hardcoded to 2 dimensions, but could be extended.
+ *
+ * @author aled.morris@infomatiq.co.uk
+ * @version 1.0b2
+ */
+public class Rectangle {
+ /**
+ * Number of dimensions in a rectangle. In theory this
+ * could be exended to three or more dimensions.
+ */
+ public final static int DIMENSIONS = 3;
+
+ /**
+ * array containing the minimum value for each dimension; ie { min(x), min(y) }
+ */
+ public float[] max;
+
+ /**
+ * array containing the maximum value for each dimension; ie { max(x), max(y) }
+ */
+ public float[] min;
+
+ /**
+ * Constructor.
+ *
+ * @param x1 coordinate of any corner of the rectangle
+ * @param y1 (see x1)
+ * @param x2 coordinate of the opposite corner
+ * @param y2 (see x2)
+ */
+ public Rectangle(float x1, float y1, float z1, float x2, float y2, float z2) {
+ min = new float[DIMENSIONS];
+ max = new float[DIMENSIONS];
+ set(x1, y1, z1, x2, y2, z2);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param min array containing the minimum value for each dimension; ie { min(x), min(y) }
+ * @param max array containing the maximum value for each dimension; ie { max(x), max(y) }
+ */
+ public Rectangle(float[] min, float[] max) {
+ if (min.length != DIMENSIONS || max.length != DIMENSIONS) {
+ throw new RuntimeException("Error in Rectangle constructor: " +
+ "min and max arrays must be of length " + DIMENSIONS);
+ }
+
+ this.min = new float[DIMENSIONS];
+ this.max = new float[DIMENSIONS];
+
+ set(min, max);
+ }
+
+ /**
+ * Sets the size of the rectangle.
+ *
+ * @param x1 coordinate of any corner of the rectangle
+ * @param y1 (see x1)
+ * @param x2 coordinate of the opposite corner
+ * @param y2 (see x2)
+ */
+ public void set(float x1, float y1, float z1, float x2, float y2, float z2) {
+ min[0] = Math.min(x1, x2);
+ min[1] = Math.min(y1, y2);
+ min[2] = Math.min(z1, z2);
+ max[0] = Math.max(x1, x2);
+ max[1] = Math.max(y1, y2);
+ max[2] = Math.max(z1, z2);
+ }
+
+ /**
+ * Sets the size of the rectangle.
+ *
+ * @param min array containing the minimum value for each dimension; ie { min(x), min(y) }
+ * @param max array containing the maximum value for each dimension; ie { max(x), max(y) }
+ */
+ public void set(float[] min, float[] max) {
+ System.arraycopy(min, 0, this.min, 0, DIMENSIONS);
+ System.arraycopy(max, 0, this.max, 0, DIMENSIONS);
+ }
+
+ /**
+ * Make a copy of this rectangle
+ *
+ * @return copy of this rectangle
+ */
+ public Rectangle copy() {
+ return new Rectangle(min, max);
+ }
+
+ /**
+ * Determine whether an edge of this rectangle overlies the equivalent
+ * edge of the passed rectangle
+ */
+ public boolean edgeOverlaps(Rectangle r) {
+ for (int i = 0; i < DIMENSIONS; i++) {
+ if (min[i] == r.min[i] || max[i] == r.max[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine whether this rectangle intersects the passed rectangle
+ *
+ * @param r The rectangle that might intersect this rectangle
+ *
+ * @return true if the rectangles intersect, false if they do not intersect
+ */
+ public boolean intersects(Rectangle r) {
+ // Every dimension must intersect. If any dimension
+ // does not intersect, return false immediately.
+ for (int i = 0; i < DIMENSIONS; i++) {
+ if (max[i] < r.min[i] || min[i] > r.max[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Determine whether this rectangle contains the passed rectangle
+ *
+ * @param r The rectangle that might be contained by this rectangle
+ *
+ * @return true if this rectangle contains the passed rectangle, false if
+ * it does not
+ */
+ public boolean contains(Rectangle r) {
+ for (int i = 0; i < DIMENSIONS; i++) {
+ if (max[i] < r.max[i] || min[i] > r.min[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Determine whether this rectangle is contained by the passed rectangle
+ *
+ * @param r The rectangle that might contain this rectangle
+ *
+ * @return true if the passed rectangle contains this rectangle, false if
+ * it does not
+ */
+ public boolean containedBy(Rectangle r) {
+ for (int i = 0; i < DIMENSIONS; i++) {
+ if (max[i] > r.max[i] || min[i] < r.min[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Return the distance between this rectangle and the passed point.
+ * If the rectangle contains the point, the distance is zero.
+ *
+ * @param p Point to find the distance to
+ *
+ * @return distance beween this rectangle and the passed point.
+ */
+ public float distance(Point p) {
+ float distanceSquared = 0;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ float greatestMin = Math.max(min[i], p.coordinates[i]);
+ float leastMax = Math.min(max[i], p.coordinates[i]);
+ if (greatestMin > leastMax) {
+ distanceSquared += ((greatestMin - leastMax) * (greatestMin - leastMax));
+ }
+ }
+ return (float) Math.sqrt(distanceSquared);
+ }
+
+ /**
+ * Return the distance between this rectangle and the passed rectangle.
+ * If the rectangles overlap, the distance is zero.
+ *
+ * @param r Rectangle to find the distance to
+ *
+ * @return distance between this rectangle and the passed rectangle
+ */
+
+ public float distance(Rectangle r) {
+ float distanceSquared = 0;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ float greatestMin = Math.max(min[i], r.min[i]);
+ float leastMax = Math.min(max[i], r.max[i]);
+ if (greatestMin > leastMax) {
+ distanceSquared += ((greatestMin - leastMax) * (greatestMin - leastMax));
+ }
+ }
+ return (float) Math.sqrt(distanceSquared);
+ }
+
+ /**
+ * Return the squared distance from this rectangle to the passed point
+ */
+ private float distanceSquared(int dimension, float point) {
+ float distanceSquared = 0;
+ float tempDistance = point - max[dimension];
+ for (int i = 0; i < 2; i++) {
+ if (tempDistance > 0) {
+ distanceSquared = (tempDistance * tempDistance);
+ break;
+ }
+ tempDistance = min[dimension] - point;
+ }
+ return distanceSquared;
+ }
+
+ /**
+ * Return the furthst possible distance between this rectangle and
+ * the passed rectangle.
+ *
+ * Find the distance between this rectangle and each corner of the
+ * passed rectangle, and use the maximum.
+ *
+ */
+ public float furthestDistance(Rectangle r) {
+ float distanceSquared = 0;
+
+ for (int i = 0; i < DIMENSIONS; i++) {
+ distanceSquared += Math.max(distanceSquared(i, r.min[i]), distanceSquared(i, r.max[i]));
+ }
+
+ return (float) Math.sqrt(distanceSquared);
+ }
+
+ /**
+ * Calculate the area by which this rectangle would be enlarged if
+ * added to the passed rectangle. Neither rectangle is altered.
+ *
+ * @param r Rectangle to union with this rectangle, in order to
+ * compute the difference in area of the union and the
+ * original rectangle
+ */
+ public float enlargement(Rectangle r) {
+ float enlargedArea = (Math.max(max[0], r.max[0]) - Math.min(min[0], r.min[0])) *
+ (Math.max(max[1], r.max[1]) - Math.min(min[1], r.min[1]));
+
+ return enlargedArea - area();
+ }
+
+ /**
+ * Compute the area of this rectangle.
+ *
+ * @return The area of this rectangle
+ */
+ public float area() {
+ return (max[0] - min[0]) * (max[1] - min[1]);
+ }
+
+ /**
+ * Computes the union of this rectangle and the passed rectangle, storing
+ * the result in this rectangle.
+ *
+ * @param r Rectangle to add to this rectangle
+ */
+ public void add(Rectangle r) {
+ for (int i = 0; i < DIMENSIONS; i++) {
+ if (r.min[i] < min[i]) {
+ min[i] = r.min[i];
+ }
+ if (r.max[i] > max[i]) {
+ max[i] = r.max[i];
+ }
+ }
+ }
+
+ /**
+ * Find the the union of this rectangle and the passed rectangle.
+ * Neither rectangle is altered
+ *
+ * @param r The rectangle to union with this rectangle
+ */
+ public Rectangle union(Rectangle r) {
+ Rectangle union = this.copy();
+ union.add(r);
+ return union;
+ }
+
+ /**
+ * Determine whether this rectangle is equal to a given object.
+ * Equality is determined by the bounds of the rectangle.
+ *
+ * @param The object to compare with this rectangle
+ */
+ public boolean equals(Object o) {
+ boolean equals = false;
+ if (o instanceof Rectangle) {
+ Rectangle r = (Rectangle) o;
+ if (Arrays.equals(r.min, min) && Arrays.equals(r.max, max)) {
+ equals = true;
+ }
+ }
+ return equals;
+ }
+
+ /**
+ * Determine whether this rectangle is the same as another object
+ *
+ * Note that two rectangles can be equal but not the same object,
+ * if they both have the same bounds.
+ *
+ * @param o The object to compare with this rectangle.
+ */
+ public boolean sameObject(Object o) {
+ return super.equals(o);
+ }
+
+ /**
+ * Return a string representation of this rectangle, in the form:
+ * (1.2, 3.4), (5.6, 7.8)
+ *
+ * @return String String representation of this rectangle.
+ */
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ // min coordinates
+ sb.append('(');
+ for (int i = 0; i < DIMENSIONS; i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ sb.append(min[i]);
+ }
+ sb.append("), (");
+
+ // max coordinates
+ for (int i = 0; i < DIMENSIONS; i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ sb.append(max[i]);
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+}