PageSourceSearch

https://mytehran.ir/assets/map/utmconvertor.js

js mytehran.ir collected 2026-10-02 22:06:37 UTC 15,618 bytes, 363 lines download raw bytes

1///
2/// A UTM -> Lat/Long (or vice versa) converter adapted from the script used at 
3///     http://www.uwgb.edu/dutchs/UsefulData/ConvertUTMNoOZ.HTM
4/// I've taken the calculations portion of his script and turned it into a singleton
5/// javascript object so that it is no longer dependent on the controls used on the page
6/// to use this script, call setDatum with the index of the datum to be used and then
7/// call the various conversion functions latLngToUtm(), utmToLatLng() or natoToLatLng(), utmToNato(), natoToUtm()
8/// to convert between the various coordinate systems, hopefully accurately!
9///
10/// NOTE: no attempt is made to compensate for the irregular grid in the area around the southern coast of Norway and
11/// Svalbard (zones 32V and 31X, 33X, 35X and 37X) because of this results returned for NATO coordinates for lat/lng or
12/// UTM values located in these regions will not be correct.
13///
14var utmconv = {
15    //
16    // constants taken from or calculated from the datum
17    //
18    a: 0,   // equatorial radius in meters
19    f: 0,   // polar flattening
20    b: 0,   // polar radius in meters
21    e: 0,   // eccentricity
22    e0: 0,  // e'
23
24
25    //
26    // constants used in calculations
27    //
28    k: 1,
29    k0: 0.9996,
30    drad: Math.PI / 180,
31
32    digraphLettersE: "ABCDEFGHJKLMNPQRSTUVWXYZ",
33    digraphLettersN: "ABCDEFGHJKLMNPQRSTUV",
34    digraphLettersAll: "ABCDEFGHJKLMNPQRSTUVABCDEFGHJKLMNPQRSTUVABCDEFGHJKLMNPQRSTUVABCDEFGHJKLMNPQRSTUVABCDEFGHJKLMNPQRSTUVABCDEFGHJKLMNPQRSTUVABCDEFGHJKLMNPQRSTUVABCDEFGHJKLMNPQRSTUVABCDEFGHJKLMNPQRSTUVABCDEFGHJKLMNPQRSTUV",
35    datumTable: [
36        { eqRad: 6378137.0, flat: 298.2572236 },    // WGS 84
37        { eqRad: 6378137.0, flat: 298.2572236 },    // NAD 83
38        { eqRad: 6378137.0, flat: 298.2572215 },    // GRS 80
39        { eqRad: 6378135.0, flat: 298.2597208 },    // WGS 72
40        { eqRad: 6378160.0, flat: 298.2497323 },    // Austrailian 1965
41        { eqRad: 6378245.0, flat: 298.2997381 },    // Krasovsky 1940
42        { eqRad: 6378206.4, flat: 294.9786982 },    // North American 1927
43        { eqRad: 6378388.0, flat: 296.9993621 },    // International 1924
44        { eqRad: 6378388.0, flat: 296.9993621 },    // Hayford 1909
45        { eqRad: 6378249.1, flat: 293.4660167 },    // Clarke 1880
46        { eqRad: 6378206.4, flat: 294.9786982 },    // Clarke 1866
47        { eqRad: 6377563.4, flat: 299.3247788 },    // Airy 1830
48        { eqRad: 6377397.2, flat: 299.1527052 },    // Bessel 1841
49        { eqRad: 6377276.3, flat: 300.8021499 }     // Everest 1830
50    ],
51
52    ///
53    /// calculate constants used for doing conversions using a given map datum
54    ///
55    setDatum: function (index) {
56        var datum = this.datumTable[index];
57        this.a = datum.eqRad;
58        this.f = 1 / datum.flat;
59        this.b = this.a * (1 - this.f);   // polar radius
60        this.e = Math.sqrt(1 - Math.pow(this.b, 2) / Math.pow(this.a, 2));
61        this.e0 = this.e / Math.sqrt(1 - Math.pow(this.e, 1));
62    },
63
64    ///
65    /// given a lat/lng pair, returns both global UTM and NATO UTM in the following form:
66    /// utm:
67    /// { 
68    ///     global: { northing: n, easting: e, zone: z, southern: x },
69    ///     nato: { northing: n, easting: e, latzone: z0, lngzone: z1, digraph: xx }
70    /// } 
71    ///
72    /// this function assumes that all data validation has been performed prior to calling
73    /// it.
74    ///
75    latLngToUtm: function (lat, lngd) {
76        var phi = lat * this.drad;                              // convert latitude to radians
77        var lng = lngd * this.drad;                             // convert longitude to radians
78        var utmz = 1 + Math.floor((lngd + 180) / 6);            // longitude to utm zone
79        var zcm = 3 + 6 * (utmz - 1) - 180;                     // central meridian of a zone
80        var latz = 0;                                           // this gives us zone A-B for below 80S
81        var esq = (1 - (this.b / this.a) * (this.b / this.a));
82        var e0sq = this.e * this.e / (1 - Math.pow(this.e, 2));
83        var M = 0;
84
85        // convert latitude to latitude zone for nato
86        if (lat > -80 && lat < 72) {
87            latz = Math.floor((lat + 80) / 8) + 2;      // zones C-W in this range
88        } if (lat > 72 && lat < 84) {
89            latz = 21;                                  // zone X
90        } else if (lat > 84) {
91            latz = 23;                                  // zone Y-Z
92        }
93
94        var N = this.a / Math.sqrt(1 - Math.pow(this.e * Math.sin(phi), 2));
95        var T = Math.pow(Math.tan(phi), 2);
96        var C = e0sq * Math.pow(Math.cos(phi), 2);
97        var A = (lngd - zcm) * this.drad * Math.cos(phi);
98
99        // calculate M (USGS style)
100        M = phi * (1 - esq * (1 / 4 + esq * (3 / 64 + 5 * esq / 256)));
101        M = M - Math.sin(2 * phi) * (esq * (3 / 8 + esq * (3 / 32 + 45 * esq / 1024)));
102        M = M + Math.sin(4 * phi) * (esq * esq * (15 / 256 + esq * 45 / 1024));
103        M = M - Math.sin(6 * phi) * (esq * esq * esq * (35 / 3072));
104        M = M * this.a;                                      //Arc length along standard meridian
105
106        M0 = 0;                                         // if another point of origin is used than the equator
107
108        // now we are ready to calculate the UTM values...
109        // first the easting
110        var x = this.k0 * N * A * (1 + A * A * ((1 - T + C) / 6 + A * A * (5 - 18 * T + T * T + 72 * C - 58 * e0sq) / 120)); //Easting relative to CM
111        x = x + 500000; // standard easting
112
113        // now the northing
114        y = this.k0 * (M - M0 + N * Math.tan(phi) * (A * A * (1 / 2 + A * A * ((5 - T + 9 * C + 4 * C * C) / 24 + A * A * (61 - 58 * T + T * T + 600 * C - 330 * e0sq) / 720))));    // first from the equator
115        yg = y + 10000000;  //yg = y global, from S. Pole
116        if (y < 0) {
117            y = 10000000 + y;   // add in false northing if south of the equator
118        }
119
120        var digraph = this.makeDigraph(x, y, utmz);
121        var rv = { 
122            global: { 
123                easting: Math.round(10*(x))/10, 
124                northing: Math.round(10*y)/10, 
125                zone: utmz, 
126                southern: phi < 0 
127            }, 
128            nato: { 
129                easting: Math.round(10*(x-100000*Math.floor(x/100000)))/10, 
130                northing: Math.round(10*(y-100000*Math.floor(y/100000)))/10, 
131                latZone: this.digraphLettersN[latz],
132                lngZone: utmz,
133                digraph: digraph
134            }
135        }
136
137        return rv;
138    },
139
140    ///
141    /// convert a set of global UTM coordinates to lat/lng returned as follows
142    ///
143    /// { lat: y, lng: x }
144    ///
145    /// inputs:
146    ///     x: easting
147    ///     y: northing
148    ///     utmz: utm zone
149    ///     southern: bool indicating coords are in southern hemisphere
150    ///
151    utmToLatLng: function(x, y, utmz, southern) {
152        var esq = (1 - (this.b / this.a) * (this.b / this.a));
153        var e0sq = this.e * this.e / (1 - Math.pow(this.e, 2));
154        var zcm = 3 + 6 * (utmz - 1) - 180;                         // Central meridian of zone
155        var e1 = (1 - Math.sqrt(1 - Math.pow(this.e, 2))) / (1 + Math.sqrt(1 - Math.pow(this.e, 2)));
156        var M0 = 0;
157        var M = 0;
158
159        if (!southern)
160            M = M0 + y / this.k0;    // Arc length along standard meridian. 
161        else
162            M = M0 + (y - 10000000) / this.k;
163
164        var mu = M / (this.a * (1 - esq * (1 / 4 + esq * (3 / 64 + 5 * esq / 256))));
165        var phi1 = mu + e1 * (3 / 2 - 27 * e1 * e1 / 32) * Math.sin(2 * mu) + e1 * e1 * (21 / 16 - 55 * e1 * e1 / 32) * Math.sin(4 * mu);   //Footprint Latitude
166        phi1 = phi1 + e1 * e1 * e1 * (Math.sin(6 * mu) * 151 / 96 + e1 * Math.sin(8 * mu) * 1097 / 512);
167        var C1 = e0sq * Math.pow(Math.cos(phi1), 2);
168        var T1 = Math.pow(Math.tan(phi1), 2);
169        var N1 = this.a / Math.sqrt(1 - Math.pow(this.e * Math.sin(phi1), 2));
170        var R1 = N1 * (1 - Math.pow(this.e, 2)) / (1 - Math.pow(this.e * Math.sin(phi1), 2));
171        var D = (x - 500000) / (N1 * this.k0);
172        var phi = (D * D) * (1 / 2 - D * D * (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * e0sq) / 24);
173        phi = phi + Math.pow(D, 6) * (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * e0sq - 3 * C1 * C1) / 720;
174        phi = phi1 - (N1 * Math.tan(phi1) / R1) * phi;
175
176        var lat = Math.floor(1000000 * phi / this.drad) / 1000000;
177        var lng = D * (1 + D * D * ((-1 - 2 * T1 - C1) / 6 + D * D * (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * e0sq + 24 * T1 * T1) / 120)) / Math.cos(phi1);
178        lng = lngd = zcm + lng / this.drad;
179
180        return { lat: lat, lng: lng };
181    },
182
183    ///
184    /// takes a set of NATO style UTM coordinates and converts them to a lat/lng pair.
185    ///
186    /// { lat: y, lng: x }
187    /// 
188    /// inputs:
189    ///     utme: easting
190    ///     utmn: northing
191    ///     utmz: longitudinal zone
192    ///     latz: character representing latitudinal zone
193    ///     digraph: string representing grid
194    ///
195    ///
196    natoToLatLng: function (utme, utmn, utmz, latz, digraph) {
197        var coords = this.natoToUtm(utme, utmn, utmz, latz, digraph);
198        return this.utmToLatLng(coords.easting, coords.northing, coords.zone, coords.southern);
199    },
200
201    ///
202    /// convert a set of nato coordinates to the global system.  returns a structure
203    /// 
204    /// { norhting: y, easting: x, zone: zone, southern: hemisphere }
205    ///
206    /// inputs:
207    ///     utme: easting
208    ///     utmn: northing
209    ///     utmz: longitudinal zone
210    ///     latz: character representing latitudinal zone
211    ///     digraph: string representing grid
212    ///
213    /// checks for digraph validity
214    ///
215    natoToUtm: function (utme, utmn, utmz, latz, digraph) {
216        latz = latz.toUpperCase();
217        digraph = digraph.toUpperCase();
218
219        var eltr = digraph.charAt(0);
220        var nltr = digraph.charAt(1);
221
222        ///
223        /// make sure the digraph is consistent
224        ///
225        if (nltr == "I" || eltr == "O")
226            throw "I and O are not legal digraph characters";
227
228        if (nltr == "W" || nltr == "X" || nltr == "Y" || nltr == "Z")
229            throw "W, X, Y and Z are not legal second characters in a digraph";
230
231        var eidx = this.digraphLettersE.indexOf(eltr);
232        var nidx = this.digraphLettersN.indexOf(nltr);
233
234        if (utmz / 2 == Math.floor(utmz / 2)) {
235            nidx -= 5;  // correction for even numbered zones
236        }
237
238        var ebase = 100000*(1 + eidx - 8 * Math.floor(eidx / 8));
239
240        var latBand = this.digraphLettersE.indexOf(latz);
241        var latBandLow = 8 * latBand - 96;
242        var latBandHigh = 8 * latBand - 88;
243
244        if (latBand < 2) {
245            latBandLow = -90;
246            latBandHigh = -80;
247        } else if (latBand == 21) {
248            latBandLow = 72;
249            latBandHigh = 84;
250        } else if (latBand > 21) {
251            latBandLow = 84;
252            latBandHigh = 90;
253        }
254
255        var lowLetter = Math.floor(100 + 1.11 * latBandLow);
256        var highLetter = Math.round(100 + 1.11 * latBandHigh);
257        var latBandLetters = null;
258        if (utmz / 2 == Math.floor(utmz / 2)) {
259            latBandLetters = this.digraphLettersAll.slice(lowLetter + 5, highLetter + 5);
260        } else {
261            latBandLetters = this.digraphLettersAll.slice(lowLetter, highLetter);
262        }
263        var nbase = 100000 * (lowLetter + latBandLetters.indexOf(nltr));
264
265        var x = ebase + utme;
266        var y = nbase + utmn;
267        if (y > 10000000) {
268            y = y - 10000000;
269        }
270        if (nbase >= 10000000) {
271            y = nbase + utmn - 10000000;
272        }
273
274        var southern = nbase < 10000000;
275
276        return { northing: y, easting: x, zone: utmz, southern: southern };
277    },
278
279    ///
280    /// returns a set of nato coordinates from a set of global UTM coordinates
281    /// return is an object with the following structure:
282    ///     { northing: n, easting: e, latZone: z0, lngZone: z1, digraph: xx }
283    ///
284    /// inputs:
285    ///     x: easting
286    ///     y: northing
287    ///     utmz: the utm zone
288    ///     southern: hemisphere indicator
289    ///
290    utmToNato: function (x, y, utmz, southern) {
291        var esq = (1 - (this.b / this.a) * (this.b / this.a));
292        var e0sq = this.e * this.e / (1 - Math.pow(this.e, 2));
293        var e1 = (1 - Math.sqrt(1 - Math.pow(this.e, 2))) / (1 + Math.sqrt(1 - Math.pow(this.e, 2)));
294        var M0 = 0;
295
296        if (!southern)
297            M = M0 + y / this.k0;    // Arc length along standard meridian. 
298        else
299            M = M0 + (y - 10000000) / this.k;
300
301        //
302        // calculate the latitude so that we can derive the latitude zone
303        //
304        var mu = M / (this.a * (1 - esq * (1 / 4 + esq * (3 / 64 + 5 * esq / 256))));
305        var phi1 = mu + e1 * (3 / 2 - 27 * e1 * e1 / 32) * Math.sin(2 * mu) + e1 * e1 * (21 / 16 - 55 * e1 * e1 / 32) * Math.sin(4 * mu);   //Footprint Latitude
306        phi1 = phi1 + e1 * e1 * e1 * (Math.sin(6 * mu) * 151 / 96 + e1 * Math.sin(8 * mu) * 1097 / 512);
307        var C1 = e0sq * Math.pow(Math.cos(phi1), 2);
308        var T1 = Math.pow(Math.tan(phi1), 2);
309        var N1 = this.a / Math.sqrt(1 - Math.pow(this.e * Math.sin(phi1), 2));
310        var R1 = N1 * (1 - Math.pow(this.e, 2)) / (1 - Math.pow(this.e * Math.sin(phi1), 2));
311        var D = (x - 500000) / (N1 * this.k0);
312        var phi = (D * D) * (1 / 2 - D * D * (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * e0sq) / 24);
313        phi = phi + Math.pow(D, 6) * (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * e0sq - 3 * C1 * C1) / 720;
314        phi = phi1 - (N1 * Math.tan(phi1) / R1) * phi;
315        var lat = Math.floor(1000000 * phi / this.drad) / 1000000;
316
317        // convert latitude to latitude zone for nato
318        if (lat > -80 && lat < 72) {
319            latz = Math.floor((lat + 80) / 8) + 2;      // zones C-W in this range
320        } if (lat > 72 && lat < 84) {
321            latz = 21;                                  // zone X
322        } else if (lat > 84) {
323            latz = 23;                                  // zone Y-Z
324        }
325
326        var digraph = this.makeDigraph(x, y, utmz);
327        x = Math.round(10 * (x - 100000 * Math.floor(x / 100000))) / 10;
328        y = Math.round(10 * (y - 100000 * Math.floor(y / 100000))) / 10;
329
330        return {
331            easting: x,
332            northing: y,
333            latZone: this.digraphLettersN[latz],
334            lngZone: utmz,
335            digraph: digraph
336        }
337    },
338
339    ///
340    /// create a nato grid digraph.
341    ///
342    /// inputs:
343    ///     x: easting
344    ///     y: northing
345    ///     utmz: utm zone
346    ///
347    makeDigraph: function (x, y, utmz) {
348        //
349        // first get the east digraph letter
350        //
351        var letter = Math.floor((utmz - 1) * 8 + (x) / 100000);
352        letter = letter - 24 * Math.floor(letter / 24) - 1;
353        var digraph = this.digraphLettersE.charAt(letter);
354
355        letter = Math.floor(y / 100000);
356        if (utmz / 2 == Math.floor(utmz / 2)) { letter = letter + 5; }
357        letter = letter - 20 * Math.floor(letter / 20);
358        digraph = digraph + this.digraphLettersN.charAt(letter);
359
360        return digraph;
361    }
362}
363window.utmconv = utmconv;

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.