001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2004, Institut de Recherche pour le Développement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation;
010: * version 2.1 of the License.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.resources;
018:
019: // J2SE dependencies
020: import java.util.Locale;
021:
022: // OpenGIS dependencies
023: import org.opengis.metadata.extent.GeographicBoundingBox;
024: import org.opengis.referencing.FactoryException;
025: import org.opengis.referencing.crs.CoordinateReferenceSystem;
026: import org.opengis.referencing.operation.CoordinateOperation;
027: import org.opengis.referencing.operation.CoordinateOperationFactory;
028: import org.opengis.referencing.operation.TransformException;
029: import org.opengis.geometry.Envelope;
030:
031: // Geotools dependencies
032: import org.geotools.factory.Hints;
033: import org.geotools.measure.Latitude;
034: import org.geotools.measure.Longitude;
035: import org.geotools.measure.AngleFormat;
036: import org.geotools.metadata.iso.extent.GeographicBoundingBoxImpl;
037: import org.geotools.referencing.CRS;
038: import org.geotools.referencing.ReferencingFactoryFinder;
039: import org.geotools.referencing.crs.DefaultGeographicCRS;
040: import org.geotools.referencing.operation.TransformPathNotFoundException;
041: import org.geotools.resources.i18n.Errors;
042: import org.geotools.resources.i18n.ErrorKeys;
043:
044: /**
045: * Provides convenience methods for {@linkplain GeographicBoundingBox geographic bounding boxes}.
046: * This is mostly a helper class for {@link GeographicBoundingBoxImpl}; users should not use this
047: * class directly.
048: *
049: * @since 2.4
050: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/resources/BoundingBoxes.java $
051: * @version $Id: BoundingBoxes.java 26378 2007-07-30 21:14:35Z desruisseaux $
052: * @author Martin Desruisseaux
053: * @author Touraïvane
054: */
055: public final class BoundingBoxes {
056: /**
057: * A set of hints used in order to fetch lenient coordinate operation factory. We accept
058: * lenient transforms because {@link GeographicBoundingBox} are usually for approximative
059: * bounds (e.g. the area of validity of some CRS). If a user wants accurate bounds, he
060: * should probably use an {@link Envelope} with the appropriate CRS.
061: */
062: private static final Hints LENIENT = new Hints(
063: Hints.LENIENT_DATUM_SHIFT, Boolean.TRUE);
064:
065: /**
066: * Prevents the creation of instances of this class.
067: */
068: private BoundingBoxes() {
069: }
070:
071: /**
072: * Initialize a geographic bounding box from the specified envelope. If the envelope contains
073: * a CRS, then the bounding box will be projected to the {@linkplain DefaultGeographicCRS#WGS84
074: * WGS 84} CRS. Otherwise, the envelope is assumed already in WGS 84 CRS.
075: */
076: public static void copy(Envelope envelope,
077: final GeographicBoundingBoxImpl box)
078: throws TransformException {
079: final CoordinateReferenceSystem crs = envelope
080: .getCoordinateReferenceSystem();
081: if (crs != null) {
082: if (!startsWith(crs, DefaultGeographicCRS.WGS84)
083: && !startsWith(crs, DefaultGeographicCRS.WGS84_3D)) {
084: final CoordinateOperation operation;
085: final CoordinateOperationFactory factory;
086: factory = ReferencingFactoryFinder
087: .getCoordinateOperationFactory(LENIENT);
088: try {
089: operation = factory.createOperation(crs,
090: DefaultGeographicCRS.WGS84);
091: } catch (FactoryException exception) {
092: throw new TransformPathNotFoundException(Errors
093: .format(ErrorKeys.CANT_TRANSFORM_ENVELOPE,
094: exception));
095: }
096: envelope = CRS.transform(operation, envelope);
097: }
098: }
099: box.setWestBoundLongitude(envelope.getMinimum(0));
100: box.setEastBoundLongitude(envelope.getMaximum(0));
101: box.setSouthBoundLatitude(envelope.getMinimum(1));
102: box.setNorthBoundLatitude(envelope.getMaximum(1));
103: }
104:
105: /**
106: * Returns {@code true} if the specified {@code crs} starts with the specified {@code head}.
107: */
108: private static final boolean startsWith(
109: final CoordinateReferenceSystem crs,
110: final CoordinateReferenceSystem head) {
111: final int dimension = head.getCoordinateSystem().getDimension();
112: return crs.getCoordinateSystem().getDimension() >= dimension
113: && CRS.equalsIgnoreMetadata(CRSUtilities.getSubCRS(crs,
114: 0, dimension), head);
115: }
116:
117: /**
118: * Returns a string representation of the specified extent using the specified angle
119: * pattern and locale. See {@link AngleFormat} for a description of angle patterns.
120: *
121: * @param box The bounding box to format.
122: * @param pattern The angle pattern (e.g. {@code DD°MM'SS.s"}.
123: * @param locale The locale, or {@code null} for the default one.
124: */
125: public static String toString(final GeographicBoundingBox box,
126: final String pattern, final Locale locale) {
127: final StringBuffer buffer = new StringBuffer();
128: final AngleFormat format;
129: format = (locale != null) ? new AngleFormat(pattern, locale)
130: : new AngleFormat(pattern);
131: buffer.append(format.format(new Latitude(box
132: .getNorthBoundLatitude())));
133: buffer.append(", ");
134: buffer.append(format.format(new Longitude(box
135: .getWestBoundLongitude())));
136: buffer.append(" - ");
137: buffer.append(format.format(new Latitude(box
138: .getSouthBoundLatitude())));
139: buffer.append(", ");
140: buffer.append(format.format(new Longitude(box
141: .getEastBoundLongitude())));
142: return buffer.toString();
143: }
144: }
|