/*---------------- FILE HEADER ------------------------------------------ This file is part of deegree. Copyright (C) 2001 by: EXSE, Department of Geography, University of Bonn http://www.giub.uni-bonn.de/exse/ lat/lon GmbH http://www.lat-lon.de It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification (C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/) SEAGIS Contacts: Surveillance de l'Environnement Assist�e par Satellite Institut de Recherche pour le D�veloppement / US-Espace mailto:seasnet@teledetection.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Andreas Poth lat/lon GmbH Aennchenstr. 19 53115 Bonn Germany E-Mail: poth@lat-lon.de Klaus Greve Department of Geography University of Bonn Meckenheimer Allee 166 53115 Bonn Germany E-Mail: klaus.greve@uni-bonn.de ---------------------------------------------------------------------------*/ package org.deegree.model.csct.resources; // Divers import java.awt.geom.Rectangle2D; import java.io.Serializable; import java.text.FieldPosition; import java.text.NumberFormat; /** * Serializable, high-performance double-precision rectangle. Instead of using * <code>x</code>, <code>y</code>, <code>width</code> and <code>height</code>, * this class store rectangle's coordinates into the following fields: * {@link #xmin}, {@link #xmax}, {@link #ymin} et {@link #ymax}. Methods likes * <code>contains</code> and <code>intersects</code> are faster, which make this * class more appropriate for using intensively inside a loop. * * @version 1.0 * @author Martin Desruisseaux */ public class XRectangle2D extends Rectangle2D implements Serializable { /** Coordonn�es <var>x</var> minimale du rectangle. */ public double xmin; /** Coordonn�es <var>y</var> minimale du rectangle. */ public double ymin; /** Coordonn�es <var>x</var> maximale du rectangle. */ public double xmax; /** Coordonn�es <var>y</var> maximale du rectangle. */ public double ymax; /** * Construit un rectangle par d�faut. Les coordonn�es * du rectangle seront <code>(0,0,0,0)</code>. */ public XRectangle2D() {} /** * Construit un rectangle avec les coordonn�es sp�cifi�es. */ public XRectangle2D(final double x, final double y, final double width, final double height) { this.xmin = x; this.ymin = y; this.xmax = x+width; this.ymax = y+height; } /** * Construit un rectangle avec une copie * des coordonn�es du rectangle sp�cifi�e. */ public XRectangle2D(final Rectangle2D rect) {setRect(rect);} /** * Determines whether the <code>RectangularShape</code> is empty. * When the <code>RectangularShape</code> is empty, it encloses no * area. * * @return <code>true</code> if the <code>RectangularShape</code> is empty; * <code>false</code> otherwise. */ public boolean isEmpty() {return !(xmin<xmax && ymin<ymax);} /** * Returns the X coordinate of the upper left corner of * the framing rectangle in <code>double</code> precision. * * @return the x coordinate of the upper left corner of the framing rectangle. */ public double getX() {return xmin;} /** * Returns the Y coordinate of the upper left corner of * the framing rectangle in <code>double</code> precision. * * @return the y coordinate of the upper left corner of the framing rectangle. */ public double getY() {return ymin;} /** * Returns the width of the framing rectangle in * <code>double</code> precision. * @return the width of the framing rectangle. */ public double getWidth() {return xmax-xmin;} /** * Returns the height of the framing rectangle in <code>double</code> precision. * * @return the height of the framing rectangle. */ public double getHeight() {return ymax-ymin;} /** * Returns the smallest X coordinate of the rectangle. */ public double getMinX() {return xmin;} /** * Returns the smallest Y coordinate of the rectangle. */ public double getMinY() {return ymin;} /** * Returns the largest X coordinate of the rectangle. */ public double getMaxX() {return xmax;} /** * Returns the largest Y coordinate of the rectangle. */ public double getMaxY() {return ymax;} /** * Returns the X coordinate of the center of the rectangle. */ public double getCenterX() {return (xmin+xmax)/2;} /** * Returns the Y coordinate of the center of the rectangle. */ public double getCenterY() {return (ymin+ymax)/2;} /** * Sets the location and size of this <code>Rectangle2D</code> * to the specified double values. * * @param x, y the coordinates to which to set the * location of the upper left corner of this <code>Rectangle2D</code> * @param width the value to use to set the width of this <code>Rectangle2D</code> * @param height the value to use to set the height of this <code>Rectangle2D</code> */ public void setRect(final double x, final double y, final double width, final double height) { this.xmin = x; this.ymin = y; this.xmax = x+width; this.ymax = y+height; } /** * Sets this <code>Rectangle2D</code> to be the same as the * specified <code>Rectangle2D</code>. * * @param r the specified <code>Rectangle2D</code> */ public void setRect(final Rectangle2D r) { this.xmin = r.getMinX(); this.ymin = r.getMinY(); this.xmax = r.getMaxX(); this.ymax = r.getMaxY(); } /** * Tests if a specified coordinate is inside the boundary of this * <code>Rectangle2D</code>. * * @param x, y the coordinates to test. * @return <code>true</code> if the specified coordinates are * inside the boundary of this <code>Rectangle2D</code>; * <code>false</code> otherwise. */ public boolean contains(final double x, final double y) {return (x>=xmin && y>=ymin && x<xmax && y<ymax);} /** * Tests if the interior of this <code>Rectangle2D</code> * intersects the interior of a specified set of rectangular * coordinates. * * @param x, y the coordinates of the upper left corner * of the specified set of rectangular coordinates * @param width the width of the specified set of rectangular coordinates * @param height the height of the specified set of rectangular coordinates * @return <code>true</code> if this <code>Rectangle2D</code> * intersects the interior of a specified set of rectangular * coordinates; <code>false</code> otherwise. */ public boolean intersects(final double x, final double y, final double width, final double height) { if (!(xmin<xmax && ymin<ymax && width>0 && height>0)) return false; return (x<xmax && y<ymax && x+width>xmin && y+height>ymin); } /** * Tests if the interior of this <code>Rectangle2D</code> entirely * contains the specified set of rectangular coordinates. * * @param x, y the coordinates of the upper left corner * of the specified set of rectangular coordinates * @param width the width of the specified set of rectangular coordinates * @param height the height of the specified set of rectangular coordinates * @return <code>true</code> if this <code>Rectangle2D</code> * entirely contains specified set of rectangular * coordinates; <code>false</code> otherwise. */ public boolean contains(final double x, final double y, final double width, final double height) { if (!(xmin<xmax && ymin<ymax && width>0 && height>0)) return false; return (x>=xmin && y>=ymin && (x+width)<=xmax && (y+height)<=ymax); } /** * Determines where the specified coordinates lie with respect * to this <code>Rectangle2D</code>. * This method computes a binary OR of the appropriate mask values * indicating, for each side of this <code>Rectangle2D</code>, * whether or not the specified coordinates are on the same side * of the edge as the rest of this <code>Rectangle2D</code>. * * @param x, y the specified coordinates * @return the logical OR of all appropriate out codes. * * @see #OUT_LEFT * @see #OUT_TOP * @see #OUT_RIGHT * @see #OUT_BOTTOM */ public int outcode(final double x, final double y) { int out=0; if (!(xmax > xmin)) out |= OUT_LEFT | OUT_RIGHT; else if (x < xmin) out |= OUT_LEFT; else if (x > xmax) out |= OUT_RIGHT; if (!(ymax > ymin)) out |= OUT_TOP | OUT_BOTTOM; else if (y < ymin) out |= OUT_TOP; else if (y > ymax) out |= OUT_BOTTOM; return out; } /** * Returns a new <code>Rectangle2D</code> object representing the * intersection of this <code>Rectangle2D</code> with the specified * <code>Rectangle2D</code>. * * @param rect the <code>Rectangle2D</code> to be intersected with this <code>Rectangle2D</code> * @return the largest <code>Rectangle2D</code> contained in both the specified * <code>Rectangle2D</code> and in this <code>Rectangle2D</code>. */ public Rectangle2D createIntersection(final Rectangle2D rect) { final XRectangle2D r=new XRectangle2D(); r.xmin = Math.max(xmin, rect.getMinX()); r.ymin = Math.max(ymin, rect.getMinY()); r.xmax = Math.min(xmax, rect.getMaxX()); r.ymax = Math.min(ymax, rect.getMaxY()); return r; } /** * Returns a new <code>Rectangle2D</code> object representing the * union of this <code>Rectangle2D</code> with the specified * <code>Rectangle2D</code>. * * @param rect the <code>Rectangle2D</code> to be combined with * this <code>Rectangle2D</code> * @return the smallest <code>Rectangle2D</code> containing both * the specified <code>Rectangle2D</code> and this * <code>Rectangle2D</code>. */ public Rectangle2D createUnion(final Rectangle2D rect) { final XRectangle2D r=new XRectangle2D(); r.xmin = Math.min(xmin, rect.getMinX()); r.ymin = Math.min(ymin, rect.getMinY()); r.xmax = Math.max(xmax, rect.getMaxX()); r.ymax = Math.max(ymax, rect.getMaxY()); return r; } /** * Adds a point, specified by the double precision arguments * <code>x</code> and <code>y</code>, to this <code>Rectangle2D</code>. * The resulting <code>Rectangle2D</code> is the smallest <code>Rectangle2D</code> * that contains both the original <code>Rectangle2D</code> and the specified point. * <p> * After adding a point, a call to <code>contains</code> with the * added point as an argument does not necessarily return * <code>true</code>. The <code>contains</code> method does not * return <code>true</code> for points on the right or bottom * edges of a rectangle. Therefore, if the added point falls on * the left or bottom edge of the enlarged rectangle, * <code>contains</code> returns <code>false</code> for that point. * */ public void add(final double x, final double y) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; if (y<ymin) ymin=y; if (y>ymax) ymax=y; } /** * Adds a <code>Rectangle2D</code> object to this <code>Rectangle2D</code>. * The resulting <code>Rectangle2D</code> is the union of the two * <code>Rectangle2D</code> objects. * * @param rect the <code>Rectangle2D</code> to add to this <code>Rectangle2D</code>. */ public void add(final Rectangle2D rect) { double t; if ((t=rect.getMinX()) < xmin) xmin=t; if ((t=rect.getMaxX()) > xmax) xmax=t; if ((t=rect.getMinY()) < ymin) ymin=t; if ((t=rect.getMaxY()) > ymax) ymax=t; } /** * Returns the <code>String</code> representation of this <code>Rectangle2D</code>. * * @return a <code>String</code> representing this <code>Rectangle2D</code>. */ public String toString() { final StringBuffer buffer = new StringBuffer(Utilities.getShortClassName(this)); final NumberFormat format = NumberFormat.getNumberInstance(); final FieldPosition dummy = new FieldPosition(0); buffer.append("[xmin="); format.format(xmin, buffer, dummy); buffer.append(" xmax="); format.format(xmax, buffer, dummy); buffer.append(" ymin="); format.format(ymin, buffer, dummy); buffer.append(" ymax="); format.format(ymax, buffer, dummy); buffer.append(']'); return buffer.toString(); } }