1 | /******************************************************************************* |
---|
2 | NAME TRANSVERSE MERCATOR |
---|
3 | |
---|
4 | PURPOSE: Transforms input longitude and latitude to Easting and |
---|
5 | Northing for the Transverse Mercator projection. The |
---|
6 | longitude and latitude must be in radians. The Easting |
---|
7 | and Northing values will be returned in meters. |
---|
8 | |
---|
9 | ALGORITHM REFERENCES |
---|
10 | |
---|
11 | 1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological |
---|
12 | Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United |
---|
13 | State Government Printing Office, Washington D.C., 1987. |
---|
14 | |
---|
15 | 2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections", |
---|
16 | U.S. Geological Survey Professional Paper 1453 , United State Government |
---|
17 | Printing Office, Washington D.C., 1989. |
---|
18 | *******************************************************************************/ |
---|
19 | |
---|
20 | |
---|
21 | /** |
---|
22 | Initialize Transverse Mercator projection |
---|
23 | */ |
---|
24 | |
---|
25 | Proj4js.Proj.tmerc = { |
---|
26 | init : function() { |
---|
27 | this.e0 = Proj4js.common.e0fn(this.es); |
---|
28 | this.e1 = Proj4js.common.e1fn(this.es); |
---|
29 | this.e2 = Proj4js.common.e2fn(this.es); |
---|
30 | this.e3 = Proj4js.common.e3fn(this.es); |
---|
31 | this.ml0 = this.a * Proj4js.common.mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0); |
---|
32 | }, |
---|
33 | |
---|
34 | /** |
---|
35 | Transverse Mercator Forward - long/lat to x/y |
---|
36 | long/lat in radians |
---|
37 | */ |
---|
38 | forward : function(p) { |
---|
39 | var lon = p.x; |
---|
40 | var lat = p.y; |
---|
41 | |
---|
42 | var delta_lon = Proj4js.common.adjust_lon(lon - this.long0); // Delta longitude |
---|
43 | var con; // cone constant |
---|
44 | var x, y; |
---|
45 | var sin_phi=Math.sin(lat); |
---|
46 | var cos_phi=Math.cos(lat); |
---|
47 | |
---|
48 | if (this.sphere) { /* spherical form */ |
---|
49 | var b = cos_phi * Math.sin(delta_lon); |
---|
50 | if ((Math.abs(Math.abs(b) - 1.0)) < .0000000001) { |
---|
51 | Proj4js.reportError("tmerc:forward: Point projects into infinity"); |
---|
52 | return(93); |
---|
53 | } else { |
---|
54 | x = .5 * this.a * this.k0 * Math.log((1.0 + b)/(1.0 - b)); |
---|
55 | con = Math.acos(cos_phi * Math.cos(delta_lon)/Math.sqrt(1.0 - b*b)); |
---|
56 | if (lat < 0) con = - con; |
---|
57 | y = this.a * this.k0 * (con - this.lat0); |
---|
58 | } |
---|
59 | } else { |
---|
60 | var al = cos_phi * delta_lon; |
---|
61 | var als = Math.pow(al,2); |
---|
62 | var c = this.ep2 * Math.pow(cos_phi,2); |
---|
63 | var tq = Math.tan(lat); |
---|
64 | var t = Math.pow(tq,2); |
---|
65 | con = 1.0 - this.es * Math.pow(sin_phi,2); |
---|
66 | var n = this.a / Math.sqrt(con); |
---|
67 | var ml = this.a * Proj4js.common.mlfn(this.e0, this.e1, this.e2, this.e3, lat); |
---|
68 | |
---|
69 | x = this.k0 * n * al * (1.0 + als / 6.0 * (1.0 - t + c + als / 20.0 * (5.0 - 18.0 * t + Math.pow(t,2) + 72.0 * c - 58.0 * this.ep2))) + this.x0; |
---|
70 | y = this.k0 * (ml - this.ml0 + n * tq * (als * (0.5 + als / 24.0 * (5.0 - t + 9.0 * c + 4.0 * Math.pow(c,2) + als / 30.0 * (61.0 - 58.0 * t + Math.pow(t,2) + 600.0 * c - 330.0 * this.ep2))))) + this.y0; |
---|
71 | |
---|
72 | } |
---|
73 | p.x = x; p.y = y; |
---|
74 | return p; |
---|
75 | }, // tmercFwd() |
---|
76 | |
---|
77 | /** |
---|
78 | Transverse Mercator Inverse - x/y to long/lat |
---|
79 | */ |
---|
80 | inverse : function(p) { |
---|
81 | var con, phi; /* temporary angles */ |
---|
82 | var delta_phi; /* difference between longitudes */ |
---|
83 | var i; |
---|
84 | var max_iter = 6; /* maximun number of iterations */ |
---|
85 | var lat, lon; |
---|
86 | |
---|
87 | if (this.sphere) { /* spherical form */ |
---|
88 | var f = Math.exp(p.x/(this.a * this.k0)); |
---|
89 | var g = .5 * (f - 1/f); |
---|
90 | var temp = this.lat0 + p.y/(this.a * this.k0); |
---|
91 | var h = Math.cos(temp); |
---|
92 | con = Math.sqrt((1.0 - h * h)/(1.0 + g * g)); |
---|
93 | lat = Proj4js.common.asinz(con); |
---|
94 | if (temp < 0) |
---|
95 | lat = -lat; |
---|
96 | if ((g == 0) && (h == 0)) { |
---|
97 | lon = this.long0; |
---|
98 | } else { |
---|
99 | lon = Proj4js.common.adjust_lon(Math.atan2(g,h) + this.long0); |
---|
100 | } |
---|
101 | } else { // ellipsoidal form |
---|
102 | var x = p.x - this.x0; |
---|
103 | var y = p.y - this.y0; |
---|
104 | |
---|
105 | con = (this.ml0 + y / this.k0) / this.a; |
---|
106 | phi = con; |
---|
107 | for (i=0;true;i++) { |
---|
108 | delta_phi=((con + this.e1 * Math.sin(2.0*phi) - this.e2 * Math.sin(4.0*phi) + this.e3 * Math.sin(6.0*phi)) / this.e0) - phi; |
---|
109 | phi += delta_phi; |
---|
110 | if (Math.abs(delta_phi) <= Proj4js.common.EPSLN) break; |
---|
111 | if (i >= max_iter) { |
---|
112 | Proj4js.reportError("tmerc:inverse: Latitude failed to converge"); |
---|
113 | return(95); |
---|
114 | } |
---|
115 | } // for() |
---|
116 | if (Math.abs(phi) < Proj4js.common.HALF_PI) { |
---|
117 | // sincos(phi, &sin_phi, &cos_phi); |
---|
118 | var sin_phi=Math.sin(phi); |
---|
119 | var cos_phi=Math.cos(phi); |
---|
120 | var tan_phi = Math.tan(phi); |
---|
121 | var c = this.ep2 * Math.pow(cos_phi,2); |
---|
122 | var cs = Math.pow(c,2); |
---|
123 | var t = Math.pow(tan_phi,2); |
---|
124 | var ts = Math.pow(t,2); |
---|
125 | con = 1.0 - this.es * Math.pow(sin_phi,2); |
---|
126 | var n = this.a / Math.sqrt(con); |
---|
127 | var r = n * (1.0 - this.es) / con; |
---|
128 | var d = x / (n * this.k0); |
---|
129 | var ds = Math.pow(d,2); |
---|
130 | lat = phi - (n * tan_phi * ds / r) * (0.5 - ds / 24.0 * (5.0 + 3.0 * t + 10.0 * c - 4.0 * cs - 9.0 * this.ep2 - ds / 30.0 * (61.0 + 90.0 * t + 298.0 * c + 45.0 * ts - 252.0 * this.ep2 - 3.0 * cs))); |
---|
131 | lon = Proj4js.common.adjust_lon(this.long0 + (d * (1.0 - ds / 6.0 * (1.0 + 2.0 * t + c - ds / 20.0 * (5.0 - 2.0 * c + 28.0 * t - 3.0 * cs + 8.0 * this.ep2 + 24.0 * ts))) / cos_phi)); |
---|
132 | } else { |
---|
133 | lat = Proj4js.common.HALF_PI * Proj4js.common.sign(y); |
---|
134 | lon = this.long0; |
---|
135 | } |
---|
136 | } |
---|
137 | p.x = lon; |
---|
138 | p.y = lat; |
---|
139 | return p; |
---|
140 | } // tmercInv() |
---|
141 | }; |
---|