1 | /******************************************************************************* |
---|
2 | NAME OBLIQUE MERCATOR (HOTINE) |
---|
3 | |
---|
4 | PURPOSE: Transforms input longitude and latitude to Easting and |
---|
5 | Northing for the Oblique Mercator projection. The |
---|
6 | longitude and latitude must be in radians. The Easting |
---|
7 | and Northing values will be returned in meters. |
---|
8 | |
---|
9 | PROGRAMMER DATE |
---|
10 | ---------- ---- |
---|
11 | T. Mittan Mar, 1993 |
---|
12 | |
---|
13 | ALGORITHM REFERENCES |
---|
14 | |
---|
15 | 1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological |
---|
16 | Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United |
---|
17 | State Government Printing Office, Washington D.C., 1987. |
---|
18 | |
---|
19 | 2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections", |
---|
20 | U.S. Geological Survey Professional Paper 1453 , United State Government |
---|
21 | Printing Office, Washington D.C., 1989. |
---|
22 | *******************************************************************************/ |
---|
23 | |
---|
24 | Proj4js.Proj.omerc = { |
---|
25 | |
---|
26 | /* Initialize the Oblique Mercator projection |
---|
27 | ------------------------------------------*/ |
---|
28 | init: function() { |
---|
29 | if (!this.mode) this.mode=0; |
---|
30 | if (!this.lon1) {this.lon1=0;this.mode=1;} |
---|
31 | if (!this.lon2) this.lon2=0; |
---|
32 | if (!this.lat2) this.lat2=0; |
---|
33 | |
---|
34 | /* Place parameters in static storage for common use |
---|
35 | -------------------------------------------------*/ |
---|
36 | var temp = this.b/ this.a; |
---|
37 | var es = 1.0 - Math.pow(temp,2); |
---|
38 | var e = Math.sqrt(es); |
---|
39 | |
---|
40 | this.sin_p20=Math.sin(this.lat0); |
---|
41 | this.cos_p20=Math.cos(this.lat0); |
---|
42 | |
---|
43 | this.con = 1.0 - this.es * this.sin_p20 * this.sin_p20; |
---|
44 | this.com = Math.sqrt(1.0 - es); |
---|
45 | this.bl = Math.sqrt(1.0 + this.es * Math.pow(this.cos_p20,4.0)/(1.0 - es)); |
---|
46 | this.al = this.a * this.bl * this.k0 * this.com / this.con; |
---|
47 | if (Math.abs(this.lat0) < Proj4js.common.EPSLN) { |
---|
48 | this.ts = 1.0; |
---|
49 | this.d = 1.0; |
---|
50 | this.el = 1.0; |
---|
51 | } else { |
---|
52 | this.ts = Proj4js.common.tsfnz(this.e,this.lat0,this.sin_p20); |
---|
53 | this.con = Math.sqrt(this.con); |
---|
54 | this.d = this.bl * this.com / (this.cos_p20 * this.con); |
---|
55 | if ((this.d * this.d - 1.0) > 0.0) { |
---|
56 | if (this.lat0 >= 0.0) { |
---|
57 | this.f = this.d + Math.sqrt(this.d * this.d - 1.0); |
---|
58 | } else { |
---|
59 | this.f = this.d - Math.sqrt(this.d * this.d - 1.0); |
---|
60 | } |
---|
61 | } else { |
---|
62 | this.f = this.d; |
---|
63 | } |
---|
64 | this.el = this.f * Math.pow(this.ts,this.bl); |
---|
65 | } |
---|
66 | |
---|
67 | //this.longc=52.60353916666667; |
---|
68 | |
---|
69 | if (this.mode != 0) { |
---|
70 | this.g = .5 * (this.f - 1.0/this.f); |
---|
71 | this.gama = Proj4js.common.asinz(Math.sin(this.alpha) / this.d); |
---|
72 | this.longc= this.longc - Proj4js.common.asinz(this.g * Math.tan(this.gama))/this.bl; |
---|
73 | |
---|
74 | /* Report parameters common to format B |
---|
75 | -------------------------------------*/ |
---|
76 | //genrpt(azimuth * R2D,"Azimuth of Central Line: "); |
---|
77 | //cenlon(lon_origin); |
---|
78 | // cenlat(lat_origin); |
---|
79 | |
---|
80 | this.con = Math.abs(this.lat0); |
---|
81 | if ((this.con > Proj4js.common.EPSLN) && (Math.abs(this.con - Proj4js.common.HALF_PI) > Proj4js.common.EPSLN)) { |
---|
82 | this.singam=Math.sin(this.gama); |
---|
83 | this.cosgam=Math.cos(this.gama); |
---|
84 | |
---|
85 | this.sinaz=Math.sin(this.alpha); |
---|
86 | this.cosaz=Math.cos(this.alpha); |
---|
87 | |
---|
88 | if (this.lat0>= 0) { |
---|
89 | this.u = (this.al / this.bl) * Math.atan(Math.sqrt(this.d*this.d - 1.0)/this.cosaz); |
---|
90 | } else { |
---|
91 | this.u = -(this.al / this.bl) *Math.atan(Math.sqrt(this.d*this.d - 1.0)/this.cosaz); |
---|
92 | } |
---|
93 | } else { |
---|
94 | Proj4js.reportError("omerc:Init:DataError"); |
---|
95 | } |
---|
96 | } else { |
---|
97 | this.sinphi =Math. sin(this.at1); |
---|
98 | this.ts1 = Proj4js.common.tsfnz(this.e,this.lat1,this.sinphi); |
---|
99 | this.sinphi = Math.sin(this.lat2); |
---|
100 | this.ts2 = Proj4js.common.tsfnz(this.e,this.lat2,this.sinphi); |
---|
101 | this.h = Math.pow(this.ts1,this.bl); |
---|
102 | this.l = Math.pow(this.ts2,this.bl); |
---|
103 | this.f = this.el/this.h; |
---|
104 | this.g = .5 * (this.f - 1.0/this.f); |
---|
105 | this.j = (this.el * this.el - this.l * this.h)/(this.el * this.el + this.l * this.h); |
---|
106 | this.p = (this.l - this.h) / (this.l + this.h); |
---|
107 | this.dlon = this.lon1 - this.lon2; |
---|
108 | if (this.dlon < -Proj4js.common.PI) this.lon2 = this.lon2 - 2.0 * Proj4js.common.PI; |
---|
109 | if (this.dlon > Proj4js.common.PI) this.lon2 = this.lon2 + 2.0 * Proj4js.common.PI; |
---|
110 | this.dlon = this.lon1 - this.lon2; |
---|
111 | this.longc = .5 * (this.lon1 + this.lon2) -Math.atan(this.j * Math.tan(.5 * this.bl * this.dlon)/this.p)/this.bl; |
---|
112 | this.dlon = Proj4js.common.adjust_lon(this.lon1 - this.longc); |
---|
113 | this.gama = Math.atan(Math.sin(this.bl * this.dlon)/this.g); |
---|
114 | this.alpha = Proj4js.common.asinz(this.d * Math.sin(this.gama)); |
---|
115 | |
---|
116 | /* Report parameters common to format A |
---|
117 | -------------------------------------*/ |
---|
118 | |
---|
119 | if (Math.abs(this.lat1 - this.lat2) <= Proj4js.common.EPSLN) { |
---|
120 | Proj4js.reportError("omercInitDataError"); |
---|
121 | //return(202); |
---|
122 | } else { |
---|
123 | this.con = Math.abs(this.lat1); |
---|
124 | } |
---|
125 | if ((this.con <= Proj4js.common.EPSLN) || (Math.abs(this.con - HALF_PI) <= Proj4js.common.EPSLN)) { |
---|
126 | Proj4js.reportError("omercInitDataError"); |
---|
127 | //return(202); |
---|
128 | } else { |
---|
129 | if (Math.abs(Math.abs(this.lat0) - Proj4js.common.HALF_PI) <= Proj4js.common.EPSLN) { |
---|
130 | Proj4js.reportError("omercInitDataError"); |
---|
131 | //return(202); |
---|
132 | } |
---|
133 | } |
---|
134 | |
---|
135 | this.singam=Math.sin(this.gam); |
---|
136 | this.cosgam=Math.cos(this.gam); |
---|
137 | |
---|
138 | this.sinaz=Math.sin(this.alpha); |
---|
139 | this.cosaz=Math.cos(this.alpha); |
---|
140 | |
---|
141 | |
---|
142 | if (this.lat0 >= 0) { |
---|
143 | this.u = (this.al/this.bl) * Math.atan(Math.sqrt(this.d * this.d - 1.0)/this.cosaz); |
---|
144 | } else { |
---|
145 | this.u = -(this.al/this.bl) * Math.atan(Math.sqrt(this.d * this.d - 1.0)/this.cosaz); |
---|
146 | } |
---|
147 | } |
---|
148 | }, |
---|
149 | |
---|
150 | |
---|
151 | /* Oblique Mercator forward equations--mapping lat,long to x,y |
---|
152 | ----------------------------------------------------------*/ |
---|
153 | forward: function(p) { |
---|
154 | var theta; /* angle */ |
---|
155 | var sin_phi, cos_phi;/* sin and cos value */ |
---|
156 | var b; /* temporary values */ |
---|
157 | var c, t, tq; /* temporary values */ |
---|
158 | var con, n, ml; /* cone constant, small m */ |
---|
159 | var q,us,vl; |
---|
160 | var ul,vs; |
---|
161 | var s; |
---|
162 | var dlon; |
---|
163 | var ts1; |
---|
164 | |
---|
165 | var lon=p.x; |
---|
166 | var lat=p.y; |
---|
167 | /* Forward equations |
---|
168 | -----------------*/ |
---|
169 | sin_phi = Math.sin(lat); |
---|
170 | dlon = Proj4js.common.adjust_lon(lon - this.longc); |
---|
171 | vl = Math.sin(this.bl * dlon); |
---|
172 | if (Math.abs(Math.abs(lat) - Proj4js.common.HALF_PI) > Proj4js.common.EPSLN) { |
---|
173 | ts1 = Proj4js.common.tsfnz(this.e,lat,sin_phi); |
---|
174 | q = this.el / (Math.pow(ts1,this.bl)); |
---|
175 | s = .5 * (q - 1.0 / q); |
---|
176 | t = .5 * (q + 1.0/ q); |
---|
177 | ul = (s * this.singam - vl * this.cosgam) / t; |
---|
178 | con = Math.cos(this.bl * dlon); |
---|
179 | if (Math.abs(con) < .0000001) { |
---|
180 | us = this.al * this.bl * dlon; |
---|
181 | } else { |
---|
182 | us = this.al * Math.atan((s * this.cosgam + vl * this.singam) / con)/this.bl; |
---|
183 | if (con < 0) us = us + Proj4js.common.PI * this.al / this.bl; |
---|
184 | } |
---|
185 | } else { |
---|
186 | if (lat >= 0) { |
---|
187 | ul = this.singam; |
---|
188 | } else { |
---|
189 | ul = -this.singam; |
---|
190 | } |
---|
191 | us = this.al * lat / this.bl; |
---|
192 | } |
---|
193 | if (Math.abs(Math.abs(ul) - 1.0) <= Proj4js.common.EPSLN) { |
---|
194 | //alert("Point projects into infinity","omer-for"); |
---|
195 | Proj4js.reportError("omercFwdInfinity"); |
---|
196 | //return(205); |
---|
197 | } |
---|
198 | vs = .5 * this.al * Math.log((1.0 - ul)/(1.0 + ul)) / this.bl; |
---|
199 | us = us - this.u; |
---|
200 | var x = this.x0 + vs * this.cosaz + us * this.sinaz; |
---|
201 | var y = this.y0 + us * this.cosaz - vs * this.sinaz; |
---|
202 | |
---|
203 | p.x=x; |
---|
204 | p.y=y; |
---|
205 | return p; |
---|
206 | }, |
---|
207 | |
---|
208 | inverse: function(p) { |
---|
209 | var delta_lon; /* Delta longitude (Given longitude - center */ |
---|
210 | var theta; /* angle */ |
---|
211 | var delta_theta; /* adjusted longitude */ |
---|
212 | var sin_phi, cos_phi;/* sin and cos value */ |
---|
213 | var b; /* temporary values */ |
---|
214 | var c, t, tq; /* temporary values */ |
---|
215 | var con, n, ml; /* cone constant, small m */ |
---|
216 | var vs,us,q,s,ts1; |
---|
217 | var vl,ul,bs; |
---|
218 | var dlon; |
---|
219 | var flag; |
---|
220 | |
---|
221 | /* Inverse equations |
---|
222 | -----------------*/ |
---|
223 | p.x -= this.x0; |
---|
224 | p.y -= this.y0; |
---|
225 | flag = 0; |
---|
226 | vs = p.x * this.cosaz - p.y * this.sinaz; |
---|
227 | us = p.y * this.cosaz + p.x * this.sinaz; |
---|
228 | us = us + this.u; |
---|
229 | q = Math.exp(-this.bl * vs / this.al); |
---|
230 | s = .5 * (q - 1.0/q); |
---|
231 | t = .5 * (q + 1.0/q); |
---|
232 | vl = Math.sin(this.bl * us / this.al); |
---|
233 | ul = (vl * this.cosgam + s * this.singam)/t; |
---|
234 | if (Math.abs(Math.abs(ul) - 1.0) <= Proj4js.common.EPSLN) |
---|
235 | { |
---|
236 | lon = this.longc; |
---|
237 | if (ul >= 0.0) { |
---|
238 | lat = Proj4js.common.HALF_PI; |
---|
239 | } else { |
---|
240 | lat = -Proj4js.common.HALF_PI; |
---|
241 | } |
---|
242 | } else { |
---|
243 | con = 1.0 / this.bl; |
---|
244 | ts1 =Math.pow((this.el / Math.sqrt((1.0 + ul) / (1.0 - ul))),con); |
---|
245 | lat = Proj4js.common.phi2z(this.e,ts1); |
---|
246 | //if (flag != 0) |
---|
247 | //return(flag); |
---|
248 | //~ con = Math.cos(this.bl * us /al); |
---|
249 | theta = this.longc - Math.atan2((s * this.cosgam - vl * this.singam) , con)/this.bl; |
---|
250 | lon = Proj4js.common.adjust_lon(theta); |
---|
251 | } |
---|
252 | p.x=lon; |
---|
253 | p.y=lat; |
---|
254 | return p; |
---|
255 | } |
---|
256 | }; |
---|