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 static javax.measure.unit.SI.METRE;
012
013import javax.measure.quantity.Length;
014import javax.measure.Measurable;
015import javax.measure.unit.Unit;
016
017import javolution.context.ObjectFactory;
018import javolution.xml.XMLFormat;
019import javolution.xml.stream.XMLStreamException;
020
021import org.jscience.geography.coordinates.crs.VerticalCRS;
022import org.opengis.referencing.cs.CoordinateSystem;
023
024/**
025 * This class represents the {@link VerticalCRS vertical} height above the 
026 * WGS84 ellipsoid.
027 * 
028 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
029 * @version 3.0, February 6, 2006
030 */
031public final class Height extends Coordinates<VerticalCRS<?>> implements
032        Measurable<Length> {
033
034    /**
035     * Holds the coordinate reference system for all instances of this class. 
036     */
037    public static final VerticalCRS<Height> CRS = new VerticalCRS<Height>() {
038
039        @Override
040        protected Height coordinatesOf(AbsolutePosition position) {
041            if (position.heightWGS84 instanceof Height)
042                return (Height) position.heightWGS84;
043            return Height.valueOf(position.heightWGS84.doubleValue(METRE),
044                    METRE);
045        }
046
047        @Override
048        protected AbsolutePosition positionOf(Height coordinates,
049                AbsolutePosition position) {
050            position.heightWGS84 = coordinates;
051            return position;
052        }
053
054        @Override
055        public CoordinateSystem getCoordinateSystem() {
056            return VerticalCRS.HEIGHT_CS;
057        }
058    };
059
060    /**
061     * Holds the height in meters. 
062     */
063    private double _meters;
064
065    /**
066     * Returns the vertical position corresponding to the specified coordinates.
067     * 
068     * @param value the height above the WGS84 ellipsoid stated in the 
069     *        specified unit.
070     * @param unit the length unit in which the height is stated.
071     * @return the corresponding vertical position.
072     */
073    public static Height valueOf(double value, Unit<Length> unit) {
074        Height height = FACTORY.object();
075        height._meters = (unit == METRE) ? value : 
076            unit.getConverterTo(METRE).convert(value);
077        return height;
078    }
079    
080    private static final ObjectFactory<Height> FACTORY = new ObjectFactory<Height>() {
081
082        @Override
083        protected Height create() {
084            return new Height();
085        } };
086    
087    private Height() {
088    }
089
090    @Override
091    public VerticalCRS<?> getCoordinateReferenceSystem() {
092        return Height.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.equals(METRE) ? _meters : METRE
113                .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> arg0) {
123        double arg0InMeter = arg0.doubleValue(METRE);
124        return (_meters > arg0InMeter) ? 1
125                : (_meters < arg0InMeter) ? -1 : 0;
126    }
127    
128    
129    @Override
130    public Height copy() {
131        return Height.valueOf(_meters, METRE);
132    }
133
134    // Default serialization.
135    //
136    
137    static final XMLFormat<Height> XML = new XMLFormat<Height>(Height.class) {
138        
139        @Override
140        public Height newInstance(Class<Height> cls, InputElement xml) throws XMLStreamException {
141            return FACTORY.object();
142        }
143        
144        public void write(Height height, OutputElement xml) throws XMLStreamException {
145             xml.setAttribute("meters", height._meters);
146         }
147
148         public void read(InputElement xml, Height height) throws XMLStreamException {
149             height._meters = xml.getAttribute("meters", 0.0);
150         }
151     };
152
153    private static final long serialVersionUID = 1L;
154}