001/*
002 * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
003 * Copyright (C) 2006 - JScience (http://jscience.org/)
004 * All rights reserved.
005 * 
006 * Permission to use, copy, modify, and distribute this software is
007 * freely granted, provided that this notice is preserved.
008 */
009package org.jscience.geography.coordinates.crs;
010
011import java.util.Collection;
012import java.util.Set;
013
014import javax.measure.quantity.Angle;
015import javax.measure.quantity.Duration;
016import javax.measure.quantity.Length;
017import javax.measure.Measurable;
018import javax.measure.unit.Unit;
019
020import javolution.util.FastSet;
021
022import org.jscience.geography.coordinates.Coordinates;
023import org.opengis.metadata.Identifier;
024import org.opengis.metadata.citation.Citation;
025import org.opengis.metadata.extent.Extent;
026import org.opengis.referencing.cs.AxisDirection;
027import org.opengis.referencing.cs.CoordinateSystem;
028import org.opengis.util.InternationalString;
029import org.opengis.referencing.cs.CoordinateSystemAxis;
030
031/**
032 * This class represents an arbitrary system of reference for which 
033 * {@link Coordinates coordinates} of same significance can be stated.
034 * 
035 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
036 * @version 3.0, February 13, 2006
037 */
038public abstract class CoordinateReferenceSystem<C extends Coordinates<?>>
039        implements org.opengis.referencing.crs.CoordinateReferenceSystem {
040
041    
042    /**
043     * This class represents an absolute position (can be be extended)
044     */
045    protected static class AbsolutePosition {
046
047        /**
048         * Holds the Geodetic Latitude (WGS84 Ellipsoid).
049         */
050        public Measurable<Angle> latitudeWGS84;
051
052        /**
053         * Holds the Geodetic Longitude (WGS84 Ellipsoid).
054         */
055        public Measurable<Angle> longitudeWGS84;
056
057        /**
058         * Holds the WGS84 Ellipsoidal Height.
059         */
060        public Measurable<Length> heightWGS84;
061
062        /**
063         * Holds the Time since midnight, January 1, 1970 UTC. 
064         */
065        public Measurable<Duration> timeUTC;
066    }
067
068    /**
069     * Returns the converter between this coordinate reference system 
070     * and the one specified.
071     * 
072     * @param  that the coordinate reference system to convert to.
073     * @return the corresponding coordinates converter.
074     * @throws ConversionException if the conversion is not possible
075     *         (e.g. geographic to temporal).
076     */
077    public <T extends Coordinates<?>> CoordinatesConverter<C, T> getConverterTo(
078            CoordinateReferenceSystem<T> that) {
079        return new GeneralConverter<T>(that);
080    }
081
082    // General implementation using absolute position as intermediary.
083    private class GeneralConverter<T extends Coordinates<?>> implements
084            CoordinatesConverter<C, T> {
085        private final CoordinateReferenceSystem<T> _toCRS;
086
087        private GeneralConverter(CoordinateReferenceSystem<T> toCRS) {
088            _toCRS = toCRS;
089        }
090
091        public T convert(C source) {
092            AbsolutePosition position = positionOf(source,
093                    new AbsolutePosition());
094            return _toCRS.coordinatesOf(position);
095        }
096    }
097
098    /**
099     * Returns the coordinates in this reference system of the specified 
100     * absolute position.
101     * 
102     * @param position the absolute position for which the coordinates  
103     *        in this reference system is returned.
104     * @return the coordinates for the specified absolute position.
105     * @throws ConversionException if a conversion error occurs.
106     */
107    protected abstract C coordinatesOf(AbsolutePosition position);
108
109    /**
110     * Returns the absolute position from the coordinates in
111     * this reference system. This update may require information already 
112     * supplied by the position. For example, the height for a pressure 
113     * altitude might depends upon the latitude/longitude and the time.
114     * 
115     * @param coordinates the coordinates for which the absolute position 
116     *        is adjusted.
117     * @param position the position object to update.
118     * @return the corresponding absolute position. 
119     * @throws ConversionException if a conversion error occurs.
120     */
121    protected abstract AbsolutePosition positionOf(C coordinates,
122            AbsolutePosition position);
123
124    /**
125     * Returns the OpenGIS coordinate system associated to this 
126     * coordinate reference system.
127     * 
128     * @return the corresponding coordinate system. 
129     */
130    public abstract CoordinateSystem getCoordinateSystem();
131
132    /////////////
133    // OpenGIS //
134    /////////////
135    
136    /**
137     * OpenGIS&reg; - Area for which the (coordinate) reference system is valid.
138     *
139     * @return coordinate reference system valid area, 
140     *         or {@code null} (default) if not available.
141     */
142    public Extent getValidArea() {
143        return null;
144    }
145
146    /**
147     * OpenGIS&reg; - Description of domain of usage, or limitations of usage,
148     * for which this (coordinate) reference system object is valid.
149     */
150    public InternationalString getScope() {
151        throw new UnsupportedOperationException();
152    }
153
154    /**
155     * OpenGIS&reg; - The primary name by which this object is identified.
156     * 
157     * @return an identifier holding the class name.
158     */
159    public Identifier getName() {
160        return new Name(CoordinateReferenceSystem.this.getClass().getName());
161    }
162
163    /**
164     * OpenGIS&reg; - An alternative name by which this object is identified.
165     *
166     * @return The aliases, or an empty collection if there is none.
167     */
168    public Collection<String> getAlias() {
169        return EMPTY_SET;
170    }
171
172    /**
173     * OpenGIS&reg;  - An identifier which references elsewhere the object's defining information.
174     * Alternatively an identifier by which this object can be referenced.
175     *
176     * @return This object identifiers, or an empty set if there is none.
177     */
178    public Set<String> getIdentifiers() {
179        return EMPTY_SET;
180    }
181
182    /**
183     * OpenGIS&reg; - Comments on or information about this object, including 
184     * data source information.
185     * 
186     * @return <code>null</code> (default).
187     */
188    public InternationalString getRemarks() {
189        return null;
190    }
191
192    /**
193     * OpenGIS&reg; - Returns a <cite>Well Known Text</cite> (WKT)</A> for 
194     * this object. This operation may fails if an object is too complex for
195     * the WKT format capability (for example an engineering CRS} with different
196     * unit for each axis).
197     *
198     * @return The Well Know Text for this object.
199     * @throws UnsupportedOperationException If this object can't be formatted 
200     *         as WKT (default).
201     */
202    public String toWKT() throws UnsupportedOperationException {
203        throw new UnsupportedOperationException();
204    }
205
206    // Default coordinates axis.
207    static class Axis implements CoordinateSystemAxis {
208
209        private final Name _name;
210
211        private final String _abbreviation;
212
213        private final Unit<?> _unit;
214
215        private final AxisDirection _direction;
216
217        public Axis(final String name, String abbreviation, Unit<?> unit,
218                AxisDirection direction) {
219            _name = new Name(name);
220            _abbreviation = abbreviation;
221            _unit = unit;
222            _direction = direction;
223        }
224
225        public final Identifier getName() {
226            return _name;
227        }
228
229        public final String getAbbreviation() {
230            return _abbreviation;
231        }
232
233        public final Unit<?> getUnit() {
234            return _unit;
235        }
236
237        public final AxisDirection getDirection() {
238            return _direction;
239        }
240
241        public Collection<String> getAlias() {
242            return EMPTY_SET;
243        }
244
245        public Set<String> getIdentifiers() {
246            return EMPTY_SET;
247        }
248
249        public InternationalString getRemarks() {
250            throw new UnsupportedOperationException();
251        }
252
253        public String toWKT() throws UnsupportedOperationException {
254            throw new UnsupportedOperationException();
255        }
256
257    }
258
259    // Default coordinates axis.
260    static class Name implements Identifier {
261        final String _value;
262
263        public Name(String value) {
264            _value = value;
265        }
266
267        public String getCode() {
268            return _value;
269        }
270
271        public Citation getAuthority() {
272            throw new UnsupportedOperationException();
273        }
274
275        public String getVersion() {
276            throw new UnsupportedOperationException();
277        }
278    }
279
280    static final FastSet<String> EMPTY_SET = new FastSet<String>();
281}