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;
010
011import javax.measure.quantity.Length;
012import javax.measure.Measurable;
013import static javax.measure.unit.SI.METRE;
014import javax.measure.unit.Unit;
015
016import javolution.context.ObjectFactory;
017import javolution.xml.XMLFormat;
018import javolution.xml.stream.XMLStreamException;
019
020import org.jscience.geography.coordinates.crs.VerticalCRS;
021import org.opengis.referencing.cs.CoordinateSystem;
022
023/**
024 * This class represents the Mean-Sea-Level {@link VerticalCRS vertical} 
025 * altitude (MSL).
026 *  
027 * <p> Note: The current implementation approximates the MSL altitude to 
028 *           the WGS-86 Ellipsoid Height. Future implementations will use 
029 *           lookup tables in order to correct for regional discrepencies.</p> 
030 * 
031 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
032 * @version 3.0, February 26, 2006
033 */
034public final class Altitude extends Coordinates<VerticalCRS<?>> implements
035        Measurable<Length> {
036
037    /**
038     * Holds the coordinate reference system for all instances of this class. 
039     */
040    public static final VerticalCRS<Altitude> CRS = new VerticalCRS<Altitude>() {
041
042        @Override
043        protected Altitude coordinatesOf(AbsolutePosition position) {
044            return Altitude.valueOf(position.heightWGS84.doubleValue(METRE),
045                    METRE);
046        }
047
048        @Override
049        protected AbsolutePosition positionOf(Altitude coordinates,
050                AbsolutePosition position) {
051            position.heightWGS84 = coordinates;
052            return position;
053        }
054
055        @Override
056        public CoordinateSystem getCoordinateSystem() {
057            return VerticalCRS.HEIGHT_CS;
058        }
059    };
060
061    /**
062     * Holds the altitude value in meters. 
063     */
064    private double _meters;
065
066    /**
067     * Returns the vertical position corresponding to the specified coordinates.
068     * 
069     * @param value the mean sea level altitude stated in the specified unit.
070     * @param unit the length unit in which the altitude is stated.
071     * @return the corresponding vertical position.
072     */
073    public static Altitude valueOf(double value, Unit<Length> unit) {
074        Altitude altitude = FACTORY.object();
075        altitude._meters = (unit == METRE) ? value : 
076            unit.getConverterTo(METRE).convert(value);
077        return altitude;
078    }
079    
080    private static final ObjectFactory<Altitude> FACTORY = new ObjectFactory<Altitude>() {
081
082        @Override
083        protected Altitude create() {
084            return new Altitude();
085        } };
086    
087    private Altitude() {
088    }
089
090    @Override
091    public VerticalCRS<?> getCoordinateReferenceSystem() {
092        return Altitude.CRS;
093    }
094
095    // OpenGIS Interface.
096    public int getDimension() {
097        return 1;
098    }
099
100    // OpenGIS Interface.
101    public double getOrdinate(int dimension) throws IndexOutOfBoundsException {
102        if (dimension == 0) {
103            Unit<?> u = VerticalCRS.HEIGHT_CS.getAxis(0).getUnit();
104            return METRE.getConverterTo(u).convert(_meters);
105        } else {
106            throw new IndexOutOfBoundsException();
107        }
108    }
109
110    // Implements Scalar<Length>
111    public final double doubleValue(Unit<Length> unit) {
112        return (unit == METRE) ? _meters : 
113            METRE.getConverterTo(unit).convert(_meters);
114    }
115
116    // Implements Scalar<Length>
117    public final long longValue(Unit<Length> unit) {
118        return Math.round(doubleValue(unit));
119    }
120
121    // Implements Scalar<Length>
122    public int compareTo(Measurable<Length> measure) {
123        double meters = measure.doubleValue(METRE);
124        return (_meters  > meters) ? 1
125                : (_meters < meters) ? -1 : 0;
126    }
127
128    @Override
129    public Altitude copy() {
130        return Altitude.valueOf(_meters, METRE);
131    }
132         
133    // Default serialization.
134    //
135    
136    static final XMLFormat<Altitude> XML = new XMLFormat<Altitude>(Altitude.class) {
137        
138        @Override
139        public Altitude newInstance(Class<Altitude> cls, InputElement xml) throws XMLStreamException {
140            return FACTORY.object();
141        }
142        
143        public void write(Altitude altitude, OutputElement xml) throws XMLStreamException {
144             xml.setAttribute("meters", altitude._meters);
145         }
146
147         public void read(InputElement xml, Altitude altitude) throws XMLStreamException {
148             altitude._meters = xml.getAttribute("meters", 0.0);
149         }
150     };
151
152     private static final long serialVersionUID = 1L;
153
154}