All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geotoolkit.geometry.Envelope2D Maven / Gradle / Ivy

Go to download

Implementations of Coordinate Reference Systems (CRS), conversion and transformation services derived from ISO 19111.

There is a newer version: 3.20-geoapi-3.0
Show newest version
/*
 *    Geotoolkit.org - An Open Source Java GIS Toolkit
 *    http://www.geotoolkit.org
 *
 *    (C) 2004-2011, Open Source Geospatial Foundation (OSGeo)
 *    (C) 2009-2011, Geomatys
 *
 *    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;
 *    version 2.1 of the License.
 *
 *    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.
 */
package org.geotoolkit.geometry;

import java.awt.geom.Rectangle2D;

import org.opengis.geometry.Envelope;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.metadata.extent.GeographicBoundingBox;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.cs.AxisDirection;

import org.geotoolkit.util.Cloneable;
import org.geotoolkit.util.Utilities;
import org.geotoolkit.resources.Errors;
import org.geotoolkit.referencing.crs.DefaultGeographicCRS;

import static org.geotoolkit.util.ArgumentChecks.ensureNonNull;


/**
 * A two-dimensional envelope on top of {@link Rectangle2D}. This implementation is provided for
 * inter-operability between Java2D and GeoAPI.
 * 

* This class inherits {@linkplain #x x} and {@linkplain #y y} fields. But despite their names, * they don't need to be oriented toward {@linkplain AxisDirection#EAST East} and * {@linkplain AxisDirection#NORTH North} respectively. The (x,y) axis can * have any orientation and should be understood as "ordinate 0" and "ordinate 1" values instead. * This is not specific to this implementation; in Java2D too, the visual axis orientation depend * on the {@linkplain java.awt.Graphics2D#getTransform affine transform in the graphics context}. * * @author Martin Desruisseaux (IRD, Geomatys) * @version 3.11 * * @see GeneralEnvelope * @see org.geotoolkit.geometry.jts.ReferencedEnvelope * @see org.opengis.metadata.extent.GeographicBoundingBox * * @since 2.1 * @module */ public class Envelope2D extends Rectangle2D.Double implements Envelope, Cloneable { /** * Serial number for inter-operability with different versions. */ private static final long serialVersionUID = -3319231220761419350L; /** * The coordinate reference system, or {@code null}. */ private CoordinateReferenceSystem crs; /** * Constructs an initially empty envelope with no CRS. * * @since 2.5 */ public Envelope2D() { } /** * Constructs two-dimensional envelope defined by an other {@link Envelope}. * * @param envelope The envelope to copy. * @throws MismatchedDimensionException If the given envelope is not two-dimensional. */ public Envelope2D(final Envelope envelope) throws MismatchedDimensionException { super(envelope.getMinimum(0), envelope.getMinimum(1), envelope.getSpan(0), envelope.getSpan(1)); // TODO: check below should be first, if only Sun could fix RFE #4093999. final int dimension = envelope.getDimension(); if (dimension != 2) { throw new MismatchedDimensionException(Errors.format( Errors.Keys.NOT_TWO_DIMENSIONAL_$1, dimension)); } setCoordinateReferenceSystem(envelope.getCoordinateReferenceSystem()); } /** * Constructs a new envelope with the same data than the specified * geographic bounding box. The coordinate reference system is set * to {@linkplain DefaultGeographicCRS#WGS84 WGS84}. * * @param box The bounding box to copy. * * @since 3.11 */ public Envelope2D(final GeographicBoundingBox box) { ensureNonNull("box", box); crs = DefaultGeographicCRS.WGS84; x = box.getWestBoundLongitude(); y = box.getSouthBoundLatitude(); width = box.getEastBoundLongitude() - x; height = box.getNorthBoundLatitude() - y; } /** * Constructs two-dimensional envelope defined by an other {@link Rectangle2D}. * * @param crs The coordinate reference system, or {@code null}. * @param rect The rectangle to copy. */ public Envelope2D(final CoordinateReferenceSystem crs, final Rectangle2D rect) { super(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); setCoordinateReferenceSystem(crs); } /** * Constructs two-dimensional envelope defined by the specified coordinates. Despite * their name, the (x,y) coordinates don't need to be oriented * toward ({@linkplain AxisDirection#EAST East}, {@linkplain AxisDirection#NORTH North}). * Those parameter names simply match the {@linkplain #x x} and {@linkplain #y y} fields. * The actual axis orientations are determined by the specified CRS. * See the class javadoc for details. * * @param crs The coordinate reference system, or {@code null}. * @param x The x minimal value. * @param y The y minimal value. * @param width The envelope width. * @param height The envelope height. */ public Envelope2D(final CoordinateReferenceSystem crs, final double x, final double y, final double width, final double height) { super(x, y, width, height); setCoordinateReferenceSystem(crs); } /** * Constructs two-dimensional envelope defined by the specified coordinates. Despite * their name, the (x,y) coordinates don't need to be oriented * toward ({@linkplain AxisDirection#EAST East}, {@linkplain AxisDirection#NORTH North}). * Those parameter names simply match the {@linkplain #x x} and {@linkplain #y y} fields. * The actual axis orientations are determined by the specified CRS. * See the class javadoc for details. *

* The {@code minDP} and {@code maxDP} arguments usually contains the minimal and maximal * ordinate values respectively, but this is not mandatory. The ordinates will be rearanged * as needed. * * @param minDP The fist position. * @param maxDP The second position. * @throws MismatchedReferenceSystemException if the two positions don't use the same CRS. * * @since 2.4 */ public Envelope2D(final DirectPosition2D minDP, final DirectPosition2D maxDP) { // Uncomment next lines if Sun fixes RFE #4093999 // ensureNonNull("minDP", minDP); // ensureNonNull("maxDP", maxDP); super(Math.min(minDP.x, maxDP.x), Math.min(minDP.y, maxDP.y), Math.abs(maxDP.x - minDP.x), Math.abs(maxDP.y - minDP.y)); setCoordinateReferenceSystem(AbstractEnvelope.getCoordinateReferenceSystem(minDP, maxDP)); } /** * Sets this envelope to the same values than the given {@link Envelope}. * * @param envelope The envelope to copy. * @throws MismatchedDimensionException If the given envelope is not two-dimensional. * * @since 3.09 */ public void setEnvelope(final Envelope envelope) throws MismatchedDimensionException { if (envelope != this) { final int dimension = envelope.getDimension(); if (dimension != 2) { throw new MismatchedDimensionException(Errors.format( Errors.Keys.NOT_TWO_DIMENSIONAL_$1, dimension)); } setCoordinateReferenceSystem(envelope.getCoordinateReferenceSystem()); setFrame(envelope.getMinimum(0), envelope.getMinimum(1), envelope.getSpan(0), envelope.getSpan(1)); } } /** * Returns the coordinate reference system in which the coordinates are given. * * @return The coordinate reference system, or {@code null}. */ @Override public final CoordinateReferenceSystem getCoordinateReferenceSystem() { return crs; } /** * Sets the coordinate reference system in which the coordinate are given. * This method does not reproject the envelope. * If the envelope coordinates need to be transformed to the new CRS, consider using * {@link org.geotoolkit.referencing.CRS#transform(Envelope, CoordinateReferenceSystem)} * instead. * * @param crs The new coordinate reference system, or {@code null}. */ public void setCoordinateReferenceSystem(final CoordinateReferenceSystem crs) { AbstractDirectPosition.checkCoordinateReferenceSystemDimension(crs, getDimension()); this.crs = crs; } /** * Returns the number of dimensions. */ @Override public final int getDimension() { return 2; } /** * A coordinate position consisting of all the minimal ordinates for each * dimension for all points within the {@code Envelope}. * * @return The lower corner. */ @Override public DirectPosition2D getLowerCorner() { return new DirectPosition2D(crs, getMinX(), getMinY()); } /** * A coordinate position consisting of all the maximal ordinates for each * dimension for all points within the {@code Envelope}. * * @return The upper corner. */ @Override public DirectPosition2D getUpperCorner() { return new DirectPosition2D(crs, getMaxX(), getMaxY()); } /** * Creates an exception for an index out of bounds. */ private static IndexOutOfBoundsException indexOutOfBounds(final int dimension) { return new IndexOutOfBoundsException(Errors.format(Errors.Keys.INDEX_OUT_OF_BOUNDS_$1, dimension)); } /** * Returns the minimal ordinate along the specified dimension. * * @param dimension The dimension to query. * @return The minimal ordinate value along the given dimension. * @throws IndexOutOfBoundsException If the given index is out of bounds. */ @Override public final double getMinimum(final int dimension) throws IndexOutOfBoundsException { switch (dimension) { case 0: return getMinX(); case 1: return getMinY(); default: throw indexOutOfBounds(dimension); } } /** * Returns the maximal ordinate along the specified dimension. * * @param dimension The dimension to query. * @return The maximal ordinate value along the given dimension. * @throws IndexOutOfBoundsException If the given index is out of bounds. */ @Override public final double getMaximum(final int dimension) throws IndexOutOfBoundsException { switch (dimension) { case 0: return getMaxX(); case 1: return getMaxY(); default: throw indexOutOfBounds(dimension); } } /** * Returns the median ordinate along the specified dimension. The result should be equals * (minus rounding error) to ({@linkplain #getMaximum getMaximum}(dimension) - * {@linkplain #getMinimum getMinimum}(dimension)) / 2. * * @param dimension The dimension to query. * @return The mid ordinate value along the given dimension. * @throws IndexOutOfBoundsException If the given index is out of bounds. */ @Override public final double getMedian(final int dimension) throws IndexOutOfBoundsException { switch (dimension) { case 0: return getCenterX(); case 1: return getCenterY(); default: throw indexOutOfBounds(dimension); } } /** * Returns the envelope span (typically width or height) along the specified dimension. * The result should be equals (minus rounding error) to {@linkplain #getMaximum * getMaximum}(dimension) - {@linkplain #getMinimum getMinimum}(dimension). * * @param dimension The dimension to query. * @return The difference along maximal and minimal ordinates in the given dimension. * @throws IndexOutOfBoundsException If the given index is out of bounds. */ @Override public final double getSpan(final int dimension) throws IndexOutOfBoundsException { switch (dimension) { case 0: return getWidth (); case 1: return getHeight(); default: throw indexOutOfBounds(dimension); } } /** * Returns a hash value for this envelope. Current implementation returns the same * value than {@link Rectangle2D} for consistency with its {@link Rectangle2D#equals * equals} method, which compare arbitrary {@code Rectangle2D} implementations. */ @Override public int hashCode() { return super.hashCode(); } /** * Compares the specified object with this envelope for equality. * * @param object The object to compare with this envelope. * @return {@code true} if the given object is equal to this envelope. */ @Override public boolean equals(final Object object) { if (super.equals(object)) { final CoordinateReferenceSystem otherCRS = (object instanceof Envelope2D) ? ((Envelope2D) object).crs : null; return Utilities.equals(crs, otherCRS); } return false; } /** * Returns {@code true} if {@code this} envelope bounds is equal to {@code that} envelope * bounds in two specified dimensions. The coordinate reference system is not compared, since * it doesn't need to have the same number of dimensions. * * @param that The envelope to compare to. * @param xDim The dimension of {@code that} envelope to compare to the x dimension * of {@code this} envelope. * @param yDim The dimension of {@code that} envelope to compare to the y dimension * of {@code this} envelope. * @param eps A small tolerance number for floating point number comparisons. This value will * be scaled according this envelope {@linkplain #width width} and * {@linkplain #height height}. * @return {@code true} if the envelope bounds are the same (up to the specified tolerance * level) in the specified dimensions, or {@code false} otherwise. */ public boolean boundsEquals(final Envelope that, final int xDim, final int yDim, double eps) { eps *= 0.5*(width + height); for (int i=0; i<4; i++) { final int dim2D = (i & 1); final int dimND = (dim2D == 0) ? xDim : yDim; final double value2D, valueND; if ((i & 2) == 0) { value2D = this.getMinimum(dim2D); valueND = that.getMinimum(dimND); } else { value2D = this.getMaximum(dim2D); valueND = that.getMaximum(dimND); } // Use '!' for catching NaN values. if (!(Math.abs(value2D - valueND) <= eps)) { return false; } } return true; } /** * Formats this envelope in the Well Known Text (WKT) format. * The output is like below: * *

{@code BOX2D(}{@linkplain #getLowerCorner() lower corner}{@code ,} * {@linkplain #getUpperCorner() upper corner}{@code )}
* * @see Envelopes#toWKT(Envelope) * * @since 2.4 */ @Override public String toString() { return AbstractEnvelope.toString(this); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy