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    }