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.datum;
021:
022: // J2SE dependencies and extensions
023: import java.util.Collections;
024: import java.util.Map;
025: import javax.units.NonSI;
026: import javax.units.Unit;
027:
028: // OpenGIS dependencies
029: import org.opengis.referencing.datum.PrimeMeridian;
030:
031: // Geotools dependencies
032: import org.geotools.referencing.AbstractIdentifiedObject;
033: import org.geotools.referencing.wkt.Formatter;
034: import org.geotools.resources.Utilities;
035:
036: /**
037: * A prime meridian defines the origin from which longitude values are determined.
038: * The {@link #getName name} initial value is "Greenwich", and that value shall be
039: * used when the {@linkplain #getGreenwichLongitude greenwich longitude} value is
040: * zero.
041: *
042: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/datum/DefaultPrimeMeridian.java $
043: * @version $Id: DefaultPrimeMeridian.java 20874 2006-08-07 10:00:01Z jgarnett $
044: * @author Martin Desruisseaux
045: *
046: * @since 2.1
047: */
048: public class DefaultPrimeMeridian extends AbstractIdentifiedObject
049: implements PrimeMeridian {
050: /**
051: * Serial number for interoperability with different versions.
052: */
053: private static final long serialVersionUID = 541978454643213305L;;
054:
055: /**
056: * The Greenwich meridian, with angular measurements in decimal degrees.
057: */
058: public static final DefaultPrimeMeridian GREENWICH = new DefaultPrimeMeridian(
059: "Greenwich", 0, NonSI.DEGREE_ANGLE);
060:
061: /**
062: * Longitude of the prime meridian measured from the Greenwich meridian, positive eastward.
063: */
064: private final double greenwichLongitude;
065:
066: /**
067: * The angular unit of the {@linkplain #getGreenwichLongitude Greenwich longitude}.
068: */
069: private final Unit angularUnit;
070:
071: /**
072: * Constructs a new prime meridian with the same values than the specified one.
073: * This copy constructor provides a way to wrap an arbitrary implementation into a
074: * Geotools one or a user-defined one (as a subclass), usually in order to leverage
075: * some implementation-specific API. This constructor performs a shallow copy,
076: * i.e. the properties are not cloned.
077: *
078: * @since 2.2
079: */
080: public DefaultPrimeMeridian(final PrimeMeridian meridian) {
081: super (meridian);
082: greenwichLongitude = meridian.getGreenwichLongitude();
083: angularUnit = meridian.getAngularUnit();
084: }
085:
086: /**
087: * Constructs a prime meridian from a name. The {@code greenwichLongitude} value
088: * is assumed in {@linkplain NonSI#DEGREE_ANGLE decimal degrees}.
089: *
090: * @param name The datum name.
091: * @param greenwichLongitude The longitude value relative to the Greenwich Meridian.
092: */
093: public DefaultPrimeMeridian(final String name,
094: final double greenwichLongitude) {
095: this (name, greenwichLongitude, NonSI.DEGREE_ANGLE);
096: }
097:
098: /**
099: * Constructs a prime meridian from a name.
100: *
101: * @param name The datum name.
102: * @param greenwichLongitude The longitude value relative to the Greenwich Meridian.
103: * @param angularUnit The angular unit of the longitude.
104: */
105: public DefaultPrimeMeridian(final String name,
106: final double greenwichLongitude, final Unit angularUnit) {
107: this (Collections.singletonMap(NAME_KEY, name),
108: greenwichLongitude, angularUnit);
109: }
110:
111: /**
112: * Constructs a prime meridian from a set of properties. The properties map is given
113: * unchanged to the {@linkplain AbstractIdentifiedObject#AbstractIdentifiedObject(Map)
114: * super-class constructor}.
115: *
116: * @param properties Set of properties. Should contains at least <code>"name"</code>.
117: * @param greenwichLongitude The longitude value relative to the Greenwich Meridian.
118: * @param angularUnit The angular unit of the longitude.
119: */
120: public DefaultPrimeMeridian(final Map properties,
121: final double greenwichLongitude, final Unit angularUnit) {
122: super (properties);
123: this .greenwichLongitude = greenwichLongitude;
124: this .angularUnit = angularUnit;
125: ensureAngularUnit(angularUnit);
126: }
127:
128: /**
129: * Longitude of the prime meridian measured from the Greenwich meridian, positive eastward.
130: * The {@code greenwichLongitude} initial value is zero, and that value shall be used
131: * when the {@linkplain #getName meridian name} value is "Greenwich".
132: *
133: * @return The prime meridian Greenwich longitude, in {@linkplain #getAngularUnit angular unit}.
134: */
135: public double getGreenwichLongitude() {
136: return greenwichLongitude;
137: }
138:
139: /**
140: * Returns the longitude value relative to the Greenwich Meridian, expressed in the specified
141: * units. This convenience method makes it easier to obtain longitude in decimal degrees
142: * ({@code getGreenwichLongitude(NonSI.DEGREE_ANGLE)}), regardless of the underlying
143: * angular units of this prime meridian.
144: *
145: * @param targetUnit The unit in which to express longitude.
146: */
147: public double getGreenwichLongitude(final Unit targetUnit) {
148: return getAngularUnit().getConverterTo(targetUnit).convert(
149: getGreenwichLongitude());
150: }
151:
152: /**
153: * Returns the angular unit of the {@linkplain #getGreenwichLongitude Greenwich longitude}.
154: */
155: public Unit getAngularUnit() {
156: return angularUnit;
157: }
158:
159: /**
160: * Compare this prime meridian with the specified object for equality.
161: *
162: * @param object The object to compare to {@code this}.
163: * @param compareMetadata {@code true} for performing a strict comparaison, or
164: * {@code false} for comparing only properties relevant to transformations.
165: * @return {@code true} if both objects are equal.
166: */
167: public boolean equals(final AbstractIdentifiedObject object,
168: final boolean compareMetadata) {
169: if (object == this ) {
170: return true; // Slight optimization.
171: }
172: if (super .equals(object, compareMetadata)) {
173: final DefaultPrimeMeridian that = (DefaultPrimeMeridian) object;
174: if (compareMetadata) {
175: return Double.doubleToLongBits(this .greenwichLongitude) == Double
176: .doubleToLongBits(that.greenwichLongitude)
177: && Utilities.equals(this .angularUnit,
178: that.angularUnit);
179: } else {
180: return Double.doubleToLongBits(this
181: .getGreenwichLongitude(NonSI.DEGREE_ANGLE)) == Double
182: .doubleToLongBits(that
183: .getGreenwichLongitude(NonSI.DEGREE_ANGLE));
184: /*
185: * Note: if compareMetadata==false, we relax the unit check because EPSG uses
186: * sexagesimal degrees for the Greenwich meridian. Requirying the same
187: * unit prevent Geodetic.isWGS84(...) method to recognize EPSG's WGS84.
188: */
189: }
190: }
191: return false;
192: }
193:
194: /**
195: * Returns a hash value for this prime meridian. {@linkplain #getName Name},
196: * {@linkplain #getRemarks remarks} and the like are not taken in account.
197: * In other words, two prime meridians will return the same hash value if
198: * they are equal in the sense of
199: * <code>{@link #equals equals}(AbstractIdentifiedObject, <strong>false</strong>)</code>.
200: *
201: * @return The hash code value. This value doesn't need to be the same
202: * in past or future versions of this class.
203: */
204: public int hashCode() {
205: final long code = Double.doubleToLongBits(greenwichLongitude);
206: return ((int) (code >>> 32) ^ (int) code)
207: ^ (int) serialVersionUID;
208: }
209:
210: /**
211: * Format the inner part of a
212: * <A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/referencing/doc-files/WKT.html"><cite>Well
213: * Known Text</cite> (WKT)</A> element.
214: *
215: * @param formatter The formatter to use.
216: * @return The WKT element name, which is "PRIMEM"
217: */
218: protected String formatWKT(final Formatter formatter) {
219: Unit context = formatter.getAngularUnit();
220: if (context == null) {
221: // If the PrimeMeridian is written inside a "GEOGCS",
222: // then OpenGIS say that it must be written into the
223: // unit of the enclosing geographic coordinate system.
224: // Otherwise, default to decimal degrees.
225: context = NonSI.DEGREE_ANGLE;
226: }
227: formatter.append(getGreenwichLongitude(context));
228: return "PRIMEM";
229: }
230: }
|