source: josm/trunk/src/org/openstreetmap/josm/data/projection/UTM.java@ 4382

Last change on this file since 4382 was 4285, checked in by bastiK, 13 years ago

major projection rework

More modular structure, inspired by Proj.4.

There are almost no semantic changes to the projection algorithms. Mostly factors of 'a' and 180/PI have been moved from one place to the other. In UTM_France_DOM, the ellipsoid conversion for the first 3 projections has been changed from hayford <-> GRS80 to hayford <-> WGS84.

Some redundant algorithms have been removed. In particular:

  • UTM_France_DOM used to have its own Transverse Mercator implementation. It is different from the implementation in TransverseMercator.java as it has another series expansion. For EPSG::2975, there are numeric differences on centimeter scale. However, the new data fits better with Proj.4 output.
  • Also removed are alternate implementations of LambertConformalConic. (They are all quite similar, though.)
  • Property svn:eol-style set to native
File size: 8.9 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.data.projection;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.GridBagLayout;
7import java.awt.event.ActionListener;
8import java.util.ArrayList;
9import java.util.Arrays;
10import java.util.Collection;
11
12import javax.swing.ButtonGroup;
13import javax.swing.JCheckBox;
14import javax.swing.JComboBox;
15import javax.swing.JLabel;
16import javax.swing.JPanel;
17import javax.swing.JRadioButton;
18
19import org.openstreetmap.josm.data.Bounds;
20import org.openstreetmap.josm.data.coor.LatLon;
21import org.openstreetmap.josm.data.projection.datum.GRS80Datum;
22import org.openstreetmap.josm.tools.GBC;
23
24/**
25 *
26 * @author Dirk Stöcker
27 * code based on JavaScript from Chuck Taylor
28 *
29 */
30public class UTM extends AbstractProjection implements ProjectionSubPrefs {
31
32 private static final int DEFAULT_ZONE = 30;
33 private int zone;
34
35 public enum Hemisphere { North, South }
36 private static final Hemisphere DEFAULT_HEMISPHERE = Hemisphere.North;
37 private Hemisphere hemisphere;
38
39 /**
40 * Applies an additional false easting of 3000000 m if true.
41 */
42 private boolean offset;
43
44 public UTM() {
45 this(DEFAULT_ZONE, DEFAULT_HEMISPHERE, false);
46 }
47
48 public UTM(int zone, Hemisphere hemisphere, boolean offset) {
49 ellps = Ellipsoid.GRS80;
50 proj = new org.openstreetmap.josm.data.projection.proj.TransverseMercator(ellps);
51 datum = GRS80Datum.INSTANCE;
52 updateParameters(zone, hemisphere, offset);
53 }
54
55 public void updateParameters(int zone, Hemisphere hemisphere, boolean offset) {
56 this.zone = zone;
57 this.hemisphere = hemisphere;
58 this.offset = offset;
59 x_0 = 500000 + (offset ? 3000000 : 0);
60 y_0 = hemisphere == Hemisphere.North ? 0 : 10000000;
61 lon_0 = getUtmCentralMeridianDeg(zone);
62 k_0 = 0.9996;
63 }
64
65 /*
66 * UTMCentralMeridian
67 *
68 * Determines the central meridian for the given UTM zone.
69 *
70 * Inputs:
71 * zone - An integer value designating the UTM zone, range [1,60].
72 *
73 * Returns:
74 * The central meridian for the given UTM zone, in radians, or zero
75 * if the UTM zone parameter is outside the range [1,60].
76 * Range of the central meridian is the radian equivalent of [-177,+177].
77 *
78 */
79 private double getUtmCentralMeridianDeg(int zone)
80 {
81 return -183.0 + (zone * 6.0);
82 }
83
84 public int getzone() {
85 return zone;
86 }
87
88 @Override
89 public String toString() {
90 return tr("UTM");
91 }
92
93 @Override
94 public Integer getEpsgCode() {
95 return ((offset?325800:32600) + getzone() + (hemisphere == Hemisphere.South?100:0));
96 }
97
98 @Override
99 public int hashCode() {
100 return toCode().hashCode();
101 }
102
103 @Override
104 public String getCacheDirectoryName() {
105 return "epsg"+ getEpsgCode();
106 }
107
108 @Override
109 public Bounds getWorldBoundsLatLon()
110 {
111 if (hemisphere == Hemisphere.North)
112 return new Bounds(
113 new LatLon(-5.0, getUtmCentralMeridianDeg(getzone())-5.0),
114 new LatLon(85.0, getUtmCentralMeridianDeg(getzone())+5.0));
115 else
116 return new Bounds(
117 new LatLon(-85.0, getUtmCentralMeridianDeg(getzone())-5.0),
118 new LatLon(5.0, getUtmCentralMeridianDeg(getzone())+5.0));
119 }
120
121 @Override
122 public void setupPreferencePanel(JPanel p, ActionListener listener) {
123 //Zone
124 JComboBox zonecb = new JComboBox();
125 for(int i = 1; i <= 60; i++) {
126 zonecb.addItem(i);
127 }
128
129 zonecb.setSelectedIndex(zone - 1);
130 p.setLayout(new GridBagLayout());
131 p.add(new JLabel(tr("UTM Zone")), GBC.std().insets(5,5,0,5));
132 p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
133 /* Note: we use component position 2 below to find this again */
134 p.add(zonecb, GBC.eop().fill(GBC.HORIZONTAL));
135 p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
136
137 //Hemisphere
138 JRadioButton north = new JRadioButton();
139 north.setSelected(hemisphere == Hemisphere.North);
140 JRadioButton south = new JRadioButton();
141 south.setSelected(hemisphere == Hemisphere.South);
142
143 ButtonGroup group = new ButtonGroup();
144 group.add(north);
145 group.add(south);
146
147 JPanel bPanel = new JPanel();
148 bPanel.setLayout(new GridBagLayout());
149
150 bPanel.add(new JLabel(tr("North")), GBC.std().insets(5, 5, 0, 5));
151 bPanel.add(north, GBC.std().fill(GBC.HORIZONTAL));
152 bPanel.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
153 bPanel.add(new JLabel(tr("South")), GBC.std().insets(5, 5, 0, 5));
154 bPanel.add(south, GBC.std().fill(GBC.HORIZONTAL));
155 bPanel.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
156
157 p.add(new JLabel(tr("Hemisphere")), GBC.std().insets(5,5,0,5));
158 p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
159 p.add(bPanel, GBC.eop().fill(GBC.HORIZONTAL));
160 p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
161
162 //Offset
163 JCheckBox offsetBox = new JCheckBox();
164 offsetBox.setSelected(offset);
165
166 p.add(new JLabel(tr("Offset 3.000.000m east")), GBC.std().insets(5,5,0,5));
167 p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
168 /* Note: we use component position 2 below to find this again */
169 p.add(offsetBox, GBC.eop().fill(GBC.HORIZONTAL));
170 p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
171
172 if (listener != null) {
173 north.addActionListener(listener);
174 south.addActionListener(listener);
175 zonecb.addActionListener(listener);
176 offsetBox.addActionListener(listener);
177 }
178 }
179
180 @Override
181 public Collection<String> getPreferences(JPanel p) {
182 int zone = DEFAULT_ZONE;
183 Hemisphere hemisphere = DEFAULT_HEMISPHERE;
184 boolean offset = false;
185
186 Object zonecb = p.getComponent(2);
187 if (zonecb instanceof JComboBox) {
188 zone = ((JComboBox)zonecb).getSelectedIndex() + 1;
189 }
190
191 Object bPanel = p.getComponent(6);
192 if (bPanel instanceof JPanel) {
193 Object south = ((JPanel)bPanel).getComponent(4);
194 if (south instanceof JRadioButton) {
195 hemisphere = ((JRadioButton)south).isSelected()?Hemisphere.South:Hemisphere.North;
196 }
197 }
198
199 Object offsetBox = p.getComponent(10);
200 if (offsetBox instanceof JCheckBox) {
201 offset = ((JCheckBox) offsetBox).isSelected();
202 }
203
204 return Arrays.asList(Integer.toString(zone), hemisphere.toString(), (offset?"offset":"standard"));
205 }
206
207 @Override
208 public void setPreferences(Collection<String> args) {
209 int zone = DEFAULT_ZONE;
210 Hemisphere hemisphere = DEFAULT_HEMISPHERE;
211 boolean offset = false;
212
213 if(args != null)
214 {
215 String[] array = args.toArray(new String[0]);
216 try {
217 zone = Integer.parseInt(array[0]);
218 if(zone <= 0 || zone > 60) {
219 zone = DEFAULT_ZONE;
220 }
221 } catch(NumberFormatException e) {}
222
223 if (array.length > 1) {
224 hemisphere = Hemisphere.valueOf(array[1]);
225 }
226
227 if (array.length > 2) {
228 offset = array[2].equals("offset");
229 }
230 }
231 updateParameters(zone, hemisphere, offset);
232 }
233
234 @Override
235 public String[] allCodes() {
236 ArrayList<String> projections = new ArrayList<String>(60*4);
237 for (int zone = 1;zone <= 60; zone++) {
238 for (boolean offset : new boolean[] { false, true }) {
239 for (Hemisphere hemisphere : Hemisphere.values()) {
240 projections.add("EPSG:" + ((offset?325800:32600) + zone + (hemisphere == Hemisphere.South?100:0)));
241 }
242 }
243 }
244 return projections.toArray(new String[0]);
245 }
246
247 @Override
248 public Collection<String> getPreferencesFromCode(String code) {
249
250 boolean offset = code.startsWith("EPSG:3258") || code.startsWith("EPSG:3259");
251
252 if(code.startsWith("EPSG:326") || code.startsWith("EPSG:327") || offset)
253 {
254 try {
255 Hemisphere hemisphere;
256 String zonestring;
257 if (offset) {
258 hemisphere = code.charAt(8)=='8'?Hemisphere.North:Hemisphere.South;
259 zonestring = code.substring(9);
260 } else {
261 hemisphere = code.charAt(7)=='6'?Hemisphere.North:Hemisphere.South;
262 zonestring = code.substring(8);
263 }
264
265 int zoneval = Integer.parseInt(zonestring);
266 if(zoneval > 0 && zoneval <= 60)
267 return Arrays.asList(zonestring, hemisphere.toString(), (offset?"offset":"standard"));
268 } catch(NumberFormatException e) {}
269 }
270 return null;
271 }
272}
Note: See TracBrowser for help on using the repository browser.