source: josm/trunk/src/org/openstreetmap/josm/data/projection/Ellipsoid.java@ 5039

Last change on this file since 5039 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: 7.2 KB
Line 
1/*
2 * Import from fr.geo.convert package, a geographic coordinates converter.
3 * (http://www.i3s.unice.fr/~johan/gps/)
4 * License: GPL. For details, see LICENSE file.
5 * Copyright (C) 2002 Johan Montagnat (johan@creatis.insa-lyon.fr)
6 */
7
8package org.openstreetmap.josm.data.projection;
9
10import org.openstreetmap.josm.data.coor.LatLon;
11
12/**
13 * the reference ellipsoids
14 */
15public class Ellipsoid {
16 /**
17 * Clarke's ellipsoid (NTF system)
18 */
19 public static final Ellipsoid clarke = new Ellipsoid(6378249.2, 6356515.0);
20 /**
21 * Hayford's ellipsoid 1909 (ED50 system)
22 * Proj.4 code: intl
23 */
24 public static final Ellipsoid hayford =
25 new Ellipsoid(6378388.0, 6356911.9461);
26 /**
27 * GRS80 ellipsoid
28 */
29 public static final Ellipsoid GRS80 = new Ellipsoid(6378137.0, 6356752.3141);
30
31 /**
32 * WGS84 ellipsoid
33 */
34 public static final Ellipsoid WGS84 = new Ellipsoid(6378137.0, 6356752.3142);
35
36 /**
37 * Bessel 1841 ellipsoid
38 */
39 public static final Ellipsoid Bessel1841 = new Ellipsoid(6377397.155, 6356078.962822);
40
41 /**
42 * half long axis
43 */
44 public final double a;
45 /**
46 * half short axis
47 */
48 public final double b;
49 /**
50 * first eccentricity
51 */
52 public final double e;
53 /**
54 * first eccentricity squared
55 */
56 public final double e2;
57
58 /**
59 * square of the second eccentricity
60 */
61 public final double eb2;
62
63 /**
64 * create a new ellipsoid and precompute its parameters
65 *
66 * @param a ellipsoid long axis (in meters)
67 * @param b ellipsoid short axis (in meters)
68 */
69 public Ellipsoid(double a, double b) {
70 this.a = a;
71 this.b = b;
72 e2 = (a*a - b*b) / (a*a);
73 e = Math.sqrt(e2);
74 eb2 = e2 / (1.0 - e2);
75 }
76
77 /**
78 * Returns the <i>radius of curvature in the prime vertical</i>
79 * for this reference ellipsoid at the specified latitude.
80 *
81 * @param phi The local latitude (radians).
82 * @return The radius of curvature in the prime vertical (meters).
83 */
84 public double verticalRadiusOfCurvature(final double phi) {
85 return a / Math.sqrt(1.0 - (e2 * sqr(Math.sin(phi))));
86 }
87
88 private static double sqr(final double x) {
89 return x * x;
90 }
91
92 /**
93 * Returns the meridional arc, the true meridional distance on the
94 * ellipsoid from the equator to the specified latitude, in meters.
95 *
96 * @param phi The local latitude (in radians).
97 * @return The meridional arc (in meters).
98 */
99 public double meridionalArc(final double phi) {
100 final double sin2Phi = Math.sin(2.0 * phi);
101 final double sin4Phi = Math.sin(4.0 * phi);
102 final double sin6Phi = Math.sin(6.0 * phi);
103 final double sin8Phi = Math.sin(8.0 * phi);
104 // TODO . calculate 'f'
105 //double f = 1.0 / 298.257222101; // GRS80
106 double f = 1.0 / 298.257223563; // WGS84
107 final double n = f / (2.0 - f);
108 final double n2 = n * n;
109 final double n3 = n2 * n;
110 final double n4 = n3 * n;
111 final double n5 = n4 * n;
112 final double n1n2 = n - n2;
113 final double n2n3 = n2 - n3;
114 final double n3n4 = n3 - n4;
115 final double n4n5 = n4 - n5;
116 final double ap = a * (1.0 - n + (5.0 / 4.0) * (n2n3) + (81.0 / 64.0) * (n4n5));
117 final double bp = (3.0 / 2.0) * a * (n1n2 + (7.0 / 8.0) * (n3n4) + (55.0 / 64.0) * n5);
118 final double cp = (15.0 / 16.0) * a * (n2n3 + (3.0 / 4.0) * (n4n5));
119 final double dp = (35.0 / 48.0) * a * (n3n4 + (11.0 / 16.0) * n5);
120 final double ep = (315.0 / 512.0) * a * (n4n5);
121 return ap * phi - bp * sin2Phi + cp * sin4Phi - dp * sin6Phi + ep * sin8Phi;
122 }
123
124 /**
125 * Returns the <i>radius of curvature in the meridian<i>
126 * for this reference ellipsoid at the specified latitude.
127 *
128 * @param phi The local latitude (in radians).
129 * @return The radius of curvature in the meridian (in meters).
130 */
131 public double meridionalRadiusOfCurvature(final double phi) {
132 return verticalRadiusOfCurvature(phi)
133 / (1.0 + eb2 * sqr(Math.cos(phi)));
134 }
135
136 /**
137 * Returns isometric latitude of phi on given first eccentricity (e)
138 * @param phi The local latitude (radians).
139 * @return isometric latitude of phi on first eccentricity (e)
140 */
141 public double latitudeIsometric(double phi, double e) {
142 double v1 = 1-e*Math.sin(phi);
143 double v2 = 1+e*Math.sin(phi);
144 return Math.log(Math.tan(Math.PI/4+phi/2)*Math.pow(v1/v2,e/2));
145 }
146
147 /**
148 * Returns isometric latitude of phi on first eccentricity (e)
149 * @param phi The local latitude (radians).
150 * @return isometric latitude of phi on first eccentricity (e)
151 */
152 public double latitudeIsometric(double phi) {
153 double v1 = 1-e*Math.sin(phi);
154 double v2 = 1+e*Math.sin(phi);
155 return Math.log(Math.tan(Math.PI/4+phi/2)*Math.pow(v1/v2,e/2));
156 }
157
158 /*
159 * Returns geographic latitude of isometric latitude of first eccentricity (e)
160 * and epsilon precision
161 */
162 public double latitude(double latIso, double e, double epsilon) {
163 double lat0 = 2*Math.atan(Math.exp(latIso))-Math.PI/2;
164 double lati = lat0;
165 double lati1 = 1.0; // random value to start the iterative processus
166 while(Math.abs(lati1-lati)>=epsilon) {
167 lati = lati1;
168 double v1 = 1+e*Math.sin(lati);
169 double v2 = 1-e*Math.sin(lati);
170 lati1 = 2*Math.atan(Math.pow(v1/v2,e/2)*Math.exp(latIso))-Math.PI/2;
171 }
172 return lati1;
173 }
174
175 /**
176 * convert cartesian coordinates to ellipsoidal coordinates
177 *
178 * @param XYZ the coordinates in meters (X, Y, Z)
179 * @return The corresponding latitude and longitude in degrees
180 */
181 public LatLon cart2LatLon(double[] XYZ) {
182 return cart2LatLon(XYZ, 1e-11);
183 }
184 public LatLon cart2LatLon(double[] XYZ, double epsilon) {
185 double norm = Math.sqrt(XYZ[0] * XYZ[0] + XYZ[1] * XYZ[1]);
186 double lg = 2.0 * Math.atan(XYZ[1] / (XYZ[0] + norm));
187 double lt = Math.atan(XYZ[2] / (norm * (1.0 - (a * e2 / Math.sqrt(XYZ[0] * XYZ[0] + XYZ[1] * XYZ[1] + XYZ[2] * XYZ[2])))));
188 double delta = 1.0;
189 while (delta > epsilon) {
190 double s2 = Math.sin(lt);
191 s2 *= s2;
192 double l = Math.atan((XYZ[2] / norm)
193 / (1.0 - (a * e2 * Math.cos(lt) / (norm * Math.sqrt(1.0 - e2 * s2)))));
194 delta = Math.abs(l - lt);
195 lt = l;
196 }
197 return new LatLon(Math.toDegrees(lt), Math.toDegrees(lg));
198 }
199
200 /**
201 * convert ellipsoidal coordinates to cartesian coordinates
202 *
203 * @param coord The Latitude and longitude in degrees
204 * @return the corresponding (X, Y Z) cartesian coordinates in meters.
205 */
206 public double[] latLon2Cart(LatLon coord) {
207 double phi = Math.toRadians(coord.lat());
208 double lambda = Math.toRadians(coord.lon());
209
210 double Rn = a / Math.sqrt(1 - e2 * Math.pow(Math.sin(phi), 2));
211 double[] XYZ = new double[3];
212 XYZ[0] = Rn * Math.cos(phi) * Math.cos(lambda);
213 XYZ[1] = Rn * Math.cos(phi) * Math.sin(lambda);
214 XYZ[2] = Rn * (1 - e2) * Math.sin(phi);
215
216 return XYZ;
217 }
218}
Note: See TracBrowser for help on using the repository browser.