source: osm/applications/editors/josm/plugins/opendata/includes/org/geotools/referencing/cs/PredefinedCS.java@ 28000

Last change on this file since 28000 was 28000, checked in by donvip, 12 years ago

Import new "opendata" JOSM plugin

File size: 8.5 KB
Line 
1/*
2 * GeoTools - The Open Source Java GIS Toolkit
3 * http://geotools.org
4 *
5 * (C) 2005-2008, Open Source Geospatial Foundation (OSGeo)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation;
10 * version 2.1 of the License.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 */
17package org.geotools.referencing.cs;
18
19import java.util.List;
20import java.util.Arrays;
21import java.util.Comparator;
22import java.util.Map;
23import javax.measure.unit.SI;
24import javax.measure.unit.Unit;
25
26import org.opengis.referencing.cs.*;
27import org.geotools.resources.i18n.Errors;
28import org.geotools.resources.i18n.ErrorKeys;
29
30
31/**
32 * Converts an arbitrary CS into one of the predefined constants provided in the
33 * {@link org.geotools.referencing.cs} package. The main usage for this class is
34 * to reorder the axis in some "standard" order like (<var>x</var>, <var>y</var>,
35 * <var>z</var>) or (<var>longitude</var>, <var>latitude</var>). What "standard"
36 * order means is sometime an arbitrary choice, which explain why this class is
37 * not public at this time.
38 *
39 * @source $URL: http://svn.osgeo.org/geotools/branches/2.7.x/modules/library/referencing/src/main/java/org/geotools/referencing/cs/PredefinedCS.java $
40 * @version $Id: PredefinedCS.java 30760 2008-06-18 14:28:24Z desruisseaux $
41 * @author Martin Desruisseaux (IRD)
42 */
43final class PredefinedCS implements Comparator<CoordinateSystem> {
44 /**
45 * An instance of {@link PredefinedCS}. Will be created only when first needed.
46 */
47 private static Comparator<CoordinateSystem> csComparator;
48
49 /**
50 * Our ordering for coordinate system objects.
51 */
52 @SuppressWarnings("unchecked")
53 private final Class<? extends CoordinateSystem>[] types = new Class[] {
54 CartesianCS .class,
55 AffineCS .class,
56 EllipsoidalCS.class,
57 SphericalCS .class,
58 CylindricalCS.class,
59 PolarCS .class,
60 VerticalCS .class,
61 TimeCS .class,
62 LinearCS .class,
63 UserDefinedCS.class
64 };
65
66 /**
67 * Creates a comparator.
68 */
69 private PredefinedCS() {
70 }
71
72 /**
73 * Compares the ordering between two coordinate systems. This comparator is used for sorting
74 * the axis in an user-supplied compound CS in an order closes to some "standard" order.
75 */
76 public int compare(final CoordinateSystem object1, final CoordinateSystem object2) {
77 final Class<? extends CoordinateSystem> type1 = object1.getClass();
78 final Class<? extends CoordinateSystem> type2 = object2.getClass();
79 for (int i=0; i<types.length; i++) {
80 final Class<?> type = types[i];
81 final boolean a1 = type.isAssignableFrom(type1);
82 final boolean a2 = type.isAssignableFrom(type2);
83 if (a1) return a2 ? 0 : -1;
84 if (a2) return a1 ? 0 : +1;
85 }
86 return 0;
87 }
88
89 /**
90 * Implementation of the {@link AbstractCS#standard} method.
91 */
92 static CoordinateSystem standard(final CoordinateSystem cs) throws IllegalArgumentException {
93 final int dimension = cs.getDimension();
94 if (cs instanceof CartesianCS) {
95 switch (dimension) {
96 case 2: {
97 if (DefaultCartesianCS.PROJECTED.axisColinearWith(cs)) {
98 return DefaultCartesianCS.PROJECTED;
99 }
100 if (DefaultCartesianCS.GRID.axisColinearWith(cs)) {
101 return DefaultCartesianCS.GRID;
102 }
103 if (DefaultCartesianCS.GENERIC_2D.directionColinearWith(cs)) {
104 return DefaultCartesianCS.GENERIC_2D;
105 }
106 return rightHanded((CartesianCS) cs);
107 }
108 case 3: {
109 if (DefaultCartesianCS.GEOCENTRIC.axisColinearWith(cs)) {
110 return DefaultCartesianCS.GEOCENTRIC;
111 }
112 if (DefaultCartesianCS.GENERIC_3D.directionColinearWith(cs)) {
113 return DefaultCartesianCS.GENERIC_3D;
114 }
115 return rightHanded((CartesianCS) cs);
116 }
117 }
118 }
119 if (cs instanceof AffineCS) {
120 return rightHanded((AffineCS) cs);
121 }
122 if (cs instanceof EllipsoidalCS) {
123 switch (dimension) {
124 case 2: return DefaultEllipsoidalCS.GEODETIC_2D;
125 case 3: return DefaultEllipsoidalCS.GEODETIC_3D;
126 }
127 }
128 if (cs instanceof SphericalCS) {
129 switch (dimension) {
130 case 3: return DefaultSphericalCS.GEOCENTRIC;
131 }
132 }
133 if (cs instanceof VerticalCS) {
134 switch (dimension) {
135 case 1: {
136 return DefaultVerticalCS.ELLIPSOIDAL_HEIGHT;
137 }
138 }
139 }
140 if (cs instanceof TimeCS) {
141 switch (dimension) {
142 case 1: return DefaultTimeCS.DAYS;
143 }
144 }
145 if (cs instanceof DefaultCompoundCS) {
146 final List<CoordinateSystem> components = ((DefaultCompoundCS) cs).getCoordinateSystems();
147 final CoordinateSystem[] user = new CoordinateSystem[components.size()];
148 final CoordinateSystem[] std = new CoordinateSystem[user.length];
149 for (int i=0; i<std.length; i++) {
150 std[i] = standard(user[i] = components.get(i));
151 }
152 if (csComparator == null) {
153 csComparator = new PredefinedCS();
154 }
155 Arrays.sort(std, csComparator);
156 return Arrays.equals(user, std) ? cs : new DefaultCompoundCS(std);
157 }
158 throw new IllegalArgumentException(
159 Errors.format(ErrorKeys.UNSUPPORTED_COORDINATE_SYSTEM_$1, cs.getName().getCode()));
160 }
161
162 /**
163 * Reorder the axis in the specified Affine CS in an attempt to get a right-handed system.
164 * Units are standardized to meters in the process. If no axis change is needed, then this
165 * method returns {@code cs} unchanged.
166 */
167 private static AffineCS rightHanded(final AffineCS cs) {
168 boolean changed = false;
169 final int dimension = cs.getDimension();
170 final CoordinateSystemAxis[] axis = new CoordinateSystemAxis[dimension];
171 for (int i=0; i<dimension; i++) {
172 /*
173 * Gets the axis and replaces it by one of the predefined constants declared in
174 * DefaultCoordinateSystemAxis, if possible. The predefined constants use ISO 19111
175 * names with metres or degrees units, so it is pretty close to the "standard" axis
176 * we are looking for.
177 */
178 CoordinateSystemAxis axe = axis[i] = cs.getAxis(i);
179 DefaultCoordinateSystemAxis standard = DefaultCoordinateSystemAxis.getPredefined(axe);
180 if (standard != null) {
181 axe = standard;
182 }
183 /*
184 * Changes units to meters. Every units in an affine CS should be linear or
185 * dimensionless (the later is used for grid coordinates). The 'usingUnit'
186 * method will thrown an exception if the unit is incompatible. See
187 * DefaultAffineCS.isCompatibleUnit(Unit).
188 */
189 final Unit<?> unit = axe.getUnit();
190 if (!Unit.ONE.equals(unit) && !SI.METER.equals(unit)) {
191 if (!(axe instanceof DefaultCoordinateSystemAxis)) {
192 axe = new DefaultCoordinateSystemAxis(axe);
193 }
194 axe = ((DefaultCoordinateSystemAxis) axe).usingUnit(SI.METER);
195 }
196 changed |= (axe != axis[i]);
197 axis[i] = axe;
198 }
199 /*
200 * Sorts the axis in an attempt to create a right-handed system
201 * and creates a new Coordinate System if at least one axis changed.
202 */
203 changed |= ComparableAxisWrapper.sort(axis);
204 if (!changed) {
205 return cs;
206 }
207 final Map<String,?> properties = DefaultAffineCS.getProperties(cs, null);
208 if (cs instanceof CartesianCS) {
209 return new DefaultCartesianCS(properties, axis);
210 }
211 return new DefaultAffineCS(properties, axis);
212 }
213}
Note: See TracBrowser for help on using the repository browser.