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

Last change on this file since 3676 was 3473, checked in by bastiK, 14 years ago

see #5327 (patch by sbrunner) - Swissgrild uses approximate formulas => better use exact formulas

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