source: josm/trunk/src/org/openstreetmap/josm/data/projection/SwissGrid.java@ 3779

Last change on this file since 3779 was 3779, checked in by Upliner, 13 years ago

Identify projections in offset bookmarks by EPSG codes, bugfixes in getPreferencesFromCode() functions as they're critical now.

  • Property svn:eol-style set to native
File size: 6.5 KB
Line 
1//License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.projection;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.event.ActionListener;
7import java.util.Collection;
8import java.util.Collections;
9
10import javax.swing.Box;
11import javax.swing.JPanel;
12
13import org.openstreetmap.josm.data.Bounds;
14import org.openstreetmap.josm.data.coor.EastNorth;
15import org.openstreetmap.josm.data.coor.LatLon;
16import org.openstreetmap.josm.gui.widgets.HtmlPanel;
17import org.openstreetmap.josm.tools.GBC;
18
19/**
20 * Projection for the SwissGrid CH1903 / L03, see http://de.wikipedia.org/wiki/Swiss_Grid.
21 *
22 * Calculations are based on formula from
23 * http://www.swisstopo.admin.ch/internet/swisstopo/en/home/topics/survey/sys/refsys/switzerland.parsysrelated1.37696.downloadList.12749.DownloadFile.tmp/ch1903wgs84en.pdf
24 *
25 * August 2010 update to this formula (rigorous formulas)
26 * http://www.swisstopo.admin.ch/internet/swisstopo/en/home/topics/survey/sys/refsys/switzerland.parsysrelated1.37696.downloadList.97912.DownloadFile.tmp/swissprojectionen.pdf
27 */
28public class SwissGrid implements Projection, ProjectionSubPrefs {
29
30 private static final double dX = 674.374;
31 private static final double dY = 15.056;
32 private static final double dZ = 405.346;
33
34 private static final double phi0 = Math.toRadians(46.0 + 57.0 / 60 + 8.66 / 3600);
35 private static final double lambda0 = Math.toRadians(7.0 + 26.0 / 60 + 22.50 / 3600);
36 private static final double R = Ellipsoid.Bessel1841.a * Math.sqrt(1 - Ellipsoid.Bessel1841.e2) / (1 - (Ellipsoid.Bessel1841.e2 * Math.pow(Math.sin(phi0), 2)));
37 private static final double alpha = Math.sqrt(1 + (Ellipsoid.Bessel1841.eb2 * Math.pow(Math.cos(phi0), 4)));
38 private static final double b0 = Math.asin(Math.sin(phi0) / alpha);
39 private static final double K = Math.log(Math.tan(Math.PI / 4 + b0 / 2)) - alpha
40 * Math.log(Math.tan(Math.PI / 4 + phi0 / 2)) + alpha * Ellipsoid.Bessel1841.e / 2
41 * Math.log((1 + Ellipsoid.Bessel1841.e * Math.sin(phi0)) / (1 - Ellipsoid.Bessel1841.e * Math.sin(phi0)));
42
43 private static final double xTrans = 200000;
44 private static final double yTrans = 600000;
45
46 private static final double DELTA_PHI = 1e-11;
47
48 private LatLon correctEllipoideGSR80toBressel1841(LatLon coord) {
49 double[] XYZ = Ellipsoid.WGS84.latLon2Cart(coord);
50 XYZ[0] -= dX;
51 XYZ[1] -= dY;
52 XYZ[2] -= dZ;
53 return Ellipsoid.Bessel1841.cart2LatLon(XYZ);
54 }
55
56 private LatLon correctEllipoideBressel1841toGRS80(LatLon coord) {
57 double[] XYZ = Ellipsoid.Bessel1841.latLon2Cart(coord);
58 XYZ[0] += dX;
59 XYZ[1] += dY;
60 XYZ[2] += dZ;
61 return Ellipsoid.WGS84.cart2LatLon(XYZ);
62 }
63
64 /**
65 * @param wgs WGS84 lat/lon (ellipsoid GRS80) (in degree)
66 * @return eastnorth projection in Swiss National Grid (ellipsoid Bessel)
67 */
68 @Override
69 public EastNorth latlon2eastNorth(LatLon wgs) {
70 LatLon coord = correctEllipoideGSR80toBressel1841(wgs);
71 double phi = Math.toRadians(coord.lat());
72 double lambda = Math.toRadians(coord.lon());
73
74 double S = alpha * Math.log(Math.tan(Math.PI / 4 + phi / 2)) - alpha * Ellipsoid.Bessel1841.e / 2
75 * Math.log((1 + Ellipsoid.Bessel1841.e * Math.sin(phi)) / (1 - Ellipsoid.Bessel1841.e * Math.sin(phi))) + K;
76 double b = 2 * (Math.atan(Math.exp(S)) - Math.PI / 4);
77 double l = alpha * (lambda - lambda0);
78
79 double lb = Math.atan2(Math.sin(l), Math.sin(b0) * Math.tan(b) + Math.cos(b0) * Math.cos(l));
80 double bb = Math.asin(Math.cos(b0) * Math.sin(b) - Math.sin(b0) * Math.cos(b) * Math.cos(l));
81
82 double y = R * lb;
83 double x = R / 2 * Math.log((1 + Math.sin(bb)) / (1 - Math.sin(bb)));
84
85 return new EastNorth(y + yTrans, x + xTrans);
86 }
87
88 /**
89 * @param xy SwissGrid east/north (in meters)
90 * @return LatLon WGS84 (in degree)
91 */
92 @Override
93 public LatLon eastNorth2latlon(EastNorth xy) {
94 double x = xy.north() - xTrans;
95 double y = xy.east() - yTrans;
96
97 double lb = y / R;
98 double bb = 2 * (Math.atan(Math.exp(x / R)) - Math.PI / 4);
99
100 double b = Math.asin(Math.cos(b0) * Math.sin(bb) + Math.sin(b0) * Math.cos(bb) * Math.cos(lb));
101 double l = Math.atan2(Math.sin(lb), Math.cos(b0) * Math.cos(lb) - Math.sin(b0) * Math.tan(bb));
102
103 double lambda = lambda0 + l / alpha;
104 double phi = b;
105 double S = 0;
106
107 double prevPhi = -1000;
108 int iteration = 0;
109 // iteration to finds S and phi
110 while (Math.abs(phi - prevPhi) > DELTA_PHI) {
111 if (++iteration > 30)
112 throw new RuntimeException("Two many iterations");
113 prevPhi = phi;
114 S = 1 / alpha * (Math.log(Math.tan(Math.PI / 4 + b / 2)) - K) + Ellipsoid.Bessel1841.e
115 * Math.log(Math.tan(Math.PI / 4 + Math.asin(Ellipsoid.Bessel1841.e * Math.sin(phi)) / 2));
116 phi = 2 * Math.atan(Math.exp(S)) - Math.PI / 2;
117 }
118
119 LatLon coord = correctEllipoideBressel1841toGRS80(new LatLon(Math.toDegrees(phi), Math.toDegrees(lambda)));
120 return coord;
121 }
122
123 @Override
124 public String toString() {
125 return tr("Swiss Grid (Switzerland)");
126 }
127
128 @Override
129 public String toCode() {
130 return "EPSG:21781";
131 }
132
133 @Override
134 public int hashCode() {
135 return getClass().getName().hashCode(); // we have no variables
136 }
137
138 @Override
139 public String getCacheDirectoryName() {
140 return "swissgrid";
141 }
142
143 @Override
144 public Bounds getWorldBoundsLatLon() {
145 return new Bounds(new LatLon(45.7, 5.7), new LatLon(47.9, 10.6));
146 }
147
148 @Override
149 public double getDefaultZoomInPPD() {
150 // This will set the scale bar to about 100 m
151 return 1.01;
152 }
153
154 @Override
155 public void setupPreferencePanel(JPanel p, ActionListener listener) {
156 p.add(new HtmlPanel("<i>CH1903 / LV03 (without local corrections)</i>"), GBC.eol().fill(GBC.HORIZONTAL));
157 p.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
158 }
159
160 @Override
161 public void setPreferences(Collection<String> args) {
162 }
163
164 @Override
165 public Collection<String> getPreferences(JPanel p) {
166 return Collections.singletonList("CH1903");
167 }
168
169 @Override
170 public String[] allCodes() {
171 return new String[] { "EPSG:21781" };
172 }
173
174 @Override
175 public Collection<String> getPreferencesFromCode(String code) {
176 if ("EPSG:21781".equals(code))
177 return Collections.singletonList("CH1903");
178 return null;
179 }
180}
Note: See TracBrowser for help on using the repository browser.