[76] | 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 | }; |
---|