2 // Java Spatial Index Library
3 // Copyright (C) 2002 Infomatiq Limited
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 package com.infomatiq.jsi;
21 import java.util.Arrays;
24 * Currently hardcoded to 2 dimensions, but could be extended.
26 * @author aled.morris@infomatiq.co.uk
29 public class Rectangle {
31 * Number of dimensions in a rectangle. In theory this
32 * could be exended to three or more dimensions.
34 public final static int DIMENSIONS = 3;
37 * array containing the minimum value for each dimension; ie { min(x), min(y) }
42 * array containing the maximum value for each dimension; ie { max(x), max(y) }
49 * @param x1 coordinate of any corner of the rectangle
51 * @param x2 coordinate of the opposite corner
54 public Rectangle(float x1, float y1, float z1, float x2, float y2, float z2) {
55 min = new float[DIMENSIONS];
56 max = new float[DIMENSIONS];
57 set(x1, y1, z1, x2, y2, z2);
63 * @param min array containing the minimum value for each dimension; ie { min(x), min(y) }
64 * @param max array containing the maximum value for each dimension; ie { max(x), max(y) }
66 public Rectangle(float[] min, float[] max) {
67 if (min.length != DIMENSIONS || max.length != DIMENSIONS) {
68 throw new RuntimeException("Error in Rectangle constructor: " +
69 "min and max arrays must be of length " + DIMENSIONS);
72 this.min = new float[DIMENSIONS];
73 this.max = new float[DIMENSIONS];
79 * Sets the size of the rectangle.
81 * @param x1 coordinate of any corner of the rectangle
83 * @param x2 coordinate of the opposite corner
86 public void set(float x1, float y1, float z1, float x2, float y2, float z2) {
87 min[0] = Math.min(x1, x2);
88 min[1] = Math.min(y1, y2);
89 min[2] = Math.min(z1, z2);
90 max[0] = Math.max(x1, x2);
91 max[1] = Math.max(y1, y2);
92 max[2] = Math.max(z1, z2);
96 * Sets the size of the rectangle.
98 * @param min array containing the minimum value for each dimension; ie { min(x), min(y) }
99 * @param max array containing the maximum value for each dimension; ie { max(x), max(y) }
101 public void set(float[] min, float[] max) {
102 System.arraycopy(min, 0, this.min, 0, DIMENSIONS);
103 System.arraycopy(max, 0, this.max, 0, DIMENSIONS);
107 * Make a copy of this rectangle
109 * @return copy of this rectangle
111 public Rectangle copy() {
112 return new Rectangle(min, max);
116 * Determine whether an edge of this rectangle overlies the equivalent
117 * edge of the passed rectangle
119 public boolean edgeOverlaps(Rectangle r) {
120 for (int i = 0; i < DIMENSIONS; i++) {
121 if (min[i] == r.min[i] || max[i] == r.max[i]) {
129 * Determine whether this rectangle intersects the passed rectangle
131 * @param r The rectangle that might intersect this rectangle
133 * @return true if the rectangles intersect, false if they do not intersect
135 public boolean intersects(Rectangle r) {
136 // Every dimension must intersect. If any dimension
137 // does not intersect, return false immediately.
138 for (int i = 0; i < DIMENSIONS; i++) {
139 if (max[i] < r.min[i] || min[i] > r.max[i]) {
147 * Determine whether this rectangle contains the passed rectangle
149 * @param r The rectangle that might be contained by this rectangle
151 * @return true if this rectangle contains the passed rectangle, false if
154 public boolean contains(Rectangle r) {
155 for (int i = 0; i < DIMENSIONS; i++) {
156 if (max[i] < r.max[i] || min[i] > r.min[i]) {
164 * Determine whether this rectangle is contained by the passed rectangle
166 * @param r The rectangle that might contain this rectangle
168 * @return true if the passed rectangle contains this rectangle, false if
171 public boolean containedBy(Rectangle r) {
172 for (int i = 0; i < DIMENSIONS; i++) {
173 if (max[i] > r.max[i] || min[i] < r.min[i]) {
181 * Return the distance between this rectangle and the passed point.
182 * If the rectangle contains the point, the distance is zero.
184 * @param p Point to find the distance to
186 * @return distance beween this rectangle and the passed point.
188 public float distance(Point p) {
189 float distanceSquared = 0;
190 for (int i = 0; i < DIMENSIONS; i++) {
191 float greatestMin = Math.max(min[i], p.coordinates[i]);
192 float leastMax = Math.min(max[i], p.coordinates[i]);
193 if (greatestMin > leastMax) {
194 distanceSquared += ((greatestMin - leastMax) * (greatestMin - leastMax));
197 return (float) Math.sqrt(distanceSquared);
201 * Return the distance between this rectangle and the passed rectangle.
202 * If the rectangles overlap, the distance is zero.
204 * @param r Rectangle to find the distance to
206 * @return distance between this rectangle and the passed rectangle
209 public float distance(Rectangle r) {
210 float distanceSquared = 0;
211 for (int i = 0; i < DIMENSIONS; i++) {
212 float greatestMin = Math.max(min[i], r.min[i]);
213 float leastMax = Math.min(max[i], r.max[i]);
214 if (greatestMin > leastMax) {
215 distanceSquared += ((greatestMin - leastMax) * (greatestMin - leastMax));
218 return (float) Math.sqrt(distanceSquared);
222 * Return the squared distance from this rectangle to the passed point
224 private float distanceSquared(int dimension, float point) {
225 float distanceSquared = 0;
226 float tempDistance = point - max[dimension];
227 for (int i = 0; i < 2; i++) {
228 if (tempDistance > 0) {
229 distanceSquared = (tempDistance * tempDistance);
232 tempDistance = min[dimension] - point;
234 return distanceSquared;
238 * Return the furthst possible distance between this rectangle and
239 * the passed rectangle.
241 * Find the distance between this rectangle and each corner of the
242 * passed rectangle, and use the maximum.
245 public float furthestDistance(Rectangle r) {
246 float distanceSquared = 0;
248 for (int i = 0; i < DIMENSIONS; i++) {
249 distanceSquared += Math.max(distanceSquared(i, r.min[i]), distanceSquared(i, r.max[i]));
252 return (float) Math.sqrt(distanceSquared);
256 * Calculate the area by which this rectangle would be enlarged if
257 * added to the passed rectangle. Neither rectangle is altered.
259 * @param r Rectangle to union with this rectangle, in order to
260 * compute the difference in area of the union and the
263 public float enlargement(Rectangle r) {
264 float enlargedArea = (Math.max(max[0], r.max[0]) - Math.min(min[0], r.min[0])) *
265 (Math.max(max[1], r.max[1]) - Math.min(min[1], r.min[1]));
267 return enlargedArea - area();
271 * Compute the area of this rectangle.
273 * @return The area of this rectangle
275 public float area() {
276 return (max[0] - min[0]) * (max[1] - min[1]);
280 * Computes the union of this rectangle and the passed rectangle, storing
281 * the result in this rectangle.
283 * @param r Rectangle to add to this rectangle
285 public void add(Rectangle r) {
286 for (int i = 0; i < DIMENSIONS; i++) {
287 if (r.min[i] < min[i]) {
290 if (r.max[i] > max[i]) {
297 * Find the the union of this rectangle and the passed rectangle.
298 * Neither rectangle is altered
300 * @param r The rectangle to union with this rectangle
302 public Rectangle union(Rectangle r) {
303 Rectangle union = this.copy();
309 * Determine whether this rectangle is equal to a given object.
310 * Equality is determined by the bounds of the rectangle.
312 * @param The object to compare with this rectangle
314 public boolean equals(Object o) {
315 boolean equals = false;
316 if (o instanceof Rectangle) {
317 Rectangle r = (Rectangle) o;
318 if (Arrays.equals(r.min, min) && Arrays.equals(r.max, max)) {
326 * Determine whether this rectangle is the same as another object
328 * Note that two rectangles can be equal but not the same object,
329 * if they both have the same bounds.
331 * @param o The object to compare with this rectangle.
333 public boolean sameObject(Object o) {
334 return super.equals(o);
338 * Return a string representation of this rectangle, in the form:
339 * (1.2, 3.4), (5.6, 7.8)
341 * @return String String representation of this rectangle.
343 public String toString() {
344 StringBuffer sb = new StringBuffer();
348 for (int i = 0; i < DIMENSIONS; i++) {
357 for (int i = 0; i < DIMENSIONS; i++) {
364 return sb.toString();