Changeset 4285 in josm for trunk/src/org/openstreetmap/josm/data/projection/proj/TransverseMercator.java
- Timestamp:
- 2011-08-07T12:17:39+02:00 (13 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/data/projection/proj
- Files:
-
- 1 added
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/projection/proj/TransverseMercator.java
r4281 r4285 1 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.data.projection; 3 4 import org.openstreetmap.josm.data.coor.EastNorth; 5 import org.openstreetmap.josm.data.coor.LatLon; 2 package org.openstreetmap.josm.data.projection.proj; 3 4 import static java.lang.Math.*; 5 6 import static org.openstreetmap.josm.tools.I18n.tr; 7 8 import org.openstreetmap.josm.data.projection.Ellipsoid; 6 9 7 10 /** 8 * T his is a base class to do projections based on Transverse Mercator projection.11 * Transverse Mercator projection. 9 12 * 10 13 * @author Dirk Stöcker 11 14 * code based on JavaScript from Chuck Taylor 12 15 * 13 * NOTE: Uses polygon approximation to translate to WGS84.14 16 */ 15 public abstract class TransverseMercator implements Projection { 16 17 private final static double UTMScaleFactor = 0.9996; 18 19 private double UTMCentralMeridianRad = 0; 20 private double offsetEastMeters = 500000; 21 private double offsetNorthMeters = 0; 22 23 24 protected void setProjectionParameters(double centralMeridianDegress, double offsetEast, double offsetNorth) 25 { 26 UTMCentralMeridianRad = Math.toRadians(centralMeridianDegress); 27 offsetEastMeters = offsetEast; 28 offsetNorthMeters = offsetNorth; 29 } 30 31 /* 32 * ArcLengthOfMeridian 33 * 34 * Computes the ellipsoidal distance from the equator to a point at a 35 * given latitude. 36 * 37 * Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J., 38 * GPS: Theory and Practice, 3rd ed. New York: Springer-Verlag Wien, 1994. 39 * 40 * Inputs: 41 * phi - Latitude of the point, in radians. 42 * 43 * Globals: 44 * Ellipsoid.GRS80.a - Ellipsoid model major axis. 45 * Ellipsoid.GRS80.b - Ellipsoid model minor axis. 46 * 47 * Returns: 48 * The ellipsoidal distance of the point from the equator, in meters. 49 * 50 */ 51 private double ArcLengthOfMeridian(double phi) 52 { 53 /* Precalculate n */ 54 double n = (Ellipsoid.GRS80.a - Ellipsoid.GRS80.b) / (Ellipsoid.GRS80.a + Ellipsoid.GRS80.b); 55 56 /* Precalculate alpha */ 57 double alpha = ((Ellipsoid.GRS80.a + Ellipsoid.GRS80.b) / 2.0) 58 * (1.0 + (Math.pow (n, 2.0) / 4.0) + (Math.pow (n, 4.0) / 64.0)); 59 60 /* Precalculate beta */ 61 double beta = (-3.0 * n / 2.0) + (9.0 * Math.pow (n, 3.0) / 16.0) 62 + (-3.0 * Math.pow (n, 5.0) / 32.0); 63 64 /* Precalculate gamma */ 65 double gamma = (15.0 * Math.pow (n, 2.0) / 16.0) 66 + (-15.0 * Math.pow (n, 4.0) / 32.0); 67 68 /* Precalculate delta */ 69 double delta = (-35.0 * Math.pow (n, 3.0) / 48.0) 70 + (105.0 * Math.pow (n, 5.0) / 256.0); 71 72 /* Precalculate epsilon */ 73 double epsilon = (315.0 * Math.pow (n, 4.0) / 512.0); 74 75 /* Now calculate the sum of the series and return */ 76 return alpha 77 * (phi + (beta * Math.sin (2.0 * phi)) 78 + (gamma * Math.sin (4.0 * phi)) 79 + (delta * Math.sin (6.0 * phi)) 80 + (epsilon * Math.sin (8.0 * phi))); 81 } 82 83 /* 84 * FootpointLatitude 85 * 86 * Computes the footpoint latitude for use in converting transverse 87 * Mercator coordinates to ellipsoidal coordinates. 88 * 89 * Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J., 90 * GPS: Theory and Practice, 3rd ed. New York: Springer-Verlag Wien, 1994. 91 * 92 * Inputs: 93 * y - The UTM northing coordinate, in meters. 94 * 95 * Returns: 96 * The footpoint latitude, in radians. 97 * 98 */ 99 private double FootpointLatitude(double y) 100 { 101 /* Precalculate n (Eq. 10.18) */ 102 double n = (Ellipsoid.GRS80.a - Ellipsoid.GRS80.b) / (Ellipsoid.GRS80.a + Ellipsoid.GRS80.b); 103 104 /* Precalculate alpha_ (Eq. 10.22) */ 105 /* (Same as alpha in Eq. 10.17) */ 106 double alpha_ = ((Ellipsoid.GRS80.a + Ellipsoid.GRS80.b) / 2.0) 107 * (1 + (Math.pow (n, 2.0) / 4) + (Math.pow (n, 4.0) / 64)); 108 109 /* Precalculate y_ (Eq. 10.23) */ 110 double y_ = y / alpha_; 111 112 /* Precalculate beta_ (Eq. 10.22) */ 113 double beta_ = (3.0 * n / 2.0) + (-27.0 * Math.pow (n, 3.0) / 32.0) 114 + (269.0 * Math.pow (n, 5.0) / 512.0); 115 116 /* Precalculate gamma_ (Eq. 10.22) */ 117 double gamma_ = (21.0 * Math.pow (n, 2.0) / 16.0) 118 + (-55.0 * Math.pow (n, 4.0) / 32.0); 119 120 /* Precalculate delta_ (Eq. 10.22) */ 121 double delta_ = (151.0 * Math.pow (n, 3.0) / 96.0) 122 + (-417.0 * Math.pow (n, 5.0) / 128.0); 123 124 /* Precalculate epsilon_ (Eq. 10.22) */ 125 double epsilon_ = (1097.0 * Math.pow (n, 4.0) / 512.0); 126 127 /* Now calculate the sum of the series (Eq. 10.21) */ 128 return y_ + (beta_ * Math.sin (2.0 * y_)) 129 + (gamma_ * Math.sin (4.0 * y_)) 130 + (delta_ * Math.sin (6.0 * y_)) 131 + (epsilon_ * Math.sin (8.0 * y_)); 132 } 133 134 /* 135 * MapLatLonToXY 136 * 17 public class TransverseMercator implements Proj { 18 19 protected double a, b; 20 21 public TransverseMercator(Ellipsoid ellps) { 22 this.a = ellps.a; 23 this.b = ellps.b; 24 } 25 26 @Override 27 public String getName() { 28 return tr("Transverse Mercator"); 29 } 30 31 @Override 32 public String getProj4Id() { 33 return "tmerc"; 34 } 35 36 /** 137 37 * Converts a latitude/longitude pair to x and y coordinates in the 138 38 * Transverse Mercator projection. Note that Transverse Mercator is not … … 141 41 * Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J., 142 42 * GPS: Theory and Practice, 3rd ed. New York: Springer-Verlag Wien, 1994. 143 * 144 * Inputs: 145 * phi - Latitude of the point, in radians. 146 * lambda - Longitude of the point, in radians. 147 * lambda0 - Longitude of the central meridian to be used, in radians. 148 * 149 * Outputs: 150 * xy - A 2-element array containing the x and y coordinates 151 * of the computed point. 152 * 153 * Returns: 154 * The function does not return a value. 155 * 156 */ 157 public EastNorth mapLatLonToXY(double phi, double lambda, double lambda0) 158 { 43 * 44 * @param phi Latitude of the point, in radians 45 * @param lambda Longitude of the point, in radians 46 * @return A 2-element array containing the x and y coordinates 47 * of the computed point 48 */ 49 @Override 50 public double[] project(double phi, double lambda) { 51 159 52 /* Precalculate ep2 */ 160 double ep2 = ( Math.pow (Ellipsoid.GRS80.a, 2.0) - Math.pow (Ellipsoid.GRS80.b, 2.0)) / Math.pow (Ellipsoid.GRS80.b, 2.0);53 double ep2 = (pow(a, 2.0) - pow(b, 2.0)) / pow(b, 2.0); 161 54 162 55 /* Precalculate nu2 */ 163 double nu2 = ep2 * Math.pow (Math.cos(phi), 2.0);164 165 /* Precalculate N */166 double N = Math.pow (Ellipsoid.GRS80.a, 2.0) / (Ellipsoid.GRS80.b * Math.sqrt(1 + nu2));56 double nu2 = ep2 * pow(cos(phi), 2.0); 57 58 /* Precalculate N / a */ 59 double N_a = a / (b * sqrt(1 + nu2)); 167 60 168 61 /* Precalculate t */ 169 double t = Math.tan(phi);62 double t = tan(phi); 170 63 double t2 = t * t; 171 64 172 65 /* Precalculate l */ 173 double l = lambda - lambda0;66 double l = lambda; 174 67 175 68 /* Precalculate coefficients for l**n in the equations below … … 191 84 double l8coef = 1385.0 - 3111.0 * t2 + 543.0 * (t2 * t2) - (t2 * t2 * t2); 192 85 193 return new EastNorth(86 return new double[] { 194 87 /* Calculate easting (x) */ 195 N * Math.cos(phi) * l196 + (N / 6.0 * Math.pow (Math.cos (phi), 3.0) * l3coef * Math.pow(l, 3.0))197 + (N / 120.0 * Math.pow (Math.cos (phi), 5.0) * l5coef * Math.pow(l, 5.0))198 + (N / 5040.0 * Math.pow (Math.cos (phi), 7.0) * l7coef * Math.pow(l, 7.0)),88 N_a * cos(phi) * l 89 + (N_a / 6.0 * pow(cos(phi), 3.0) * l3coef * pow(l, 3.0)) 90 + (N_a / 120.0 * pow(cos(phi), 5.0) * l5coef * pow(l, 5.0)) 91 + (N_a / 5040.0 * pow(cos(phi), 7.0) * l7coef * pow(l, 7.0)), 199 92 /* Calculate northing (y) */ 200 ArcLengthOfMeridian (phi) 201 + (t / 2.0 * N * Math.pow (Math.cos (phi), 2.0) * Math.pow (l, 2.0)) 202 + (t / 24.0 * N * Math.pow (Math.cos (phi), 4.0) * l4coef * Math.pow (l, 4.0)) 203 + (t / 720.0 * N * Math.pow (Math.cos (phi), 6.0) * l6coef * Math.pow (l, 6.0)) 204 + (t / 40320.0 * N * Math.pow (Math.cos (phi), 8.0) * l8coef * Math.pow (l, 8.0))); 205 } 206 207 /* 208 * MapXYToLatLon 209 * 93 ArcLengthOfMeridian (phi) / a 94 + (t / 2.0 * N_a * pow(cos(phi), 2.0) * pow(l, 2.0)) 95 + (t / 24.0 * N_a * pow(cos(phi), 4.0) * l4coef * pow(l, 4.0)) 96 + (t / 720.0 * N_a * pow(cos(phi), 6.0) * l6coef * pow(l, 6.0)) 97 + (t / 40320.0 * N_a * pow(cos(phi), 8.0) * l8coef * pow(l, 8.0)) }; 98 } 99 100 /** 210 101 * Converts x and y coordinates in the Transverse Mercator projection to 211 102 * a latitude/longitude pair. Note that Transverse Mercator is not … … 214 105 * Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J., 215 106 * GPS: Theory and Practice, 3rd ed. New York: Springer-Verlag Wien, 1994. 216 * 217 * Inputs: 218 * x - The easting of the point, in meters. 219 * y - The northing of the point, in meters. 220 * lambda0 - Longitude of the central meridian to be used, in radians. 221 * 222 * Outputs: 223 * philambda - A 2-element containing the latitude and longitude 224 * in radians. 225 * 226 * Returns: 227 * The function does not return a value. 228 * 107 * 229 108 * Remarks: 230 109 * The local variables Nf, nuf2, tf, and tf2 serve the same purpose as … … 234 113 * x1frac, x2frac, x2poly, x3poly, etc. are to enhance readability and 235 114 * to optimize computations. 236 * 237 */ 238 public LatLon mapXYToLatLon(double x, double y, double lambda0) 239 { 115 * 116 * @param x The easting of the point, in meters, divided by the semi major axis of the ellipsoid 117 * @param y The northing of the point, in meters, divided by the semi major axis of the ellipsoid 118 * @return A 2-element containing the latitude and longitude 119 * in radians 120 */ 121 @Override 122 public double[] invproject(double x, double y) { 240 123 /* Get the value of phif, the footpoint latitude. */ 241 double phif = FootpointLatitude(y);124 double phif = footpointLatitude(y); 242 125 243 126 /* Precalculate ep2 */ 244 double ep2 = ( Math.pow (Ellipsoid.GRS80.a, 2.0) - Math.pow (Ellipsoid.GRS80.b, 2.0))245 / Math.pow (Ellipsoid.GRS80.b, 2.0);246 247 /* Precalculate cos 248 double cf = Math.cos(phif);127 double ep2 = (a*a - b*b) 128 / (b*b); 129 130 /* Precalculate cos(phif) */ 131 double cf = cos(phif); 249 132 250 133 /* Precalculate nuf2 */ 251 double nuf2 = ep2 * Math.pow(cf, 2.0);252 253 /* Precalculate Nf and initialize Nfpow */254 double Nf = Math.pow (Ellipsoid.GRS80.a, 2.0) / (Ellipsoid.GRS80.b * Math.sqrt(1 + nuf2));255 double Nfpow = Nf ;134 double nuf2 = ep2 * pow(cf, 2.0); 135 136 /* Precalculate Nf / a and initialize Nfpow */ 137 double Nf_a = a / (b * sqrt(1 + nuf2)); 138 double Nfpow = Nf_a; 256 139 257 140 /* Precalculate tf */ 258 double tf = Math.tan(phif);141 double tf = tan(phif); 259 142 double tf2 = tf * tf; 260 143 double tf4 = tf2 * tf2; … … 264 147 double x1frac = 1.0 / (Nfpow * cf); 265 148 266 Nfpow *= Nf ; /* now equals Nf**2) */149 Nfpow *= Nf_a; /* now equals Nf**2) */ 267 150 double x2frac = tf / (2.0 * Nfpow); 268 151 269 Nfpow *= Nf ; /* now equals Nf**3) */152 Nfpow *= Nf_a; /* now equals Nf**3) */ 270 153 double x3frac = 1.0 / (6.0 * Nfpow * cf); 271 154 272 Nfpow *= Nf ; /* now equals Nf**4) */155 Nfpow *= Nf_a; /* now equals Nf**4) */ 273 156 double x4frac = tf / (24.0 * Nfpow); 274 157 275 Nfpow *= Nf ; /* now equals Nf**5) */158 Nfpow *= Nf_a; /* now equals Nf**5) */ 276 159 double x5frac = 1.0 / (120.0 * Nfpow * cf); 277 160 278 Nfpow *= Nf ; /* now equals Nf**6) */161 Nfpow *= Nf_a; /* now equals Nf**6) */ 279 162 double x6frac = tf / (720.0 * Nfpow); 280 163 281 Nfpow *= Nf ; /* now equals Nf**7) */164 Nfpow *= Nf_a; /* now equals Nf**7) */ 282 165 double x7frac = 1.0 / (5040.0 * Nfpow * cf); 283 166 284 Nfpow *= Nf ; /* now equals Nf**8) */167 Nfpow *= Nf_a; /* now equals Nf**8) */ 285 168 double x8frac = tf / (40320.0 * Nfpow); 286 169 … … 295 178 double x8poly = 1385.0 + 3633.0 * tf2 + 4095.0 * tf4 + 1575 * (tf4 * tf2); 296 179 297 return new LatLon(180 return new double[] { 298 181 /* Calculate latitude */ 299 Math.toDegrees(300 182 phif + x2frac * x2poly * (x * x) 301 + x4frac * x4poly * Math.pow (x, 4.0) 302 + x6frac * x6poly * Math.pow (x, 6.0) 303 + x8frac * x8poly * Math.pow (x, 8.0)), 304 Math.toDegrees( 305 /* Calculate longitude */ 306 lambda0 + x1frac * x 307 + x3frac * x3poly * Math.pow (x, 3.0) 308 + x5frac * x5poly * Math.pow (x, 5.0) 309 + x7frac * x7poly * Math.pow (x, 7.0))); 310 } 311 312 @Override 313 public EastNorth latlon2eastNorth(LatLon p) { 314 EastNorth a = mapLatLonToXY(Math.toRadians(p.lat()), Math.toRadians(p.lon()), UTMCentralMeridianRad); 315 return new EastNorth(a.east() * UTMScaleFactor + offsetEastMeters, a.north() * UTMScaleFactor + offsetNorthMeters); 316 } 317 318 @Override 319 public LatLon eastNorth2latlon(EastNorth p) { 320 return mapXYToLatLon((p.east() - offsetEastMeters)/UTMScaleFactor, (p.north() - offsetNorthMeters)/UTMScaleFactor, UTMCentralMeridianRad); 321 } 322 323 @Override 324 public double getDefaultZoomInPPD() { 325 // this will set the map scaler to about 1000 m 326 return 10; 327 } 183 + x4frac * x4poly * pow(x, 4.0) 184 + x6frac * x6poly * pow(x, 6.0) 185 + x8frac * x8poly * pow(x, 8.0), 186 /* Calculate longitude */ 187 x1frac * x 188 + x3frac * x3poly * pow(x, 3.0) 189 + x5frac * x5poly * pow(x, 5.0) 190 + x7frac * x7poly * pow(x, 7.0) }; 191 } 192 193 /** 194 * ArcLengthOfMeridian 195 * 196 * Computes the ellipsoidal distance from the equator to a point at a 197 * given latitude. 198 * 199 * Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J., 200 * GPS: Theory and Practice, 3rd ed. New York: Springer-Verlag Wien, 1994. 201 * 202 * @param phi Latitude of the point, in radians 203 * @return The ellipsoidal distance of the point from the equator 204 * (in meters, divided by the semi major axis of the ellipsoid) 205 */ 206 private double ArcLengthOfMeridian(double phi) { 207 /* Precalculate n */ 208 double n = (a - b) / (a + b); 209 210 /* Precalculate alpha */ 211 double alpha = ((a + b) / 2.0) 212 * (1.0 + (pow(n, 2.0) / 4.0) + (pow(n, 4.0) / 64.0)); 213 214 /* Precalculate beta */ 215 double beta = (-3.0 * n / 2.0) + (9.0 * pow(n, 3.0) / 16.0) 216 + (-3.0 * pow(n, 5.0) / 32.0); 217 218 /* Precalculate gamma */ 219 double gamma = (15.0 * pow(n, 2.0) / 16.0) 220 + (-15.0 * pow(n, 4.0) / 32.0); 221 222 /* Precalculate delta */ 223 double delta = (-35.0 * pow(n, 3.0) / 48.0) 224 + (105.0 * pow(n, 5.0) / 256.0); 225 226 /* Precalculate epsilon */ 227 double epsilon = (315.0 * pow(n, 4.0) / 512.0); 228 229 /* Now calculate the sum of the series and return */ 230 return alpha 231 * (phi + (beta * sin(2.0 * phi)) 232 + (gamma * sin(4.0 * phi)) 233 + (delta * sin(6.0 * phi)) 234 + (epsilon * sin(8.0 * phi))); 235 } 236 237 /** 238 * FootpointLatitude 239 * 240 * Computes the footpoint latitude for use in converting transverse 241 * Mercator coordinates to ellipsoidal coordinates. 242 * 243 * Reference: Hoffmann-Wellenhof, B., Lichtenegger, H., and Collins, J., 244 * GPS: Theory and Practice, 3rd ed. New York: Springer-Verlag Wien, 1994. 245 * 246 * @param y northing coordinate, in meters, divided by the semi major axis of the ellipsoid 247 * @return The footpoint latitude, in radians 248 */ 249 private double footpointLatitude(double y) { 250 /* Precalculate n (Eq. 10.18) */ 251 double n = (a - b) / (a + b); 252 253 /* Precalculate alpha_ (Eq. 10.22) */ 254 /* (Same as alpha in Eq. 10.17) */ 255 double alpha_ = ((a + b) / 2.0) 256 * (1 + (pow(n, 2.0) / 4) + (pow(n, 4.0) / 64)); 257 258 /* Precalculate y_ (Eq. 10.23) */ 259 double y_ = y / alpha_ * a; 260 261 /* Precalculate beta_ (Eq. 10.22) */ 262 double beta_ = (3.0 * n / 2.0) + (-27.0 * pow(n, 3.0) / 32.0) 263 + (269.0 * pow(n, 5.0) / 512.0); 264 265 /* Precalculate gamma_ (Eq. 10.22) */ 266 double gamma_ = (21.0 * pow(n, 2.0) / 16.0) 267 + (-55.0 * pow(n, 4.0) / 32.0); 268 269 /* Precalculate delta_ (Eq. 10.22) */ 270 double delta_ = (151.0 * pow(n, 3.0) / 96.0) 271 + (-417.0 * pow(n, 5.0) / 128.0); 272 273 /* Precalculate epsilon_ (Eq. 10.22) */ 274 double epsilon_ = (1097.0 * pow(n, 4.0) / 512.0); 275 276 /* Now calculate the sum of the series (Eq. 10.21) */ 277 return y_ + (beta_ * sin(2.0 * y_)) 278 + (gamma_ * sin(4.0 * y_)) 279 + (delta_ * sin(6.0 * y_)) 280 + (epsilon_ * sin(8.0 * y_)); 281 } 282 328 283 }
Note:
See TracChangeset
for help on using the changeset viewer.