001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/csct/resources/XRectangle2D.java $
002 /*---------------- FILE HEADER ------------------------------------------
003
004 This file is part of deegree.
005 Copyright (C) 2001 by:
006 EXSE, Department of Geography, University of Bonn
007 http://www.giub.uni-bonn.de/exse/
008 lat/lon GmbH
009 http://www.lat-lon.de
010
011 It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification
012 (C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/)
013 SEAGIS Contacts: Surveillance de l'Environnement Assist�e par Satellite
014 Institut de Recherche pour le D�veloppement / US-Espace
015 mailto:seasnet@teledetection.fr
016
017
018 This library is free software; you can redistribute it and/or
019 modify it under the terms of the GNU Lesser General Public
020 License as published by the Free Software Foundation; either
021 version 2.1 of the License, or (at your option) any later version.
022
023 This library is distributed in the hope that it will be useful,
024 but WITHOUT ANY WARRANTY; without even the implied warranty of
025 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
026 Lesser General Public License for more details.
027
028 You should have received a copy of the GNU Lesser General Public
029 License along with this library; if not, write to the Free Software
030 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
031
032 Contact:
033
034 Andreas Poth
035 lat/lon GmbH
036 Aennchenstr. 19
037 53115 Bonn
038 Germany
039 E-Mail: poth@lat-lon.de
040
041 Klaus Greve
042 Department of Geography
043 University of Bonn
044 Meckenheimer Allee 166
045 53115 Bonn
046 Germany
047 E-Mail: klaus.greve@uni-bonn.de
048
049
050 ---------------------------------------------------------------------------*/
051 package org.deegree.model.csct.resources;
052
053 // Divers
054 import java.awt.geom.Rectangle2D;
055 import java.io.Serializable;
056 import java.text.FieldPosition;
057 import java.text.NumberFormat;
058
059 /**
060 * Serializable, high-performance double-precision rectangle. Instead of using <code>x</code>,
061 * <code>y</code>, <code>width</code> and <code>height</code>, this class store rectangle's
062 * coordinates into the following fields: {@link #xmin}, {@link #xmax}, {@link #ymin} et
063 * {@link #ymax}. Methods likes <code>contains</code> and <code>intersects</code> are faster,
064 * which make this class more appropriate for using intensively inside a loop.
065 *
066 * @version 1.0
067 * @author Martin Desruisseaux
068 */
069 public class XRectangle2D extends Rectangle2D implements Serializable {
070 /** Coordonn�es <var>x</var> minimale du rectangle. */
071 public double xmin;
072
073 /** Coordonn�es <var>y</var> minimale du rectangle. */
074 public double ymin;
075
076 /** Coordonn�es <var>x</var> maximale du rectangle. */
077 public double xmax;
078
079 /** Coordonn�es <var>y</var> maximale du rectangle. */
080 public double ymax;
081
082 /**
083 * Construit un rectangle par d�faut. Les coordonn�es du rectangle seront <code>(0,0,0,0)</code>.
084 */
085 public XRectangle2D() {
086 }
087
088 /**
089 * Construit un rectangle avec les coordonn�es sp�cifi�es.
090 */
091 public XRectangle2D( final double x, final double y, final double width, final double height ) {
092 this.xmin = x;
093 this.ymin = y;
094 this.xmax = x + width;
095 this.ymax = y + height;
096 }
097
098 /**
099 * Construit un rectangle avec une copie des coordonn�es du rectangle sp�cifi�e.
100 */
101 public XRectangle2D( final Rectangle2D rect ) {
102 setRect( rect );
103 }
104
105 /**
106 * Determines whether the <code>RectangularShape</code> is empty. When the
107 * <code>RectangularShape</code> is empty, it encloses no area.
108 *
109 * @return <code>true</code> if the <code>RectangularShape</code> is empty;
110 * <code>false</code> otherwise.
111 */
112 public boolean isEmpty() {
113 return !( xmin < xmax && ymin < ymax );
114 }
115
116 /**
117 * Returns the X coordinate of the upper left corner of the framing rectangle in
118 * <code>double</code> precision.
119 *
120 * @return the x coordinate of the upper left corner of the framing rectangle.
121 */
122 public double getX() {
123 return xmin;
124 }
125
126 /**
127 * Returns the Y coordinate of the upper left corner of the framing rectangle in
128 * <code>double</code> precision.
129 *
130 * @return the y coordinate of the upper left corner of the framing rectangle.
131 */
132 public double getY() {
133 return ymin;
134 }
135
136 /**
137 * Returns the width of the framing rectangle in <code>double</code> precision.
138 *
139 * @return the width of the framing rectangle.
140 */
141 public double getWidth() {
142 return xmax - xmin;
143 }
144
145 /**
146 * Returns the height of the framing rectangle in <code>double</code> precision.
147 *
148 * @return the height of the framing rectangle.
149 */
150 public double getHeight() {
151 return ymax - ymin;
152 }
153
154 /**
155 * Returns the smallest X coordinate of the rectangle.
156 */
157 public double getMinX() {
158 return xmin;
159 }
160
161 /**
162 * Returns the smallest Y coordinate of the rectangle.
163 */
164 public double getMinY() {
165 return ymin;
166 }
167
168 /**
169 * Returns the largest X coordinate of the rectangle.
170 */
171 public double getMaxX() {
172 return xmax;
173 }
174
175 /**
176 * Returns the largest Y coordinate of the rectangle.
177 */
178 public double getMaxY() {
179 return ymax;
180 }
181
182 /**
183 * Returns the X coordinate of the center of the rectangle.
184 */
185 public double getCenterX() {
186 return ( xmin + xmax ) / 2;
187 }
188
189 /**
190 * Returns the Y coordinate of the center of the rectangle.
191 */
192 public double getCenterY() {
193 return ( ymin + ymax ) / 2;
194 }
195
196 /**
197 * Sets the location and size of this <code>Rectangle2D</code> to the specified double values.
198 *
199 * @param x
200 * the x-coordinates to which to set the location of the upper left corner of this
201 * <code>Rectangle2D</code>
202 * @param y
203 * the y-coordinates to which to set the location of the upper left corner of this
204 * <code>Rectangle2D</code>
205 * @param width
206 * the value to use to set the width of this <code>Rectangle2D</code>
207 * @param height
208 * the value to use to set the height of this <code>Rectangle2D</code>
209 */
210 public void setRect( final double x, final double y, final double width, final double height ) {
211 this.xmin = x;
212 this.ymin = y;
213 this.xmax = x + width;
214 this.ymax = y + height;
215 }
216
217 /**
218 * Sets this <code>Rectangle2D</code> to be the same as the specified <code>Rectangle2D</code>.
219 *
220 * @param r
221 * the specified <code>Rectangle2D</code>
222 */
223 public void setRect( final Rectangle2D r ) {
224 this.xmin = r.getMinX();
225 this.ymin = r.getMinY();
226 this.xmax = r.getMaxX();
227 this.ymax = r.getMaxY();
228 }
229
230 /**
231 * Tests if a specified coordinate is inside the boundary of this <code>Rectangle2D</code>.
232 *
233 * @param x
234 * the x-coordinates to test.
235 * @param y
236 * the y-coordinates to test.
237 * @return <code>true</code> if the specified coordinates are inside the boundary of this
238 * <code>Rectangle2D</code>; <code>false</code> otherwise.
239 */
240 public boolean contains( final double x, final double y ) {
241 return ( x >= xmin && y >= ymin && x < xmax && y < ymax );
242 }
243
244 /**
245 * Tests if the interior of this <code>Rectangle2D</code> intersects the interior of a
246 * specified set of rectangular coordinates.
247 *
248 * @param x
249 * the x-coordinates of the upper left corner of the specified set of rectangular
250 * coordinates
251 * @param y
252 * the y-coordinates of the upper left corner of the specified set of rectangular
253 * coordinates
254 * @param width
255 * the width of the specified set of rectangular coordinates
256 * @param height
257 * the height of the specified set of rectangular coordinates
258 * @return <code>true</code> if this <code>Rectangle2D</code> intersects the interior of a
259 * specified set of rectangular coordinates; <code>false</code> otherwise.
260 */
261 public boolean intersects( final double x, final double y, final double width, final double height ) {
262 if ( !( xmin < xmax && ymin < ymax && width > 0 && height > 0 ) )
263 return false;
264 return ( x < xmax && y < ymax && x + width > xmin && y + height > ymin );
265 }
266
267 /**
268 * Tests if the interior of this <code>Rectangle2D</code> entirely contains the specified set
269 * of rectangular coordinates.
270 *
271 * @param x
272 * the x-coordinates of the upper left corner of the specified set of rectangular
273 * coordinates
274 * @param y
275 * the y-coordinates of the upper left corner of the specified set of rectangular
276 * coordinates
277 * @param width
278 * the width of the specified set of rectangular coordinates
279 * @param height
280 * the height of the specified set of rectangular coordinates
281 * @return <code>true</code> if this <code>Rectangle2D</code> entirely contains specified
282 * set of rectangular coordinates; <code>false</code> otherwise.
283 */
284 public boolean contains( final double x, final double y, final double width, final double height ) {
285 if ( !( xmin < xmax && ymin < ymax && width > 0 && height > 0 ) )
286 return false;
287 return ( x >= xmin && y >= ymin && ( x + width ) <= xmax && ( y + height ) <= ymax );
288 }
289
290 /**
291 * Determines where the specified coordinates lie with respect to this <code>Rectangle2D</code>.
292 * This method computes a binary OR of the appropriate mask values indicating, for each side of
293 * this <code>Rectangle2D</code>, whether or not the specified coordinates are on the same
294 * side of the edge as the rest of this <code>Rectangle2D</code>.
295 *
296 * @param x
297 * the specified x-coordinates
298 * @param y
299 * the specified y-coordinates
300 * @return the logical OR of all appropriate out codes.
301 *
302 * @see #OUT_LEFT
303 * @see #OUT_TOP
304 * @see #OUT_RIGHT
305 * @see #OUT_BOTTOM
306 */
307 public int outcode( final double x, final double y ) {
308 int out = 0;
309 if ( !( xmax > xmin ) )
310 out |= OUT_LEFT | OUT_RIGHT;
311 else if ( x < xmin )
312 out |= OUT_LEFT;
313 else if ( x > xmax )
314 out |= OUT_RIGHT;
315
316 if ( !( ymax > ymin ) )
317 out |= OUT_TOP | OUT_BOTTOM;
318 else if ( y < ymin )
319 out |= OUT_TOP;
320 else if ( y > ymax )
321 out |= OUT_BOTTOM;
322 return out;
323 }
324
325 /**
326 * Returns a new <code>Rectangle2D</code> object representing the intersection of this
327 * <code>Rectangle2D</code> with the specified <code>Rectangle2D</code>.
328 *
329 * @param rect
330 * the <code>Rectangle2D</code> to be intersected with this
331 * <code>Rectangle2D</code>
332 * @return the largest <code>Rectangle2D</code> contained in both the specified
333 * <code>Rectangle2D</code> and in this <code>Rectangle2D</code>.
334 */
335 public Rectangle2D createIntersection( final Rectangle2D rect ) {
336 final XRectangle2D r = new XRectangle2D();
337 r.xmin = Math.max( xmin, rect.getMinX() );
338 r.ymin = Math.max( ymin, rect.getMinY() );
339 r.xmax = Math.min( xmax, rect.getMaxX() );
340 r.ymax = Math.min( ymax, rect.getMaxY() );
341 return r;
342 }
343
344 /**
345 * Returns a new <code>Rectangle2D</code> object representing the union of this
346 * <code>Rectangle2D</code> with the specified <code>Rectangle2D</code>.
347 *
348 * @param rect
349 * the <code>Rectangle2D</code> to be combined with this <code>Rectangle2D</code>
350 * @return the smallest <code>Rectangle2D</code> containing both the specified
351 * <code>Rectangle2D</code> and this <code>Rectangle2D</code>.
352 */
353 public Rectangle2D createUnion( final Rectangle2D rect ) {
354 final XRectangle2D r = new XRectangle2D();
355 r.xmin = Math.min( xmin, rect.getMinX() );
356 r.ymin = Math.min( ymin, rect.getMinY() );
357 r.xmax = Math.max( xmax, rect.getMaxX() );
358 r.ymax = Math.max( ymax, rect.getMaxY() );
359 return r;
360 }
361
362 /**
363 * Adds a point, specified by the double precision arguments <code>x</code> and <code>y</code>,
364 * to this <code>Rectangle2D</code>. The resulting <code>Rectangle2D</code> is the smallest
365 * <code>Rectangle2D</code> that contains both the original <code>Rectangle2D</code> and the
366 * specified point.
367 * <p>
368 * After adding a point, a call to <code>contains</code> with the added point as an argument
369 * does not necessarily return <code>true</code>. The <code>contains</code> method does not
370 * return <code>true</code> for points on the right or bottom edges of a rectangle. Therefore,
371 * if the added point falls on the left or bottom edge of the enlarged rectangle,
372 * <code>contains</code> returns <code>false</code> for that point.
373 *
374 */
375 public void add( final double x, final double y ) {
376 if ( x < xmin )
377 xmin = x;
378 if ( x > xmax )
379 xmax = x;
380 if ( y < ymin )
381 ymin = y;
382 if ( y > ymax )
383 ymax = y;
384 }
385
386 /**
387 * Adds a <code>Rectangle2D</code> object to this <code>Rectangle2D</code>. The resulting
388 * <code>Rectangle2D</code> is the union of the two <code>Rectangle2D</code> objects.
389 *
390 * @param rect
391 * the <code>Rectangle2D</code> to add to this <code>Rectangle2D</code>.
392 */
393 public void add( final Rectangle2D rect ) {
394 double t;
395 if ( ( t = rect.getMinX() ) < xmin )
396 xmin = t;
397 if ( ( t = rect.getMaxX() ) > xmax )
398 xmax = t;
399 if ( ( t = rect.getMinY() ) < ymin )
400 ymin = t;
401 if ( ( t = rect.getMaxY() ) > ymax )
402 ymax = t;
403 }
404
405 /**
406 * Returns the <code>String</code> representation of this <code>Rectangle2D</code>.
407 *
408 * @return a <code>String</code> representing this <code>Rectangle2D</code>.
409 */
410 public String toString() {
411 final StringBuffer buffer = new StringBuffer( Utilities.getShortClassName( this ) );
412 final NumberFormat format = NumberFormat.getNumberInstance();
413 final FieldPosition dummy = new FieldPosition( 0 );
414 buffer.append( "[xmin=" );
415 format.format( xmin, buffer, dummy );
416 buffer.append( " xmax=" );
417 format.format( xmax, buffer, dummy );
418 buffer.append( " ymin=" );
419 format.format( ymin, buffer, dummy );
420 buffer.append( " ymax=" );
421 format.format( ymax, buffer, dummy );
422 buffer.append( ']' );
423 return buffer.toString();
424 }
425 }