/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2005-2012, Open Source Geospatial Foundation (OSGeo) * (C) 2009-2012, 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 java.awt.geom.AffineTransform; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.MathTransform2D; import org.opengis.referencing.operation.CoordinateOperation; import org.opengis.referencing.operation.TransformException; import org.geotoolkit.lang.Static; import org.geotoolkit.referencing.CRS; import org.apache.sis.util.ArgumentChecks; import org.geotoolkit.internal.referencing.CRSUtilities; import org.apache.sis.geometry.Shapes2D; /** * Utility methods for envelopes. This utility class is made up of static functions working * with arbitrary implementations of GeoAPI interfaces. * * @author Martin Desruisseaux (IRD, Geomatys) * @author Jody Garnett (Refractions) * @author Andrea Aime (TOPP) * @author Johann Sorel (Geomatys) * @see CRS * @module */ public final class Envelopes extends Static { static { org.geotoolkit.internal.io.JNDI.install(); } /** * Do not allow instantiation of this class. */ private Envelopes() { } /** * Returns the domain of validity for the specified coordinate reference system, * or {@code null} if unknown. The returned envelope is expressed in terms of the * specified CRS. * <p> * This method performs the work documented in the * {@link CRS#getEnvelope(CoordinateReferenceSystem)} method. * It is defined in this class for convenience. * * @param crs The coordinate reference system, or {@code null}. * @return The envelope in terms of the specified CRS, or {@code null} if none. * * @see CRS#getEnvelope(CoordinateReferenceSystem) * @see org.apache.sis.geometry.GeneralEnvelope#reduceToDomain(boolean) * * @deprecated Moved to Apache SIS as {@link return org.apache.sis.referencing.CRS#getDomainOfValidity}. */ @Deprecated public static Envelope getDomainOfValidity(final CoordinateReferenceSystem crs) { return CRS.getEnvelope(crs); } /** * Transforms a rectangular envelope using the given {@linkplain MathTransform math transform}. * The transformation is only approximative: the returned envelope may be bigger than * necessary, or smaller than required if the bounding box contains a pole. * <p> * Invoking this method is equivalent to invoking the following: * * {@preformat java * transform(transform, new GeneralEnvelope(envelope)).toRectangle2D() * } * * Note that this method can not handle the case where the rectangle contains the North or South * pole, or when it cross the ±180° longitude, because {@linkplain MathTransform * math transforms} do not carry sufficient informations. For a more robust rectangle * transformation, use {@link #transform(CoordinateOperation, Rectangle2D, Rectangle2D)} * instead. * * @param transform The transform to use. Source and target dimension must be 2. * @param envelope The rectangle to transform (may be {@code null}). * @param destination The destination rectangle (may be {@code envelope}). * If {@code null}, a new rectangle will be created and returned. * @return {@code destination}, or a new rectangle if {@code destination} was non-null * and {@code envelope} was null. * @throws TransformException if a transform failed. * * @see #transform(CoordinateOperation, Rectangle2D, Rectangle2D) * @see org.geotoolkit.referencing.operation.matrix.XAffineTransform#transform(AffineTransform, Rectangle2D, Rectangle2D) * * @deprecated Moved to Apache SIS in {@link Shapes2D} class. */ @Deprecated public static Rectangle2D transform(final MathTransform2D transform, final Rectangle2D envelope, Rectangle2D destination) throws TransformException { return Shapes2D.transform(transform, envelope, destination); } /** * Transforms a rectangular envelope using the given {@linkplain CoordinateOperation coordinate * operation}. The transformation is only approximative: the returned envelope may be bigger * than the smallest possible bounding box, but should not be smaller in most cases. * <p> * Invoking this method is equivalent to invoking the following: * * {@preformat java * transform(operation, new GeneralEnvelope(envelope)).toRectangle2D() * } * * This method can handle the case where the rectangle contains the North or South pole, * or when it cross the ±180° longitude. * * @param operation The operation to use. Source and target dimension must be 2. * @param envelope The rectangle to transform (may be {@code null}). * @param destination The destination rectangle (may be {@code envelope}). * If {@code null}, a new rectangle will be created and returned. * @return {@code destination}, or a new rectangle if {@code destination} was non-null * and {@code envelope} was null. * @throws TransformException if a transform failed. * * @see #transform(MathTransform2D, Rectangle2D, Rectangle2D) * @see org.geotoolkit.referencing.operation.matrix.XAffineTransform#transform(AffineTransform, Rectangle2D, Rectangle2D) * * @deprecated Moved to Apache SIS in {@link Shapes2D} class. */ @Deprecated public static Rectangle2D transform(final CoordinateOperation operation, final Rectangle2D envelope, Rectangle2D destination) throws TransformException { return Shapes2D.transform(operation, envelope, destination); } /** * Returns {@code true} if {@link Envelope} contain at least one * {@link Double#NaN} value, else {@code false}. * * @param envelope the envelope which will be verify. * @return {@code true} if {@link Envelope} contain at least one {@link Double#NaN} value, else {@code false}. * @see #containNAN(org.opengis.geometry.Envelope, int, int) */ public static boolean containNAN(final Envelope envelope) { return containNAN(envelope, 0, envelope.getDimension() - 1); } /** * Returns {@code true} if {@link Envelope} contain at least one * {@link Double#NaN} value into its horizontal geographic part, else {@code false}. * * @param envelope the envelope which will be verify. * @return {@code true} if {@link Envelope} contain at least one {@link Double#NaN} value, else {@code false}. * @see CRSUtilities#firstHorizontalAxis(org.opengis.referencing.crs.CoordinateReferenceSystem) * @see #containNAN(org.opengis.geometry.Envelope, int, int) */ public static boolean containNANInto2DGeographicPart(final Envelope envelope) { ArgumentChecks.ensureNonNull("Envelopes.containNANInto2DGeographicPart()", envelope); final int minOrdiGeo = CRSUtilities.firstHorizontalAxis(envelope.getCoordinateReferenceSystem()); return containNAN(envelope, minOrdiGeo, minOrdiGeo + 1); } /** * Returns {@code true} if {@link Envelope} contain at least one * {@link Double#NaN} value on each inclusive dimension stipulate by * firstIndex and lastIndex, else {@code false}. * * @param envelope the envelope which will be verify. * @param firstIndex first inclusive dimension index. * @param lastIndex last <strong>INCLUSIVE</strong> dimension. * @return {@code true} if {@link Envelope} contain at least one {@link Double#NaN} value, else {@code false}. */ public static boolean containNAN(final Envelope envelope, final int firstIndex, final int lastIndex) { ArgumentChecks.ensureNonNull("Envelopes.containNAN()", envelope); ArgumentChecks.ensurePositive("firstIndex", firstIndex); ArgumentChecks.ensurePositive("lastIndex", lastIndex); if (lastIndex >= envelope.getDimension()) throw new IllegalArgumentException("LastIndex must be strictly lower than " + "envelope dimension number. Expected maximum valid index = "+(envelope.getDimension() - 1)+". Found : "+lastIndex); ArgumentChecks.ensureValidIndex(lastIndex + 1, firstIndex); for (int d = firstIndex; d <= lastIndex; d++) { if (Double.isNaN(envelope.getMinimum(d)) || Double.isNaN(envelope.getMaximum(d))) return true; } return false; } }