001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/model/csct/cs/AxisOrientation.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/exse/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     It has been implemented within SEAGIS - An OpenSource implementation of OpenGIS specification
012     (C) 2001, Institut de Recherche pour le D�veloppement (http://sourceforge.net/projects/seagis/)
013     SEAGIS Contacts:  Surveillance de l'Environnement Assist�e par Satellite
014     Institut de Recherche pour le D�veloppement / US-Espace
015     mailto:seasnet@teledetection.fr
016    
017    
018     This library is free software; you can redistribute it and/or
019     modify it under the terms of the GNU Lesser General Public
020     License as published by the Free Software Foundation; either
021     version 2.1 of the License, or (at your option) any later version.
022    
023     This library is distributed in the hope that it will be useful,
024     but WITHOUT ANY WARRANTY; without even the implied warranty of
025     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
026     Lesser General Public License for more details.
027    
028     You should have received a copy of the GNU Lesser General Public
029     License along with this library; if not, write to the Free Software
030     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
031    
032     Contact:
033    
034     Andreas Poth
035     lat/lon GmbH
036     Aennchenstr. 19
037     53115 Bonn
038     Germany
039     E-Mail: poth@lat-lon.de
040    
041     Klaus Greve
042     Department of Geography
043     University of Bonn
044     Meckenheimer Allee 166
045     53115 Bonn
046     Germany
047     E-Mail: klaus.greve@uni-bonn.de
048    
049     
050     ---------------------------------------------------------------------------*/
051    package org.deegree.model.csct.cs;
052    
053    // OpenGIS dependencies
054    import java.io.ObjectStreamException;
055    import java.util.Locale;
056    import java.util.NoSuchElementException;
057    
058    import javax.media.jai.EnumeratedParameter;
059    
060    import org.deegree.model.csct.resources.css.ResourceKeys;
061    import org.deegree.model.csct.resources.css.Resources;
062    
063    /**
064     * Orientation of axis. Some coordinate systems use non-standard orientations. For example, the
065     * first axis in South African grids usually points West, instead of East. This information is
066     * obviously relevant for algorithms converting South African grid coordinates into Lat/Long. <br>
067     * <br>
068     * The <em>natural ordering</em> for axis orientations is defined as (EAST-WEST), (NORTH-SOUTH),
069     * (UP-DOWN), (FUTURE-PAST) and OTHER, which is the ordering for a (<var>x</var>,<var>y</var>,<var>z</var>,<var>t</var>)
070     * coordinate system. This means that when an array of <code>AxisOrientation</code>s is sorted
071     * using {@link java.util.Arrays#sort(Object[])}, EAST and WEST orientations will appears first.
072     * NORTH and SOUTH will be next, followed by UP and DOWN, etc.
073     * 
074     * Care should be exercised if <code>AxisOrientation</code>s are to be used as keys in a sorted
075     * map or elements in a sorted set, as <code>AxisOrientation</code>'s natural ordering is
076     * inconsistent with equals. See {@link java.lang.Comparable}, {@link java.util.SortedMap} or
077     * {@link java.util.SortedSet} for more information.
078     * 
079     * @version 1.00
080     * @author OpenGIS (www.opengis.org)
081     * @author Martin Desruisseaux
082     * 
083     * @author last edited by: $Author: bezema $
084     * 
085     * @version $Revision: 6259 $, $Date: 2007-03-20 10:15:15 +0100 (Di, 20 Mär 2007) $
086     * 
087     * @see "org.opengis.cs.CS_AxisOrientationEnum"
088     */
089    public final class AxisOrientation extends EnumeratedParameter implements Comparable {
090        /**
091         * Serial number for interoperability with different versions.
092         */
093        private static final long serialVersionUID = 4649182002820021468L;
094    
095        /**
096         * Unknown or unspecified axis orientation. This can be used for local or fitted coordinate
097         * systems.
098         */
099        public static final int CS_AO_Other = 0;
100    
101        /**
102         * Increasing ordinates values go North. This is usually used for Grid Y coordinates and
103         * Latitude.
104         */
105        public static final int CS_AO_North = 1;
106    
107        /**
108         * Increasing ordinates values go South. This is rarely used.
109         */
110        public static final int CS_AO_South = 2;
111    
112        /**
113         * Increasing ordinates values go East. This is rarely used.
114         */
115        public static final int CS_AO_East = 3;
116    
117        /**
118         * Increasing ordinates values go West. This is usually used for Grid X coordinates and
119         * Longitude.
120         */
121        public static final int CS_AO_West = 4;
122    
123        /**
124         * Increasing ordinates values go up. This is used for vertical coordinate systems.
125         */
126        public static final int CS_AO_Up = 5;
127    
128        /**
129         * Increasing ordinates values go down. This is used for vertical coordinate systems.
130         */
131        public static final int CS_AO_Down = 6;
132    
133        /**
134         * Unknown or unspecified axis orientation. This can be used for local or fitted coordinate
135         * systems.
136         * 
137         * @see "org.opengis.cs.CS_AxisOrientationEnum#CS_AO_Other"
138         */
139        public static final AxisOrientation OTHER = new AxisOrientation( "OTHER", CS_AO_Other,
140                                                                         ResourceKeys.OTHER );
141    
142        /**
143         * Increasing ordinates values go North. This is usually used for Grid Y coordinates and
144         * Latitude.
145         * 
146         * @see "org.opengis.cs.CS_AxisOrientationEnum#CS_AO_North"
147         */
148        public static final AxisOrientation NORTH = new AxisOrientation( "NORTH", CS_AO_North,
149                                                                         ResourceKeys.NORTH );
150    
151        /**
152         * Increasing ordinates values go South.
153         * 
154         * @see "org.opengis.cs.CS_AxisOrientationEnum#CS_AO_South"
155         */
156        public static final AxisOrientation SOUTH = new AxisOrientation( "SOUTH", CS_AO_South,
157                                                                         ResourceKeys.SOUTH );
158    
159        /**
160         * Increasing ordinates values go East. This is usually used for Grid X coordinates and
161         * Longitude.
162         * 
163         * @see "org.opengis.cs.CS_AxisOrientationEnum#CS_AO_East"
164         */
165        public static final AxisOrientation EAST = new AxisOrientation( "EAST", CS_AO_East,
166                                                                        ResourceKeys.EAST );
167    
168        /**
169         * Increasing ordinates values go West.
170         * 
171         * @see "org.opengis.cs.CS_AxisOrientationEnum#CS_AO_West"
172         */
173        public static final AxisOrientation WEST = new AxisOrientation( "WEST", CS_AO_West,
174                                                                        ResourceKeys.WEST );
175    
176        /**
177         * Increasing ordinates values go up. This is used for vertical coordinate systems.
178         * 
179         * @see "org.opengis.cs.CS_AxisOrientationEnum#CS_AO_Up"
180         */
181        public static final AxisOrientation UP = new AxisOrientation( "UP", CS_AO_Up, ResourceKeys.UP );
182    
183        /**
184         * Increasing ordinates values go down. This is used for vertical coordinate systems.
185         * 
186         * @see "org.opengis.cs.CS_AxisOrientationEnum#CS_AO_Down"
187         */
188        public static final AxisOrientation DOWN = new AxisOrientation( "DOWN", CS_AO_Down,
189                                                                        ResourceKeys.DOWN );
190    
191        /**
192         * Increasing time go toward future. This is used for temporal axis.
193         */
194        public static final AxisOrientation FUTURE = new AxisOrientation( "FUTURE", 7,
195                                                                          ResourceKeys.FUTURE );
196    
197        /**
198         * Increasing time go toward past. This is used for temporal axis.
199         */
200        public static final AxisOrientation PAST = new AxisOrientation( "PAST", 8, ResourceKeys.PAST );
201    
202        /**
203         * The last paired value. Paired value are NORTH-SOUTH, EAST-WEST, UP-DOWN, FUTURE-PAST.
204         */
205        private static final int LAST_PAIRED_VALUE = 8;
206    
207        /**
208         * Axis orientations by value. Used to canonicalize after deserialization.
209         */
210        private static final AxisOrientation[] ENUMS = { OTHER, NORTH, SOUTH, EAST, WEST, UP, DOWN,
211                                                        FUTURE, PAST };
212    
213        /**
214         * The axis order. Used for {@link #compareTo} implementation.
215         */
216        private static final AxisOrientation[] ORDER = { EAST, NORTH, UP, FUTURE };
217    
218        /**
219         * Resource key, used for building localized name. This key doesn't need to be serialized, since
220         * {@link #readResolve} canonicalize enums according their {@link #value}. Furthermore, its
221         * value is implementation-dependent (which is an other raison why it should not be serialized).
222         */
223        private transient final int key;
224    
225        /**
226         * Construct a new enum with the specified value.
227         */
228        private AxisOrientation( final String name, final int value, final int key ) {
229            super( name, value );
230            this.key = key;
231        }
232    
233        /**
234         * Return the enum for the specified value. This method is provided for compatibility with
235         * {@link "org.opengis.cs.CS_AxisOrientationEnum"}.
236         * 
237         * @param value
238         *            The enum value.
239         * @return The enum for the specified value.
240         * @throws NoSuchElementException
241         *             if there is no enum for the specified value.
242         */
243        public static AxisOrientation getEnum( final int value )
244                                throws NoSuchElementException {
245            if ( value >= 0 && value < ENUMS.length )
246                return ENUMS[value];
247            throw new NoSuchElementException( String.valueOf( value ) );
248        }
249    
250        /**
251         * Returns this enum's name in the specified locale. If no name is available for the specified
252         * locale, a default one will be used.
253         * 
254         * @param locale
255         *            The locale, or <code>null</code> for the default locale.
256         * @return Enum's name in the specified locale.
257         */
258        public String getName( final Locale locale ) {
259            return Resources.getResources( locale ).getString( key );
260        }
261    
262        /**
263         * Returns the opposite orientation of this axis. The opposite of North is South, and the
264         * opposite of South is North. The same apply to East-West, Up-Down and Future-Past. Other axis
265         * orientation are returned inchanged.
266         * 
267         * @return the opposite orientation of this axis. The opposite of North is South, and the
268         *         opposite of South is North. The same apply to East-West, Up-Down and Future-Past.
269         *         Other axis orientation are returned inchanged.
270         */
271        public AxisOrientation inverse() {
272            final int value = getValue() - 1;
273            if ( value >= 0 && value < LAST_PAIRED_VALUE ) {
274                return ENUMS[( value ^ 1 ) + 1];
275            }
276            return this;
277        }
278    
279        /**
280         * Returns the "absolute" orientation of this axis. This "absolute" operation is similar to the
281         * <code>Math.abs(int)</code> method in that "negative" orientation (<code>SOUTH</code>,
282         * <code>WEST</code>, <code>DOWN</code>, <code>PAST</code>) are changed for their
283         * positive counterpart (<code>NORTH</code>, <code>EAST</code>, <code>UP</code>,
284         * <code>FUTURE</code>). More specifically, the following conversion table is applied. <br>
285         * &nbsp; <table align="center" cellpadding="3" border="1" bgcolor="F4F8FF">
286         * <tr bgcolor="#B9DCFF">
287         * <th>&nbsp;&nbsp;Orientation&nbsp;&nbsp;</th>
288         * <th>&nbsp;&nbsp;Absolute value&nbsp;&nbsp;</th>
289         * </tr>
290         * <tr align="center">
291         * <td>NORTH</td>
292         * <td>NORTH</td>
293         * </tr>
294         * <tr align="center">
295         * <td>SOUTH</td>
296         * <td>NORTH</td>
297         * </tr>
298         * <tr align="center">
299         * <td>EAST</td>
300         * <td>EAST</td>
301         * </tr>
302         * <tr align="center">
303         * <td>WEST</td>
304         * <td>EAST</td>
305         * </tr>
306         * <tr align="center">
307         * <td>UP</td>
308         * <td>UP</td>
309         * </tr>
310         * <tr align="center">
311         * <td>DOWN</td>
312         * <td>UP</td>
313         * </tr>
314         * <tr align="center">
315         * <td>FUTURE</td>
316         * <td>FUTURE</td>
317         * </tr>
318         * <tr align="center">
319         * <td>PAST</td>
320         * <td>FUTURE</td>
321         * </tr>
322         * <tr align="center">
323         * <td>OTHER</td>
324         * <td>OTHER</td>
325         * </tr>
326         * </table>
327         * 
328         * @return the "absolute" orientation of this axis.
329         */
330        public AxisOrientation absolute() {
331            final int value = getValue() - 1;
332            if ( value >= 0 && value < LAST_PAIRED_VALUE ) {
333                return ENUMS[( value & ~1 ) + 1];
334            }
335            return this;
336        }
337    
338        /**
339         * Compares this <code>AxisOrientation</code> with the specified orientation. The
340         * <em>natural ordering</em> is defined as (EAST-WEST), (NORTH-SOUTH), (UP-DOWN),
341         * (FUTURE-PAST) and OTHER, which is the ordering for a (<var>x</var>,<var>y</var>,<var>z</var>,<var>t</var>)
342         * coordinate system. Two <code>AxisOrientation</code> that are among the same axis but with
343         * an opposite direction (e.g. EAST vs WEST) are considered equal by this method.
344         * 
345         * @param ao
346         *            An <code>AxisOrientation</code> object to be compared with.
347         * @return
348         * @throws ClassCastException
349         *             if <code>ao</code> is not an <code>AxisOrientation</code> object.
350         */
351        public int compareTo( final Object ao ) {
352            final AxisOrientation that = (AxisOrientation) ao;
353            final int thisOrder = this.absolute().getOrder();
354            final int thatOrder = that.absolute().getOrder();
355            if ( thisOrder > thatOrder )
356                return +1;
357            if ( thisOrder < thatOrder )
358                return -1;
359            return 0;
360        }
361    
362        /**
363         * Returns the order for this axis orientation (i.e. the index in the {@link #ORDER} table).
364         */
365        private int getOrder() {
366            int i;
367            for ( i = 0; i < ORDER.length; i++ )
368                if ( equals( ORDER[i] ) )
369                    break;
370            return i;
371        }
372    
373        /**
374         * Use a single instance of {@link AxisOrientation} after deserialization. It allow client code
375         * to test <code>enum1==enum2</code> instead of <code>enum1.equals(enum2)</code>.
376         * 
377         * @return A single instance of this enum.
378         * @throws ObjectStreamException
379         *             is deserialization failed.
380         */
381        private Object readResolve() {
382            final int value = getValue();
383            if ( value >= 0 && value < ENUMS.length ) {
384                return ENUMS[value]; // Canonicalize
385            }
386            return ENUMS[0]; // Collapse unknow value to a single canonical one
387        }
388    }