]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scenegraph/src/com/infomatiq/jsi/Rectangle.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / com / infomatiq / jsi / Rectangle.java
1 //   Rectangle.java
2 //   Java Spatial Index Library
3 //   Copyright (C) 2002-2005 Infomatiq Limited
4 //  
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.
9 //  
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.
14 //  
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
18
19 package com.infomatiq.jsi;
20
21
22
23 /**
24  * Currently hardcoded to 2 dimensions, but could be extended.
25  * 
26  * @author  aled@sourceforge.net
27  * @version 1.0b8
28  */
29 public class Rectangle {
30   
31   /**
32    * use primitives instead of arrays for the coordinates of the rectangle,
33    * to reduce memory requirements.
34    */
35   public float minX, minY, maxX, maxY;
36   
37   public Rectangle() {
38     minX = Float.MAX_VALUE;
39     minY = Float.MAX_VALUE;
40     maxX = -Float.MAX_VALUE;
41     maxY = -Float.MAX_VALUE;
42   }
43   
44   /**
45    * Constructor.
46    * 
47    * @param x1 coordinate of any corner of the rectangle
48    * @param y1 (see x1)
49    * @param x2 coordinate of the opposite corner
50    * @param y2 (see x2)
51    */
52   public Rectangle(float x1, float y1, float x2, float y2) {
53     set(x1, y1, x2, y2);
54   }
55
56  /**
57    * Sets the size of the rectangle.
58    * 
59    * @param x1 coordinate of any corner of the rectangle
60    * @param y1 (see x1)
61    * @param x2 coordinate of the opposite corner
62    * @param y2 (see x2)
63    */
64   public void set(float x1, float y1, float x2, float y2) {
65     minX = Math.min(x1, x2);
66     maxX = Math.max(x1, x2);
67     minY = Math.min(y1, y2);
68     maxY = Math.max(y1, y2);
69   }
70   
71   /**
72    * Sets the size of this rectangle to equal the passed rectangle.
73    */
74   public void set(Rectangle r) {
75     minX = r.minX;
76     minY = r.minY;
77     maxX = r.maxX;
78     maxY = r.maxY;  
79   }
80    
81   /**
82    * Make a copy of this rectangle
83    * 
84    * @return copy of this rectangle
85    */
86   public Rectangle copy() {
87     return new Rectangle(minX, minY, maxX, maxY); 
88   }
89   
90   /**
91    * Determine whether an edge of this rectangle overlies the equivalent 
92    * edge of the passed rectangle
93    */
94   public boolean edgeOverlaps(Rectangle r) {
95     return minX == r.minX || maxX == r.maxX || minY == r.minY || maxY == r.maxY;
96   }
97   
98   /**
99    * Determine whether this rectangle intersects the passed rectangle
100    * 
101    * @param r The rectangle that might intersect this rectangle
102    * 
103    * @return true if the rectangles intersect, false if they do not intersect
104    */
105   public boolean intersects(Rectangle r) {
106     return maxX >= r.minX && minX <= r.maxX && maxY >= r.minY && minY <= r.maxY;
107   }
108  
109   /**
110    * Determine whether or not two rectangles intersect
111    * 
112    * @param r1MinX minimum X coordinate of rectangle 1
113    * @param r1MinY minimum Y coordinate of rectangle 1
114    * @param r1MaxX maximum X coordinate of rectangle 1
115    * @param r1MaxY maximum Y coordinate of rectangle 1
116    * @param r2MinX minimum X coordinate of rectangle 2
117    * @param r2MinY minimum Y coordinate of rectangle 2
118    * @param r2MaxX maximum X coordinate of rectangle 2
119    * @param r2MaxY maximum Y coordinate of rectangle 2
120    * 
121    * @return true if r1 intersects r2, false otherwise.
122    */
123   static public boolean intersects(float r1MinX, float r1MinY, float r1MaxX, float r1MaxY,
124                                  float r2MinX, float r2MinY, float r2MaxX, float r2MaxY) { 
125     return r1MaxX >= r2MinX && r1MinX <= r2MaxX && r1MaxY >= r2MinY && r1MinY <= r2MaxY;                           
126   }
127   
128   /**
129    * Determine whether this rectangle contains the passed rectangle
130    * 
131    * @param r The rectangle that might be contained by this rectangle
132    * 
133    * @return true if this rectangle contains the passed rectangle, false if
134    *         it does not
135    */
136   public boolean contains(Rectangle r) {
137     return maxX >= r.maxX && minX <= r.minX && maxY >= r.maxY && minY <= r.minY;   
138   }
139   
140   /**
141    * Determine whether or not one rectangle contains another.
142    * 
143    * @param r1MinX minimum X coordinate of rectangle 1
144    * @param r1MinY minimum Y coordinate of rectangle 1
145    * @param r1MaxX maximum X coordinate of rectangle 1
146    * @param r1MaxY maximum Y coordinate of rectangle 1
147    * @param r2MinX minimum X coordinate of rectangle 2
148    * @param r2MinY minimum Y coordinate of rectangle 2
149    * @param r2MaxX maximum X coordinate of rectangle 2
150    * @param r2MaxY maximum Y coordinate of rectangle 2
151    * 
152    * @return true if r1 contains r2, false otherwise.
153    */
154   static public boolean contains(float r1MinX, float r1MinY, float r1MaxX, float r1MaxY,
155                                  float r2MinX, float r2MinY, float r2MaxX, float r2MaxY) {
156     return r1MaxX >= r2MaxX && r1MinX <= r2MinX && r1MaxY >= r2MaxY && r1MinY <= r2MinY;                              
157   }
158  
159   /**
160    * Determine whether this rectangle is contained by the passed rectangle
161    * 
162    * @param r The rectangle that might contain this rectangle
163    * 
164    * @return true if the passed rectangle contains this rectangle, false if
165    *         it does not
166    */
167   public boolean containedBy(Rectangle r) {
168     return r.maxX >= maxX && r.minX <= minX && r.maxY >= maxY && r.minY <= minY;   
169   }
170   
171   /**
172    * Return the distance between this rectangle and the passed point.
173    * If the rectangle contains the point, the distance is zero.
174    * 
175    * @param p Point to find the distance to
176    * 
177    * @return distance beween this rectangle and the passed point.
178    */
179   public float distance(Point p) {
180     float distanceSquared = 0;
181     
182     float temp = minX - p.x;
183     if (temp < 0) {
184       temp = p.x - maxX;
185     }
186     
187     if (temp > 0) {
188       distanceSquared += (temp * temp);
189     }
190
191     temp = minY - p.y;
192     if (temp < 0) {
193       temp = p.y - maxY;
194     }
195
196     if (temp > 0) {
197       distanceSquared += (temp * temp);
198     }
199          
200     return (float) Math.sqrt(distanceSquared);
201   }
202   
203   /**
204    * Return the distance between a rectangle and a point.
205    * If the rectangle contains the point, the distance is zero.
206    * 
207    * @param minX minimum X coordinate of rectangle
208    * @param minY minimum Y coordinate of rectangle
209    * @param maxX maximum X coordinate of rectangle
210    * @param maxY maximum Y coordinate of rectangle
211    * @param pX X coordinate of point
212    * @param pY Y coordinate of point
213    * 
214    * @return distance beween this rectangle and the passed point.
215    */
216   static public float distance(float minX, float minY, float maxX, float maxY, float pX, float pY) {
217     return (float) Math.sqrt(distanceSq(minX, minY, maxX, maxY, pX, pY));
218   }
219   
220   static public float distanceSq(float minX, float minY, float maxX, float maxY, float pX, float pY) {
221     float distanceSqX = 0;
222     float distanceSqY = 0;
223     
224     if (minX > pX) {
225       distanceSqX = minX - pX;
226       distanceSqX *= distanceSqX;
227     } else if (pX > maxX) {
228       distanceSqX = pX - maxX;
229       distanceSqX *= distanceSqX;
230     }
231    
232     if (minY > pY) {
233       distanceSqY = minY - pY;
234       distanceSqY *= distanceSqY;
235     } else if (pY > maxY) {
236       distanceSqY = pY - maxY;
237       distanceSqY *= distanceSqY;
238     }
239    
240     return distanceSqX + distanceSqY;
241   }
242   
243   /**
244    * Return the distance between this rectangle and the passed rectangle.
245    * If the rectangles overlap, the distance is zero.
246    * 
247    * @param r Rectangle to find the distance to
248    * 
249    * @return distance between this rectangle and the passed rectangle
250    */
251
252   public float distance(Rectangle r) {
253     float distanceSquared = 0;
254     float greatestMin = Math.max(minX, r.minX);
255     float leastMax    = Math.min(maxX, r.maxX);
256     if (greatestMin > leastMax) {
257       distanceSquared += ((greatestMin - leastMax) * (greatestMin - leastMax)); 
258     }
259     greatestMin = Math.max(minY, r.minY);
260     leastMax    = Math.min(maxY, r.maxY);
261     if (greatestMin > leastMax) {
262       distanceSquared += ((greatestMin - leastMax) * (greatestMin - leastMax)); 
263     }
264     return (float) Math.sqrt(distanceSquared);
265   }
266
267   /**
268    * Calculate the area by which this rectangle would be enlarged if
269    * added to the passed rectangle. Neither rectangle is altered.
270    * 
271    * @param r Rectangle to union with this rectangle, in order to 
272    *          compute the difference in area of the union and the
273    *          original rectangle
274    * 
275    * @return enlargement
276    */
277   public float enlargement(Rectangle r) {
278     float enlargedArea = (Math.max(maxX, r.maxX) - Math.min(minX, r.minX)) *
279                          (Math.max(maxY, r.maxY) - Math.min(minY, r.minY));
280                          
281     return enlargedArea - area();
282   }
283   
284   /**
285     * Calculate the area by which a rectangle would be enlarged if
286     * added to the passed rectangle..
287     * 
288     * @param r1MinX minimum X coordinate of rectangle 1
289     * @param r1MinY minimum Y coordinate of rectangle 1
290     * @param r1MaxX maximum X coordinate of rectangle 1
291     * @param r1MaxY maximum Y coordinate of rectangle 1
292     * @param r2MinX minimum X coordinate of rectangle 2
293     * @param r2MinY minimum Y coordinate of rectangle 2
294     * @param r2MaxX maximum X coordinate of rectangle 2
295     * @param r2MaxY maximum Y coordinate of rectangle 2
296     * 
297     * @return enlargement
298     */
299   static public float enlargement(float r1MinX, float r1MinY, float r1MaxX, float r1MaxY,
300                                   float r2MinX, float r2MinY, float r2MaxX, float r2MaxY) { 
301     float r1Area = (r1MaxX - r1MinX) * (r1MaxY - r1MinY);                    
302     
303     if (r1Area == Float.POSITIVE_INFINITY) {
304       return 0; // cannot enlarge an infinite rectangle...
305     }
306     
307     if (r2MinX < r1MinX) r1MinX = r2MinX;   
308     if (r2MinY < r1MinY) r1MinY = r2MinY;   
309     if (r2MaxX > r1MaxX) r1MaxX = r2MaxX;                               
310     if (r2MaxY > r1MaxY) r1MaxY = r2MaxY;
311     
312     float r1r2UnionArea = (r1MaxX - r1MinX) * (r1MaxY - r1MinY);
313           
314     if (r1r2UnionArea == Float.POSITIVE_INFINITY) {
315       // if a finite rectangle is enlarged and becomes infinite,
316       // then the enlargement must be infinite.
317       return Float.POSITIVE_INFINITY;
318     }
319     return r1r2UnionArea - r1Area;                              
320   }
321   
322   /**
323    * Compute the area of this rectangle.
324    * 
325    * @return The area of this rectangle
326    */
327   public float area() {
328     return (maxX - minX) * (maxY - minY);
329   }
330   
331   /**
332    * Compute the area of a rectangle.
333    * 
334    * @param minX the minimum X coordinate of the rectangle
335    * @param minY the minimum Y coordinate of the rectangle
336    * @param maxX the maximum X coordinate of the rectangle
337    * @param maxY the maximum Y coordinate of the rectangle
338    * 
339    * @return The area of the rectangle
340    */
341   static public float area(float minX, float minY, float maxX, float maxY) {
342     return (maxX - minX) * (maxY - minY);
343   }
344   
345   /**
346    * Computes the union of this rectangle and the passed rectangle, storing
347    * the result in this rectangle.
348    * 
349    * @param r Rectangle to add to this rectangle
350    */
351   public void add(Rectangle r) {
352     if (r.minX < minX) minX = r.minX;
353     if (r.maxX > maxX) maxX = r.maxX;
354     if (r.minY < minY) minY = r.minY;
355     if (r.maxY > maxY) maxY = r.maxY;
356   }
357   
358   /**
359    * Computes the union of this rectangle and the passed point, storing
360    * the result in this rectangle.
361    * 
362    * @param p Point to add to this rectangle
363    */
364   public void add(Point p) {
365     if (p.x < minX) minX = p.x;
366     if (p.x > maxX) maxX = p.x;
367     if (p.y < minY) minY = p.y;
368     if (p.y > maxY) maxY = p.y;
369   }
370   
371   /**
372    * Find the the union of this rectangle and the passed rectangle.
373    * Neither rectangle is altered
374    * 
375    * @param r The rectangle to union with this rectangle
376    */
377   public Rectangle union(Rectangle r) {
378     Rectangle union = this.copy();
379     union.add(r);
380     return union; 
381   }
382   
383   /**
384    * Determine whether this rectangle is equal to a given object.
385    * Equality is determined by the bounds of the rectangle.
386    * 
387    * @param o The object to compare with this rectangle
388    */
389   public boolean equals(Object o) {
390     boolean equals = false;
391     if (o instanceof Rectangle) {
392       Rectangle r = (Rectangle) o;
393       if (minX == r.minX && minY == r.minY && maxX == r.maxX && maxY == r.maxY) {
394         equals = true;
395       }
396     } 
397     return equals;       
398   }
399
400   /** 
401    * Determine whether this rectangle is the same as another object
402    * 
403    * Note that two rectangles can be equal but not the same object, 
404    * if they both have the same bounds.
405    * 
406    * @param o The object to compare with this rectangle.
407    */  
408   public boolean sameObject(Object o) {
409     return super.equals(o); 
410   }
411   
412   /**
413    * Return a string representation of this rectangle, in the form: 
414    * (1.2, 3.4), (5.6, 7.8)
415    * 
416    * @return String String representation of this rectangle.
417    */
418   public String toString() {
419     return "(" + minX + ", " + minY + "), (" + maxX + ", " + maxY + ")";
420   }
421   
422   /**
423    * Utility methods (not used by JSI); added to 
424    * enable this to be used as a generic rectangle class 
425    */
426   public float width() {
427     return maxX - minX;
428   }
429   
430   public float height() {
431     return maxY - minY;
432   }
433   
434   public float aspectRatio() {
435     return width() / height();
436   }
437   
438   public Point centre() {
439     return new Point((minX + maxX) / 2, (minY + maxY) / 2);
440   }
441   
442 }