source: josm/trunk/src/org/openstreetmap/josm/data/projection/proj/PolarStereographic.java@ 9419

Last change on this file since 9419 was 9419, checked in by bastiK, 8 years ago

add Albers Equal Area Projection and Polar Stereographic Projection (see #12186)
(imports pieces of code from the Geotools project)

  • Property svn:eol-style set to native
File size: 6.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.projection.proj;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import org.openstreetmap.josm.data.Bounds;
7import org.openstreetmap.josm.data.projection.ProjectionConfigurationException;
8
9/**
10 * The polar case of the {@linkplain Stereographic stereographic} projection.
11 * <p>
12 * In the proj.4 library, the code "stere" covers several variants of the
13 * Stereographic projection, depending on the latitude of natural origin
14 * (parameter lat_0).
15 * <p>
16 *
17 * In this file, only the polar case is implemented. This corresponds to
18 * EPSG:9810 (Polar Stereographic Variant A) and EPSG:9829 (Polar Stereographic
19 * Variant B).
20 * <p>
21 *
22 * It is required, that the latitude of natural origin has the value +/-90 degrees.
23 * <p>
24 *
25 * This class has been derived from the implementation of the Geotools project;
26 * git 8cbf52d, org.geotools.referencing.operation.projection.PolarStereographic
27 * at the time of migration.
28 * <p>
29 *
30 * <b>References:</b>
31 * <ul>
32 * <li>John P. Snyder (Map Projections - A Working Manual,<br>
33 * U.S. Geological Survey Professional Paper 1395, 1987)</li>
34 * <li>"Coordinate Conversions and Transformations including Formulas",<br>
35 * EPSG Guidence Note Number 7, Version 19.</li>
36 * <li>Gerald Evenden. <A HREF="http://members.bellatlantic.net/~vze2hc4d/proj4/sterea.pdf">
37 * "Supplementary PROJ.4 Notes - Oblique Stereographic Alternative"</A></li>
38 * <li>Krakiwsky, E.J., D.B. Thomson, and R.R. Steeves. 1977. A Manual
39 * For Geodetic Coordinate Transformations in the Maritimes.
40 * Geodesy and Geomatics Engineering, UNB. Technical Report No. 48.</li>
41 * <li>Thomson, D.B., M.P. Mepham and R.R. Steeves. 1977.
42 * The Stereographic Double Projection.
43 * Geodesy and Geomatics Engineereng, UNB. Technical Report No. 46.</li>
44 * </ul>
45 *
46 * @see <A HREF="http://mathworld.wolfram.com/StereographicProjection.html">Stereographic projection on MathWorld</A>
47 * @see <A HREF="http://www.remotesensing.org/geotiff/proj_list/polar_stereographic.html">Polar_Stereographic</A>
48 * @see <A HREF="http://www.remotesensing.org/geotiff/proj_list/oblique_stereographic.html">Oblique_Stereographic</A>
49 * @see <A HREF="http://www.remotesensing.org/geotiff/proj_list/stereographic.html">Stereographic</A>
50 * @see <A HREF="http://www.remotesensing.org/geotiff/proj_list/random_issues.html#stereographic">Some Random Stereographic Issues</A>
51 *
52 * @see DoubleStereographic
53 *
54 * @author André Gosselin
55 * @author Martin Desruisseaux (PMO, IRD)
56 * @author Rueben Schulz
57 */
58public class PolarStereographic extends AbstractProj implements IPolar {
59 /**
60 * Maximum number of iterations for iterative computations.
61 */
62 private static final int MAXIMUM_ITERATIONS = 15;
63
64 /**
65 * Difference allowed in iterative computations.
66 */
67 private static final double ITERATION_TOLERANCE = 1E-10;
68
69 /**
70 * Maximum difference allowed when comparing real numbers.
71 */
72 private static final double EPSILON = 1E-8;
73
74 /**
75 * A constant used in the transformations.
76 * This is <strong>not</strong> equal to the {@link #scaleFactor}.
77 */
78 private double k0;
79
80 /**
81 * Latitude of true scale, in radians
82 */
83 private double latitudeTrueScale;
84
85 /**
86 * {@code true} if this projection is for the south pole, or {@code false}
87 * if it is for the north pole.
88 */
89 boolean southPole;
90
91 @Override
92 public String getName() {
93 return tr("Polar Stereographic");
94 }
95
96 @Override
97 public String getProj4Id() {
98 return "stere";
99 }
100
101 @Override
102 public void initialize(ProjParameters params) throws ProjectionConfigurationException {
103 super.initialize(params);
104 if (params.lat0 == null)
105 throw new ProjectionConfigurationException(tr("Parameter ''{0}'' required.", "lat_0"));
106 if (params.lat0 != 90.0 && params.lat0 != -90.0)
107 throw new ProjectionConfigurationException(
108 tr("Polar Stereographic: Parameter ''{0}'' must be 90 or -90.", "lat_0"));
109 if (params.lat_ts == null) {
110 latitudeTrueScale = (params.lat0 < 0) ? -Math.PI/2 : Math.PI/2;
111 } else {
112 latitudeTrueScale = Math.toRadians(params.lat_ts);
113 }
114 southPole = latitudeTrueScale < 0;
115
116 /*
117 * Computes coefficients.
118 */
119 double latitudeTrueScaleAbs = Math.abs(latitudeTrueScale);
120 if (Math.abs(latitudeTrueScaleAbs - Math.PI/2) >= EPSILON) {
121 final double t = Math.sin(latitudeTrueScaleAbs);
122 k0 = msfn(t, Math.cos(latitudeTrueScaleAbs)) /
123 tsfn(latitudeTrueScaleAbs, t); // Derives from (21-32 and 21-33)
124 } else {
125 // True scale at pole (part of (21-33))
126 k0 = 2.0 / Math.sqrt(Math.pow(1+e, 1+e)*
127 Math.pow(1-e, 1-e));
128 }
129 }
130
131 @Override
132 public double[] project(double y, double x) {
133 final double sinlat = Math.sin(y);
134 final double coslon = Math.cos(x);
135 final double sinlon = Math.sin(x);
136 if (southPole) {
137 final double rho = k0 * tsfn(-y, -sinlat);
138 x = rho * sinlon;
139 y = rho * coslon;
140 } else {
141 final double rho = k0 * tsfn(y, sinlat);
142 x = rho * sinlon;
143 y = -rho * coslon;
144 }
145 return new double[] {x, y};
146 }
147
148 @Override
149 public double[] invproject(double x, double y) {
150 final double rho = Math.hypot(x, y);
151 if (southPole) {
152 y = -y;
153 }
154 /*
155 * Compute latitude using iterative technique.
156 */
157 final double t = rho/k0;
158 final double halfe = e/2.0;
159 double phi0 = 0;
160 for (int i=MAXIMUM_ITERATIONS;;) {
161 final double esinphi = e * Math.sin(phi0);
162 final double phi = (Math.PI/2) - 2.0*Math.atan(t*Math.pow((1-esinphi)/(1+esinphi), halfe));
163 if (Math.abs(phi-phi0) < ITERATION_TOLERANCE) {
164 x = (Math.abs(rho) < EPSILON) ? 0.0 : Math.atan2(x, -y);
165 y = (southPole) ? -phi : phi;
166 break;
167 }
168 phi0 = phi;
169 if (--i < 0) {
170 throw new RuntimeException("no convergence");
171 }
172 }
173 return new double[] {y, x};
174 }
175
176 @Override
177 public Bounds getAlgorithmBounds() {
178 final double CUT = 60;
179 if (southPole) {
180 return new Bounds(-90, -180, CUT, 180, false);
181 } else {
182 return new Bounds(-CUT, -180, 90, 180, false);
183 }
184 }
185
186 @Override
187 public boolean hasPole(boolean south) {
188 return south == southPole;
189 }
190}
Note: See TracBrowser for help on using the repository browser.