001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2001, 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: * This package contains documentation from OpenGIS specifications.
018: * OpenGIS consortium's work is fully acknowledged here.
019: */
020: package org.geotools.referencing.crs;
021:
022: // J2SE dependencies and extensions
023: import java.util.Map;
024: import java.util.HashMap;
025: import javax.units.Unit;
026:
027: // OpenGIS dependencies
028: import org.opengis.referencing.cs.CoordinateSystem;
029: import org.opengis.referencing.crs.CoordinateReferenceSystem;
030: import org.opengis.geometry.MismatchedDimensionException;
031: import org.opengis.util.InternationalString;
032:
033: // Geotools dependencies
034: import org.geotools.measure.Measure;
035: import org.geotools.referencing.AbstractIdentifiedObject;
036: import org.geotools.referencing.AbstractReferenceSystem;
037: import org.geotools.referencing.cs.AbstractCS;
038: import org.geotools.referencing.wkt.Formatter;
039: import org.geotools.resources.CRSUtilities;
040: import org.geotools.resources.i18n.Vocabulary;
041: import org.geotools.util.UnsupportedImplementationException;
042:
043: /**
044: * Abstract coordinate reference system, usually defined by a coordinate system and a datum.
045: *
046: * @since 2.1
047: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/crs/AbstractCRS.java $
048: * @version $Id: AbstractCRS.java 24925 2007-03-27 20:12:08Z jgarnett $
049: * @author Martin Desruisseaux
050: *
051: * @see AbstractCS
052: * @see org.geotools.referencing.datum.AbstractDatum
053: * @tutorial http://docs.codehaus.org/display/GEOTOOLS/Coordinate+Transformation+Services+for+Geotools+2.1
054: */
055: public abstract class AbstractCRS extends AbstractReferenceSystem
056: implements CoordinateReferenceSystem {
057: /**
058: * Serial number for interoperability with different versions.
059: */
060: private static final long serialVersionUID = -7433284548909530047L;
061:
062: /**
063: * The coordinate system.
064: */
065: protected final CoordinateSystem coordinateSystem;
066:
067: /**
068: * Constructs a new coordinate reference system with the same values than the specified one.
069: * This copy constructor provides a way to wrap an arbitrary implementation into a
070: * Geotools one or a user-defined one (as a subclass), usually in order to leverage
071: * some implementation-specific API. This constructor performs a shallow copy,
072: * i.e. the properties are not cloned.
073: *
074: * @since 2.2
075: */
076: public AbstractCRS(final CoordinateReferenceSystem crs) {
077: super (crs);
078: coordinateSystem = crs.getCoordinateSystem();
079: }
080:
081: /**
082: * Constructs a coordinate reference system from a set of properties. The properties are given
083: * unchanged to the {@linkplain AbstractReferenceSystem#AbstractReferenceSystem(Map) super-class
084: * constructor}.
085: *
086: * @param properties Set of properties. Should contains at least <code>"name"</code>.
087: * @param cs The coordinate system.
088: */
089: public AbstractCRS(final Map properties, final CoordinateSystem cs) {
090: super (properties);
091: ensureNonNull("cs", cs);
092: this .coordinateSystem = cs;
093: }
094:
095: /**
096: * Creates a name for the predefined constants in subclasses. The name is an unlocalized String
097: * object. However, since this method is used for creation of convenience objects only (not for
098: * objects created from an "official" database), the "unlocalized" name is actually choosen
099: * according the user's locale at class initialization time. The same name is also added in
100: * a localizable form as an alias. Since the {@link #nameMatches} convenience method checks
101: * the alias, it still possible to consider two objects are equivalent even if their names
102: * were formatted in different locales.
103: */
104: static Map name(final int key) {
105: final Map properties = new HashMap(4);
106: final InternationalString name = Vocabulary
107: .formatInternational(key);
108: properties.put(NAME_KEY, name.toString());
109: properties.put(ALIAS_KEY, name);
110: return properties;
111: }
112:
113: /**
114: * Returns the coordinate system.
115: */
116: public CoordinateSystem getCoordinateSystem() {
117: return coordinateSystem;
118: }
119:
120: /**
121: * Returns the unit used for all axis. If not all axis uses the same unit,
122: * then this method returns {@code null}. This method is often used for
123: * Well Know Text (WKT) formatting.
124: */
125: final Unit getUnit() {
126: return CRSUtilities.getUnit(coordinateSystem);
127: }
128:
129: /**
130: * Computes the distance between two points. This convenience method delegates the work to
131: * the underlyling {@linkplain AbstractCS coordinate system}, if possible.
132: *
133: * @param coord1 Coordinates of the first point.
134: * @param coord2 Coordinates of the second point.
135: * @return The distance between {@code coord1} and {@code coord2}.
136: * @throws UnsupportedOperationException if this coordinate reference system can't compute
137: * distances.
138: * @throws MismatchedDimensionException if a coordinate doesn't have the expected dimension.
139: */
140: public Measure distance(final double[] coord1, final double[] coord2)
141: throws UnsupportedOperationException,
142: MismatchedDimensionException {
143: if (coordinateSystem instanceof AbstractCS) {
144: return ((AbstractCS) coordinateSystem).distance(coord1,
145: coord2);
146: }
147: throw new UnsupportedImplementationException(coordinateSystem
148: .getClass());
149: }
150:
151: /**
152: * Compare this coordinate reference system with the specified object for equality.
153: * If {@code compareMetadata} is {@code true}, then all available properties are
154: * compared including {@linkplain #getValidArea valid area} and {@linkplain #getScope scope}.
155: *
156: * @param object The object to compare to {@code this}.
157: * @param compareMetadata {@code true} for performing a strict comparaison, or
158: * {@code false} for comparing only properties relevant to transformations.
159: * @return {@code true} if both objects are equal.
160: */
161: public boolean equals(final AbstractIdentifiedObject object,
162: final boolean compareMetadata) {
163: if (super .equals(object, compareMetadata)) {
164: final AbstractCRS that = (AbstractCRS) object;
165: return equals(this .coordinateSystem, that.coordinateSystem,
166: compareMetadata);
167: }
168: return false;
169: }
170:
171: /**
172: * Returns a hash value for this CRS. {@linkplain #getName Name},
173: * {@linkplain #getIdentifiers identifiers} and {@linkplain #getRemarks remarks}
174: * are not taken in account. In other words, two CRS objects will return the same
175: * hash value if they are equal in the sense of
176: * <code>{@link #equals(AbstractIdentifiedObject,boolean) equals}(AbstractIdentifiedObject,
177: * <strong>false</strong>)</code>.
178: *
179: * @return The hash code value. This value doesn't need to be the same
180: * in past or future versions of this class.
181: */
182: public int hashCode() {
183: return (int) serialVersionUID ^ coordinateSystem.hashCode();
184: }
185:
186: /**
187: * Formats the inner part of a
188: * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
189: * Known Text</cite> (WKT)</A> element. The default implementation writes the following
190: * elements:
191: * <ul>
192: * <li>The {@linkplain #datum datum}, if any.</li>
193: * <li>The unit if all axis use the same unit. Otherwise the unit is omitted and
194: * the WKT format is {@linkplain Formatter#isInvalidWKT flagged as invalid}.</li>
195: * <li>All {@linkplain #coordinateSystem coordinate system}'s axis.</li>
196: * </ul>
197: *
198: * @param formatter The formatter to use.
199: * @return The name of the WKT element type (e.g. {@code "GEOGCS"}).
200: */
201: protected String formatWKT(final Formatter formatter) {
202: formatDefaultWKT(formatter);
203: // Will declares the WKT as invalid.
204: return super .formatWKT(formatter);
205: }
206:
207: /**
208: * Default implementation of {@link #formatWKT}. For {@link DefaultEngineeringCRS}
209: * and {@link DefaultVerticalCRS} use only.
210: */
211: void formatDefaultWKT(final Formatter formatter) {
212: final Unit unit = getUnit();
213: formatter.append(unit);
214: final int dimension = coordinateSystem.getDimension();
215: for (int i = 0; i < dimension; i++) {
216: formatter.append(coordinateSystem.getAxis(i));
217: }
218: if (unit == null) {
219: formatter.setInvalidWKT(CoordinateReferenceSystem.class);
220: }
221: }
222: }
|