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

Revision 5072, 9.0 KB checked in by bastiK, 2 months ago (diff)

basic support for custom projections (see #7495)

  • Property svn:eol-style set to native
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 1880 IGN (French national geographic institute)
18     */
19    public static final Ellipsoid clarkeIGN = Ellipsoid.create_a_b(6378249.2, 6356515.0);
20    /**
21     * Hayford's ellipsoid 1909 (ED50 system)
22     * Proj.4 code: intl
23     */
24    public static final Ellipsoid hayford = Ellipsoid.create_a_rf(6378388.0, 297.0);
25    /**
26     * GRS80 ellipsoid
27     */
28    public static final Ellipsoid GRS80 = Ellipsoid.create_a_rf(6378137.0, 298.257222101);
29
30    /**
31     * WGS84 ellipsoid
32     */
33    public static final Ellipsoid WGS84 = Ellipsoid.create_a_rf(6378137.0, 298.257223563);
34
35    /**
36     * Bessel 1841 ellipsoid
37     */
38    public static final Ellipsoid Bessel1841 = Ellipsoid.create_a_rf(6377397.155, 299.1528128);
39
40    /**
41     * half long axis
42     */
43    public final double a;
44    /**
45     * half short axis
46     */
47    public final double b;
48    /**
49     * first eccentricity
50     */
51    public final double e;
52    /**
53     * first eccentricity squared
54     */
55    public final double e2;
56
57    /**
58     * square of the second eccentricity
59     */
60    public final double eb2;
61
62    /**
63     * private constructur - use one of the create_* methods
64     *
65     * @param a semimajor radius of the ellipsoid axis
66     * @param b semiminor radius of the ellipsoid axis
67     * @param e first eccentricity of the ellipsoid ( = sqrt((a*a - b*b)/(a*a)))
68     * @param e2 first eccentricity squared
69     * @param eb2 square of the second eccentricity
70     */
71    private Ellipsoid(double a, double b, double e, double e2, double eb2) {
72        this.a = a;
73        this.b = b;
74        this.e = e;
75        this.e2 = e2;
76        this.eb2 = eb2;
77    }
78
79    /**
80     * create a new ellipsoid
81     *
82     * @param a semimajor radius of the ellipsoid axis (in meters)
83     * @param b semiminor radius of the ellipsoid axis (in meters)
84     */
85    public static Ellipsoid create_a_b(double a, double b) {
86        double e2 = (a*a - b*b) / (a*a);
87        double e = Math.sqrt(e2);
88        double eb2 = e2 / (1.0 - e2);
89        return new Ellipsoid(a, b, e, e2, eb2);
90    }
91
92    /**
93     * create a new ellipsoid
94     *
95     * @param a semimajor radius of the ellipsoid axis (in meters)
96     * @param es first eccentricity squared
97     */
98    public static Ellipsoid create_a_es(double a, double es) {
99        double b = a * Math.sqrt(1.0 - es);
100        double e = Math.sqrt(es);
101        double eb2 = es / (1.0 - es);
102        return new Ellipsoid(a, b, e, es, eb2);
103    }
104
105    /**
106     * create a new ellipsoid
107     *
108     * @param a semimajor radius of the ellipsoid axis (in meters)
109     * @param f flattening ( = (a - b) / a)
110     */
111    public static Ellipsoid create_a_f(double a, double f) {
112        double b = a * (1.0 - f);
113        double e2 = f * (2 - f);
114        double e = Math.sqrt(e2);
115        double eb2 = e2 / (1.0 - e2);
116        return new Ellipsoid(a, b, e, e2, eb2);
117    }
118
119    /**
120     * create a new ellipsoid
121     *
122     * @param a semimajor radius of the ellipsoid axis (in meters)
123     * @param rf inverse flattening
124     */
125    public static Ellipsoid create_a_rf(double a, double rf) {
126        return create_a_f(a, 1.0 / rf);
127    }
128
129    @Override
130    public String toString() {
131        return "Ellipsoid{a="+a+", b="+b+"}";
132    }
133
134    /**
135     * Returns the <i>radius of curvature in the prime vertical</i>
136     * for this reference ellipsoid at the specified latitude.
137     *
138     * @param phi The local latitude (radians).
139     * @return The radius of curvature in the prime vertical (meters).
140     */
141    public double verticalRadiusOfCurvature(final double phi) {
142        return a / Math.sqrt(1.0 - (e2 * sqr(Math.sin(phi))));
143    }
144
145    private static double sqr(final double x) {
146        return x * x;
147    }
148
149    /**
150     *  Returns the meridional arc, the true meridional distance on the
151     * ellipsoid from the equator to the specified latitude, in meters.
152     *
153     * @param phi   The local latitude (in radians).
154     * @return  The meridional arc (in meters).
155     */
156    public double meridionalArc(final double phi) {
157        final double sin2Phi = Math.sin(2.0 * phi);
158        final double sin4Phi = Math.sin(4.0 * phi);
159        final double sin6Phi = Math.sin(6.0 * phi);
160        final double sin8Phi = Math.sin(8.0 * phi);
161        // TODO . calculate 'f'
162        //double f = 1.0 / 298.257222101; // GRS80
163        double f = 1.0 / 298.257223563; // WGS84
164        final double n = f / (2.0 - f);
165        final double n2 = n * n;
166        final double n3 = n2 * n;
167        final double n4 = n3 * n;
168        final double n5 = n4 * n;
169        final double n1n2 = n - n2;
170        final double n2n3 = n2 - n3;
171        final double n3n4 = n3 - n4;
172        final double n4n5 = n4 - n5;
173        final double ap = a * (1.0 - n + (5.0 / 4.0) * (n2n3) + (81.0 / 64.0) * (n4n5));
174        final double bp = (3.0 / 2.0) * a * (n1n2 + (7.0 / 8.0) * (n3n4) + (55.0 / 64.0) * n5);
175        final double cp = (15.0 / 16.0) * a * (n2n3 + (3.0 / 4.0) * (n4n5));
176        final double dp = (35.0 / 48.0) * a * (n3n4 + (11.0 / 16.0) * n5);
177        final double ep = (315.0 / 512.0) * a * (n4n5);
178        return ap * phi - bp * sin2Phi + cp * sin4Phi - dp * sin6Phi + ep * sin8Phi;
179    }
180
181    /**
182     *  Returns the <i>radius of curvature in the meridian<i>
183     *  for this reference ellipsoid at the specified latitude.
184     *
185     * @param phi The local latitude (in radians).
186     * @return  The radius of curvature in the meridian (in meters).
187     */
188    public double meridionalRadiusOfCurvature(final double phi) {
189        return verticalRadiusOfCurvature(phi)
190        / (1.0 + eb2 * sqr(Math.cos(phi)));
191    }
192
193    /**
194     * Returns isometric latitude of phi on given first eccentricity (e)
195     * @param phi The local latitude (radians).
196     * @return isometric latitude of phi on first eccentricity (e)
197     */
198    public double latitudeIsometric(double phi, double e) {
199        double v1 = 1-e*Math.sin(phi);
200        double v2 = 1+e*Math.sin(phi);
201        return Math.log(Math.tan(Math.PI/4+phi/2)*Math.pow(v1/v2,e/2));
202    }
203
204    /**
205     * Returns isometric latitude of phi on first eccentricity (e)
206     * @param phi The local latitude (radians).
207     * @return isometric latitude of phi on first eccentricity (e)
208     */
209    public double latitudeIsometric(double phi) {
210        double v1 = 1-e*Math.sin(phi);
211        double v2 = 1+e*Math.sin(phi);
212        return Math.log(Math.tan(Math.PI/4+phi/2)*Math.pow(v1/v2,e/2));
213    }
214
215    /*
216     * Returns geographic latitude of isometric latitude of first eccentricity (e)
217     * and epsilon precision
218     */
219    public double latitude(double latIso, double e, double epsilon) {
220        double lat0 = 2*Math.atan(Math.exp(latIso))-Math.PI/2;
221        double lati = lat0;
222        double lati1 = 1.0; // random value to start the iterative processus
223        while(Math.abs(lati1-lati)>=epsilon) {
224            lati = lati1;
225            double v1 = 1+e*Math.sin(lati);
226            double v2 = 1-e*Math.sin(lati);
227            lati1 = 2*Math.atan(Math.pow(v1/v2,e/2)*Math.exp(latIso))-Math.PI/2;
228        }
229        return lati1;
230    }
231
232    /**
233     * convert cartesian coordinates to ellipsoidal coordinates
234     *
235     * @param XYZ the coordinates in meters (X, Y, Z)
236     * @return The corresponding latitude and longitude in degrees
237     */
238    public LatLon cart2LatLon(double[] XYZ) {
239        return cart2LatLon(XYZ, 1e-11);
240    }
241    public LatLon cart2LatLon(double[] XYZ, double epsilon) {
242        double norm = Math.sqrt(XYZ[0] * XYZ[0] + XYZ[1] * XYZ[1]);
243        double lg = 2.0 * Math.atan(XYZ[1] / (XYZ[0] + norm));
244        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])))));
245        double delta = 1.0;
246        while (delta > epsilon) {
247            double s2 = Math.sin(lt);
248            s2 *= s2;
249            double l = Math.atan((XYZ[2] / norm)
250                    / (1.0 - (a * e2 * Math.cos(lt) / (norm * Math.sqrt(1.0 - e2 * s2)))));
251            delta = Math.abs(l - lt);
252            lt = l;
253        }
254        return new LatLon(Math.toDegrees(lt), Math.toDegrees(lg));
255    }
256
257    /**
258     * convert ellipsoidal coordinates to cartesian coordinates
259     *
260     * @param coord The Latitude and longitude in degrees
261     * @return the corresponding (X, Y Z) cartesian coordinates in meters.
262     */
263    public double[] latLon2Cart(LatLon coord) {
264        double phi = Math.toRadians(coord.lat());
265        double lambda = Math.toRadians(coord.lon());
266
267        double Rn = a / Math.sqrt(1 - e2 * Math.pow(Math.sin(phi), 2));
268        double[] XYZ = new double[3];
269        XYZ[0] = Rn * Math.cos(phi) * Math.cos(lambda);
270        XYZ[1] = Rn * Math.cos(phi) * Math.sin(lambda);
271        XYZ[2] = Rn * (1 - e2) * Math.sin(phi);
272
273        return XYZ;
274    }
275}
Note: See TracBrowser for help on using the repository browser.