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 }