1 | /* |
---|
2 | Author: Mike Adair madairATdmsolutions.ca |
---|
3 | Richard Greenwood rich@greenwoodmap.com |
---|
4 | License: LGPL as per: http://www.gnu.org/copyleft/lesser.html |
---|
5 | |
---|
6 | $Id: Proj.js 2956 2007-07-09 12:17:52Z steven $ |
---|
7 | */ |
---|
8 | |
---|
9 | /** |
---|
10 | * Namespace: Proj4js |
---|
11 | * |
---|
12 | * Proj4js is a JavaScript library to transform point coordinates from one |
---|
13 | * coordinate system to another, including datum transformations. |
---|
14 | * |
---|
15 | * This library is a port of both the Proj.4 and GCTCP C libraries to JavaScript. |
---|
16 | * Enabling these transformations in the browser allows geographic data stored |
---|
17 | * in different projections to be combined in browser-based web mapping |
---|
18 | * applications. |
---|
19 | * |
---|
20 | * Proj4js must have access to coordinate system initialization strings (which |
---|
21 | * are the same as for PROJ.4 command line). Thes can be included in your |
---|
22 | * application using a <script> tag or Proj4js can load CS initialization |
---|
23 | * strings from a local directory or a web service such as spatialreference.org. |
---|
24 | * |
---|
25 | * Similarly, Proj4js must have access to projection transform code. These can |
---|
26 | * be included individually using a <script> tag in your page, built into a |
---|
27 | * custom build of Proj4js or loaded dynamically at run-time. Using the |
---|
28 | * -combined and -compressed versions of Proj4js includes all projection class |
---|
29 | * code by default. |
---|
30 | * |
---|
31 | * Note that dynamic loading of defs and code happens ascynchrously, check the |
---|
32 | * Proj.readyToUse flag before using the Proj object. If the defs and code |
---|
33 | * required by your application are loaded through script tags, dynamic loading |
---|
34 | * is not required and the Proj object will be readyToUse on return from the |
---|
35 | * constructor. |
---|
36 | * |
---|
37 | * All coordinates are handled as points which have a .x and a .y property |
---|
38 | * which will be modified in place. |
---|
39 | * |
---|
40 | * Override Proj4js.reportError for output of alerts and warnings. |
---|
41 | * |
---|
42 | * See http://trac.osgeo.org/proj4js/wiki/UserGuide for full details. |
---|
43 | */ |
---|
44 | |
---|
45 | /** |
---|
46 | * Global namespace object for Proj4js library |
---|
47 | */ |
---|
48 | Proj4js = { |
---|
49 | |
---|
50 | /** |
---|
51 | * Property: defaultDatum |
---|
52 | * The datum to use when no others a specified |
---|
53 | */ |
---|
54 | defaultDatum: 'WGS84', //default datum |
---|
55 | |
---|
56 | /** |
---|
57 | * Method: transform(source, dest, point) |
---|
58 | * Transform a point coordinate from one map projection to another. This is |
---|
59 | * really the only public method you should need to use. |
---|
60 | * |
---|
61 | * Parameters: |
---|
62 | * source - {Proj4js.Proj} source map projection for the transformation |
---|
63 | * dest - {Proj4js.Proj} destination map projection for the transformation |
---|
64 | * point - {Object} point to transform, may be geodetic (long, lat) or |
---|
65 | * projected Cartesian (x,y), but should always have x,y properties. |
---|
66 | */ |
---|
67 | transform: function(source, dest, point) { |
---|
68 | if (!source.readyToUse) { |
---|
69 | this.reportError("Proj4js initialization for:"+source.srsCode+" not yet complete"); |
---|
70 | return point; |
---|
71 | } |
---|
72 | if (!dest.readyToUse) { |
---|
73 | this.reportError("Proj4js initialization for:"+dest.srsCode+" not yet complete"); |
---|
74 | return point; |
---|
75 | } |
---|
76 | |
---|
77 | // Workaround for Spherical Mercator |
---|
78 | if ((source.srsProjNumber =="900913" && dest.datumCode != "WGS84" && !dest.datum_params) || |
---|
79 | (dest.srsProjNumber == "900913" && source.datumCode != "WGS84" && !source.datum_params)) { |
---|
80 | var wgs84 = Proj4js.WGS84; |
---|
81 | this.transform(source, wgs84, point); |
---|
82 | source = wgs84; |
---|
83 | } |
---|
84 | |
---|
85 | // DGR, 2010/11/12 |
---|
86 | if (source.axis!="enu") { |
---|
87 | this.adjust_axis(source,false,point); |
---|
88 | } |
---|
89 | |
---|
90 | // Transform source points to long/lat, if they aren't already. |
---|
91 | if ( source.projName=="longlat") { |
---|
92 | point.x *= Proj4js.common.D2R; // convert degrees to radians |
---|
93 | point.y *= Proj4js.common.D2R; |
---|
94 | } else { |
---|
95 | if (source.to_meter) { |
---|
96 | point.x *= source.to_meter; |
---|
97 | point.y *= source.to_meter; |
---|
98 | } |
---|
99 | source.inverse(point); // Convert Cartesian to longlat |
---|
100 | } |
---|
101 | |
---|
102 | // Adjust for the prime meridian if necessary |
---|
103 | if (source.from_greenwich) { |
---|
104 | point.x += source.from_greenwich; |
---|
105 | } |
---|
106 | |
---|
107 | // Convert datums if needed, and if possible. |
---|
108 | point = this.datum_transform( source.datum, dest.datum, point ); |
---|
109 | |
---|
110 | // Adjust for the prime meridian if necessary |
---|
111 | if (dest.from_greenwich) { |
---|
112 | point.x -= dest.from_greenwich; |
---|
113 | } |
---|
114 | |
---|
115 | if( dest.projName=="longlat" ) { |
---|
116 | // convert radians to decimal degrees |
---|
117 | point.x *= Proj4js.common.R2D; |
---|
118 | point.y *= Proj4js.common.R2D; |
---|
119 | } else { // else project |
---|
120 | dest.forward(point); |
---|
121 | if (dest.to_meter) { |
---|
122 | point.x /= dest.to_meter; |
---|
123 | point.y /= dest.to_meter; |
---|
124 | } |
---|
125 | } |
---|
126 | |
---|
127 | // DGR, 2010/11/12 |
---|
128 | if (dest.axis!="enu") { |
---|
129 | this.adjust_axis(dest,true,point); |
---|
130 | } |
---|
131 | |
---|
132 | return point; |
---|
133 | }, // transform() |
---|
134 | |
---|
135 | /** datum_transform() |
---|
136 | source coordinate system definition, |
---|
137 | destination coordinate system definition, |
---|
138 | point to transform in geodetic coordinates (long, lat, height) |
---|
139 | */ |
---|
140 | datum_transform : function( source, dest, point ) { |
---|
141 | |
---|
142 | // Short cut if the datums are identical. |
---|
143 | if( source.compare_datums( dest ) ) { |
---|
144 | return point; // in this case, zero is sucess, |
---|
145 | // whereas cs_compare_datums returns 1 to indicate TRUE |
---|
146 | // confusing, should fix this |
---|
147 | } |
---|
148 | |
---|
149 | // Explicitly skip datum transform by setting 'datum=none' as parameter for either source or dest |
---|
150 | if( source.datum_type == Proj4js.common.PJD_NODATUM |
---|
151 | || dest.datum_type == Proj4js.common.PJD_NODATUM) { |
---|
152 | return point; |
---|
153 | } |
---|
154 | |
---|
155 | // If this datum requires grid shifts, then apply it to geodetic coordinates. |
---|
156 | if( source.datum_type == Proj4js.common.PJD_GRIDSHIFT ) |
---|
157 | { |
---|
158 | alert("ERROR: Grid shift transformations are not implemented yet."); |
---|
159 | /* |
---|
160 | pj_apply_gridshift( pj_param(source.params,"snadgrids").s, 0, |
---|
161 | point_count, point_offset, x, y, z ); |
---|
162 | CHECK_RETURN; |
---|
163 | |
---|
164 | src_a = SRS_WGS84_SEMIMAJOR; |
---|
165 | src_es = 0.006694379990; |
---|
166 | */ |
---|
167 | } |
---|
168 | |
---|
169 | if( dest.datum_type == Proj4js.common.PJD_GRIDSHIFT ) |
---|
170 | { |
---|
171 | alert("ERROR: Grid shift transformations are not implemented yet."); |
---|
172 | /* |
---|
173 | dst_a = ; |
---|
174 | dst_es = 0.006694379990; |
---|
175 | */ |
---|
176 | } |
---|
177 | |
---|
178 | // Do we need to go through geocentric coordinates? |
---|
179 | if( source.es != dest.es || source.a != dest.a |
---|
180 | || source.datum_type == Proj4js.common.PJD_3PARAM |
---|
181 | || source.datum_type == Proj4js.common.PJD_7PARAM |
---|
182 | || dest.datum_type == Proj4js.common.PJD_3PARAM |
---|
183 | || dest.datum_type == Proj4js.common.PJD_7PARAM) |
---|
184 | { |
---|
185 | |
---|
186 | // Convert to geocentric coordinates. |
---|
187 | source.geodetic_to_geocentric( point ); |
---|
188 | // CHECK_RETURN; |
---|
189 | |
---|
190 | // Convert between datums |
---|
191 | if( source.datum_type == Proj4js.common.PJD_3PARAM || source.datum_type == Proj4js.common.PJD_7PARAM ) { |
---|
192 | source.geocentric_to_wgs84(point); |
---|
193 | // CHECK_RETURN; |
---|
194 | } |
---|
195 | |
---|
196 | if( dest.datum_type == Proj4js.common.PJD_3PARAM || dest.datum_type == Proj4js.common.PJD_7PARAM ) { |
---|
197 | dest.geocentric_from_wgs84(point); |
---|
198 | // CHECK_RETURN; |
---|
199 | } |
---|
200 | |
---|
201 | // Convert back to geodetic coordinates |
---|
202 | dest.geocentric_to_geodetic( point ); |
---|
203 | // CHECK_RETURN; |
---|
204 | } |
---|
205 | |
---|
206 | // Apply grid shift to destination if required |
---|
207 | if( dest.datum_type == Proj4js.common.PJD_GRIDSHIFT ) |
---|
208 | { |
---|
209 | alert("ERROR: Grid shift transformations are not implemented yet."); |
---|
210 | // pj_apply_gridshift( pj_param(dest.params,"snadgrids").s, 1, point); |
---|
211 | // CHECK_RETURN; |
---|
212 | } |
---|
213 | return point; |
---|
214 | }, // cs_datum_transform |
---|
215 | |
---|
216 | /** |
---|
217 | * Function: adjust_axis |
---|
218 | * Normalize or de-normalized the x/y/z axes. The normal form is "enu" |
---|
219 | * (easting, northing, up). |
---|
220 | * Parameters: |
---|
221 | * crs {Proj4js.Proj} the coordinate reference system |
---|
222 | * denorm {Boolean} when false, normalize |
---|
223 | * point {Object} the coordinates to adjust |
---|
224 | */ |
---|
225 | adjust_axis: function(crs, denorm, point) { |
---|
226 | var xin= point.x, yin= point.y, zin= point.z || 0.0; |
---|
227 | var v, t; |
---|
228 | for (var i= 0; i<3; i++) { |
---|
229 | if (denorm && i==2 && point.z===undefined) { continue; } |
---|
230 | if (i==0) { v= xin; t= 'x'; } |
---|
231 | else if (i==1) { v= yin; t= 'y'; } |
---|
232 | else { v= zin; t= 'z'; } |
---|
233 | switch(crs.axis[i]) { |
---|
234 | case 'e': |
---|
235 | point[t]= v; |
---|
236 | break; |
---|
237 | case 'w': |
---|
238 | point[t]= -v; |
---|
239 | break; |
---|
240 | case 'n': |
---|
241 | point[t]= v; |
---|
242 | break; |
---|
243 | case 's': |
---|
244 | point[t]= -v; |
---|
245 | break; |
---|
246 | case 'u': |
---|
247 | if (point[t]!==undefined) { point.z= v; } |
---|
248 | break; |
---|
249 | case 'd': |
---|
250 | if (point[t]!==undefined) { point.z= -v; } |
---|
251 | break; |
---|
252 | default : |
---|
253 | alert("ERROR: unknow axis ("+crs.axis[i]+") - check definition of "+src.projName); |
---|
254 | return null; |
---|
255 | } |
---|
256 | } |
---|
257 | return point; |
---|
258 | }, |
---|
259 | |
---|
260 | /** |
---|
261 | * Function: reportError |
---|
262 | * An internal method to report errors back to user. |
---|
263 | * Override this in applications to report error messages or throw exceptions. |
---|
264 | */ |
---|
265 | reportError: function(msg) { |
---|
266 | //console.log(msg); |
---|
267 | }, |
---|
268 | |
---|
269 | /** |
---|
270 | * |
---|
271 | * Title: Private Methods |
---|
272 | * The following properties and methods are intended for internal use only. |
---|
273 | * |
---|
274 | * This is a minimal implementation of JavaScript inheritance methods so that |
---|
275 | * Proj4js can be used as a stand-alone library. |
---|
276 | * These are copies of the equivalent OpenLayers methods at v2.7 |
---|
277 | */ |
---|
278 | |
---|
279 | /** |
---|
280 | * Function: extend |
---|
281 | * Copy all properties of a source object to a destination object. Modifies |
---|
282 | * the passed in destination object. Any properties on the source object |
---|
283 | * that are set to undefined will not be (re)set on the destination object. |
---|
284 | * |
---|
285 | * Parameters: |
---|
286 | * destination - {Object} The object that will be modified |
---|
287 | * source - {Object} The object with properties to be set on the destination |
---|
288 | * |
---|
289 | * Returns: |
---|
290 | * {Object} The destination object. |
---|
291 | */ |
---|
292 | extend: function(destination, source) { |
---|
293 | destination = destination || {}; |
---|
294 | if(source) { |
---|
295 | for(var property in source) { |
---|
296 | var value = source[property]; |
---|
297 | if(value !== undefined) { |
---|
298 | destination[property] = value; |
---|
299 | } |
---|
300 | } |
---|
301 | } |
---|
302 | return destination; |
---|
303 | }, |
---|
304 | |
---|
305 | /** |
---|
306 | * Constructor: Class |
---|
307 | * Base class used to construct all other classes. Includes support for |
---|
308 | * multiple inheritance. |
---|
309 | * |
---|
310 | */ |
---|
311 | Class: function() { |
---|
312 | var Class = function() { |
---|
313 | this.initialize.apply(this, arguments); |
---|
314 | }; |
---|
315 | |
---|
316 | var extended = {}; |
---|
317 | var parent; |
---|
318 | for(var i=0; i<arguments.length; ++i) { |
---|
319 | if(typeof arguments[i] == "function") { |
---|
320 | // get the prototype of the superclass |
---|
321 | parent = arguments[i].prototype; |
---|
322 | } else { |
---|
323 | // in this case we're extending with the prototype |
---|
324 | parent = arguments[i]; |
---|
325 | } |
---|
326 | Proj4js.extend(extended, parent); |
---|
327 | } |
---|
328 | Class.prototype = extended; |
---|
329 | |
---|
330 | return Class; |
---|
331 | }, |
---|
332 | |
---|
333 | /** |
---|
334 | * Function: bind |
---|
335 | * Bind a function to an object. Method to easily create closures with |
---|
336 | * 'this' altered. |
---|
337 | * |
---|
338 | * Parameters: |
---|
339 | * func - {Function} Input function. |
---|
340 | * object - {Object} The object to bind to the input function (as this). |
---|
341 | * |
---|
342 | * Returns: |
---|
343 | * {Function} A closure with 'this' set to the passed in object. |
---|
344 | */ |
---|
345 | bind: function(func, object) { |
---|
346 | // create a reference to all arguments past the second one |
---|
347 | var args = Array.prototype.slice.apply(arguments, [2]); |
---|
348 | return function() { |
---|
349 | // Push on any additional arguments from the actual function call. |
---|
350 | // These will come after those sent to the bind call. |
---|
351 | var newArgs = args.concat( |
---|
352 | Array.prototype.slice.apply(arguments, [0]) |
---|
353 | ); |
---|
354 | return func.apply(object, newArgs); |
---|
355 | }; |
---|
356 | }, |
---|
357 | |
---|
358 | /** |
---|
359 | * The following properties and methods handle dynamic loading of JSON objects. |
---|
360 | */ |
---|
361 | |
---|
362 | /** |
---|
363 | * Property: scriptName |
---|
364 | * {String} The filename of this script without any path. |
---|
365 | */ |
---|
366 | scriptName: "proj4js.js", |
---|
367 | |
---|
368 | /** |
---|
369 | * Property: defsLookupService |
---|
370 | * AJAX service to retreive projection definition parameters from |
---|
371 | */ |
---|
372 | defsLookupService: 'http://spatialreference.org/ref', |
---|
373 | |
---|
374 | /** |
---|
375 | * Property: libPath |
---|
376 | * internal: http server path to library code. |
---|
377 | */ |
---|
378 | libPath: null, |
---|
379 | |
---|
380 | /** |
---|
381 | * Function: getScriptLocation |
---|
382 | * Return the path to this script. |
---|
383 | * |
---|
384 | * Returns: |
---|
385 | * Path to this script |
---|
386 | */ |
---|
387 | getScriptLocation: function () { |
---|
388 | if (this.libPath) return this.libPath; |
---|
389 | var scriptName = this.scriptName; |
---|
390 | var scriptNameLen = scriptName.length; |
---|
391 | |
---|
392 | var scripts = document.getElementsByTagName('script'); |
---|
393 | for (var i = 0; i < scripts.length; i++) { |
---|
394 | var src = scripts[i].getAttribute('src'); |
---|
395 | if (src) { |
---|
396 | var index = src.lastIndexOf(scriptName); |
---|
397 | // is it found, at the end of the URL? |
---|
398 | if ((index > -1) && (index + scriptNameLen == src.length)) { |
---|
399 | this.libPath = src.slice(0, -scriptNameLen); |
---|
400 | break; |
---|
401 | } |
---|
402 | } |
---|
403 | } |
---|
404 | return this.libPath||""; |
---|
405 | }, |
---|
406 | |
---|
407 | /** |
---|
408 | * Function: loadScript |
---|
409 | * Load a JS file from a URL into a <script> tag in the page. |
---|
410 | * |
---|
411 | * Parameters: |
---|
412 | * url - {String} The URL containing the script to load |
---|
413 | * onload - {Function} A method to be executed when the script loads successfully |
---|
414 | * onfail - {Function} A method to be executed when there is an error loading the script |
---|
415 | * loadCheck - {Function} A boolean method that checks to see if the script |
---|
416 | * has loaded. Typically this just checks for the existance of |
---|
417 | * an object in the file just loaded. |
---|
418 | */ |
---|
419 | loadScript: function(url, onload, onfail, loadCheck) { |
---|
420 | var script = document.createElement('script'); |
---|
421 | script.defer = false; |
---|
422 | script.type = "text/javascript"; |
---|
423 | script.id = url; |
---|
424 | script.src = url; |
---|
425 | script.onload = onload; |
---|
426 | script.onerror = onfail; |
---|
427 | script.loadCheck = loadCheck; |
---|
428 | if (/MSIE/.test(navigator.userAgent)) { |
---|
429 | script.onreadystatechange = this.checkReadyState; |
---|
430 | } |
---|
431 | document.getElementsByTagName('head')[0].appendChild(script); |
---|
432 | }, |
---|
433 | |
---|
434 | /** |
---|
435 | * Function: checkReadyState |
---|
436 | * IE workaround since there is no onerror handler. Calls the user defined |
---|
437 | * loadCheck method to determine if the script is loaded. |
---|
438 | * |
---|
439 | */ |
---|
440 | checkReadyState: function() { |
---|
441 | if (this.readyState == 'loaded') { |
---|
442 | if (!this.loadCheck()) { |
---|
443 | this.onerror(); |
---|
444 | } else { |
---|
445 | this.onload(); |
---|
446 | } |
---|
447 | } |
---|
448 | } |
---|
449 | }; |
---|
450 | |
---|
451 | /** |
---|
452 | * Class: Proj4js.Proj |
---|
453 | * |
---|
454 | * Proj objects provide transformation methods for point coordinates |
---|
455 | * between geodetic latitude/longitude and a projected coordinate system. |
---|
456 | * once they have been initialized with a projection code. |
---|
457 | * |
---|
458 | * Initialization of Proj objects is with a projection code, usually EPSG codes, |
---|
459 | * which is the key that will be used with the Proj4js.defs array. |
---|
460 | * |
---|
461 | * The code passed in will be stripped of colons and converted to uppercase |
---|
462 | * to locate projection definition files. |
---|
463 | * |
---|
464 | * A projection object has properties for units and title strings. |
---|
465 | */ |
---|
466 | Proj4js.Proj = Proj4js.Class({ |
---|
467 | |
---|
468 | /** |
---|
469 | * Property: readyToUse |
---|
470 | * Flag to indicate if initialization is complete for this Proj object |
---|
471 | */ |
---|
472 | readyToUse: false, |
---|
473 | |
---|
474 | /** |
---|
475 | * Property: title |
---|
476 | * The title to describe the projection |
---|
477 | */ |
---|
478 | title: null, |
---|
479 | |
---|
480 | /** |
---|
481 | * Property: projName |
---|
482 | * The projection class for this projection, e.g. lcc (lambert conformal conic, |
---|
483 | * or merc for mercator). These are exactly equivalent to their Proj4 |
---|
484 | * counterparts. |
---|
485 | */ |
---|
486 | projName: null, |
---|
487 | /** |
---|
488 | * Property: units |
---|
489 | * The units of the projection. Values include 'm' and 'degrees' |
---|
490 | */ |
---|
491 | units: null, |
---|
492 | /** |
---|
493 | * Property: datum |
---|
494 | * The datum specified for the projection |
---|
495 | */ |
---|
496 | datum: null, |
---|
497 | /** |
---|
498 | * Property: x0 |
---|
499 | * The x coordinate origin |
---|
500 | */ |
---|
501 | x0: 0, |
---|
502 | /** |
---|
503 | * Property: y0 |
---|
504 | * The y coordinate origin |
---|
505 | */ |
---|
506 | y0: 0, |
---|
507 | /** |
---|
508 | * Property: localCS |
---|
509 | * Flag to indicate if the projection is a local one in which no transforms |
---|
510 | * are required. |
---|
511 | */ |
---|
512 | localCS: false, |
---|
513 | |
---|
514 | /** |
---|
515 | * Property: queue |
---|
516 | * Buffer (FIFO) to hold callbacks waiting to be called when projection loaded. |
---|
517 | */ |
---|
518 | queue: null, |
---|
519 | |
---|
520 | /** |
---|
521 | * Constructor: initialize |
---|
522 | * Constructor for Proj4js.Proj objects |
---|
523 | * |
---|
524 | * Parameters: |
---|
525 | * srsCode - a code for map projection definition parameters. These are usually |
---|
526 | * (but not always) EPSG codes. |
---|
527 | */ |
---|
528 | initialize: function(srsCode, callback) { |
---|
529 | this.srsCodeInput = srsCode; |
---|
530 | |
---|
531 | //Register callbacks prior to attempting to process definition |
---|
532 | this.queue = []; |
---|
533 | if( callback ){ |
---|
534 | this.queue.push( callback ); |
---|
535 | } |
---|
536 | |
---|
537 | //check to see if this is a WKT string |
---|
538 | if ((srsCode.indexOf('GEOGCS') >= 0) || |
---|
539 | (srsCode.indexOf('GEOCCS') >= 0) || |
---|
540 | (srsCode.indexOf('PROJCS') >= 0) || |
---|
541 | (srsCode.indexOf('LOCAL_CS') >= 0)) { |
---|
542 | this.parseWKT(srsCode); |
---|
543 | this.deriveConstants(); |
---|
544 | this.loadProjCode(this.projName); |
---|
545 | return; |
---|
546 | } |
---|
547 | |
---|
548 | // DGR 2008-08-03 : support urn and url |
---|
549 | if (srsCode.indexOf('urn:') == 0) { |
---|
550 | //urn:ORIGINATOR:def:crs:CODESPACE:VERSION:ID |
---|
551 | var urn = srsCode.split(':'); |
---|
552 | if ((urn[1] == 'ogc' || urn[1] =='x-ogc') && |
---|
553 | (urn[2] =='def') && |
---|
554 | (urn[3] =='crs')) { |
---|
555 | srsCode = urn[4]+':'+urn[urn.length-1]; |
---|
556 | } |
---|
557 | } else if (srsCode.indexOf('http://') == 0) { |
---|
558 | //url#ID |
---|
559 | var url = srsCode.split('#'); |
---|
560 | if (url[0].match(/epsg.org/)) { |
---|
561 | // http://www.epsg.org/# |
---|
562 | srsCode = 'EPSG:'+url[1]; |
---|
563 | } else if (url[0].match(/RIG.xml/)) { |
---|
564 | //http://librairies.ign.fr/geoportail/resources/RIG.xml# |
---|
565 | //http://interop.ign.fr/registers/ign/RIG.xml# |
---|
566 | srsCode = 'IGNF:'+url[1]; |
---|
567 | } |
---|
568 | } |
---|
569 | this.srsCode = srsCode.toUpperCase(); |
---|
570 | if (this.srsCode.indexOf("EPSG") == 0) { |
---|
571 | this.srsCode = this.srsCode; |
---|
572 | this.srsAuth = 'epsg'; |
---|
573 | this.srsProjNumber = this.srsCode.substring(5); |
---|
574 | // DGR 2007-11-20 : authority IGNF |
---|
575 | } else if (this.srsCode.indexOf("IGNF") == 0) { |
---|
576 | this.srsCode = this.srsCode; |
---|
577 | this.srsAuth = 'IGNF'; |
---|
578 | this.srsProjNumber = this.srsCode.substring(5); |
---|
579 | // DGR 2008-06-19 : pseudo-authority CRS for WMS |
---|
580 | } else if (this.srsCode.indexOf("CRS") == 0) { |
---|
581 | this.srsCode = this.srsCode; |
---|
582 | this.srsAuth = 'CRS'; |
---|
583 | this.srsProjNumber = this.srsCode.substring(4); |
---|
584 | } else { |
---|
585 | this.srsAuth = ''; |
---|
586 | this.srsProjNumber = this.srsCode; |
---|
587 | } |
---|
588 | |
---|
589 | this.loadProjDefinition(); |
---|
590 | }, |
---|
591 | |
---|
592 | /** |
---|
593 | * Function: loadProjDefinition |
---|
594 | * Loads the coordinate system initialization string if required. |
---|
595 | * Note that dynamic loading happens asynchronously so an application must |
---|
596 | * wait for the readyToUse property is set to true. |
---|
597 | * To prevent dynamic loading, include the defs through a script tag in |
---|
598 | * your application. |
---|
599 | * |
---|
600 | */ |
---|
601 | loadProjDefinition: function() { |
---|
602 | //check in memory |
---|
603 | if (Proj4js.defs[this.srsCode]) { |
---|
604 | this.defsLoaded(); |
---|
605 | return; |
---|
606 | } |
---|
607 | |
---|
608 | //else check for def on the server |
---|
609 | var url = Proj4js.getScriptLocation() + 'defs/' + this.srsAuth.toUpperCase() + this.srsProjNumber + '.js'; |
---|
610 | Proj4js.loadScript(url, |
---|
611 | Proj4js.bind(this.defsLoaded, this), |
---|
612 | Proj4js.bind(this.loadFromService, this), |
---|
613 | Proj4js.bind(this.checkDefsLoaded, this) ); |
---|
614 | }, |
---|
615 | |
---|
616 | /** |
---|
617 | * Function: loadFromService |
---|
618 | * Creates the REST URL for loading the definition from a web service and |
---|
619 | * loads it. |
---|
620 | * |
---|
621 | */ |
---|
622 | loadFromService: function() { |
---|
623 | //else load from web service |
---|
624 | var url = Proj4js.defsLookupService +'/' + this.srsAuth +'/'+ this.srsProjNumber + '/proj4js/'; |
---|
625 | Proj4js.loadScript(url, |
---|
626 | Proj4js.bind(this.defsLoaded, this), |
---|
627 | Proj4js.bind(this.defsFailed, this), |
---|
628 | Proj4js.bind(this.checkDefsLoaded, this) ); |
---|
629 | }, |
---|
630 | |
---|
631 | /** |
---|
632 | * Function: defsLoaded |
---|
633 | * Continues the Proj object initilization once the def file is loaded |
---|
634 | * |
---|
635 | */ |
---|
636 | defsLoaded: function() { |
---|
637 | this.parseDefs(); |
---|
638 | this.loadProjCode(this.projName); |
---|
639 | }, |
---|
640 | |
---|
641 | /** |
---|
642 | * Function: checkDefsLoaded |
---|
643 | * This is the loadCheck method to see if the def object exists |
---|
644 | * |
---|
645 | */ |
---|
646 | checkDefsLoaded: function() { |
---|
647 | if (Proj4js.defs[this.srsCode]) { |
---|
648 | return true; |
---|
649 | } else { |
---|
650 | return false; |
---|
651 | } |
---|
652 | }, |
---|
653 | |
---|
654 | /** |
---|
655 | * Function: defsFailed |
---|
656 | * Report an error in loading the defs file, but continue on using WGS84 |
---|
657 | * |
---|
658 | */ |
---|
659 | defsFailed: function() { |
---|
660 | Proj4js.reportError('failed to load projection definition for: '+this.srsCode); |
---|
661 | Proj4js.defs[this.srsCode] = Proj4js.defs['WGS84']; //set it to something so it can at least continue |
---|
662 | this.defsLoaded(); |
---|
663 | }, |
---|
664 | |
---|
665 | /** |
---|
666 | * Function: loadProjCode |
---|
667 | * Loads projection class code dynamically if required. |
---|
668 | * Projection code may be included either through a script tag or in |
---|
669 | * a built version of proj4js |
---|
670 | * |
---|
671 | */ |
---|
672 | loadProjCode: function(projName) { |
---|
673 | if (Proj4js.Proj[projName]) { |
---|
674 | this.initTransforms(); |
---|
675 | return; |
---|
676 | } |
---|
677 | |
---|
678 | //the URL for the projection code |
---|
679 | var url = Proj4js.getScriptLocation() + 'projCode/' + projName + '.js'; |
---|
680 | Proj4js.loadScript(url, |
---|
681 | Proj4js.bind(this.loadProjCodeSuccess, this, projName), |
---|
682 | Proj4js.bind(this.loadProjCodeFailure, this, projName), |
---|
683 | Proj4js.bind(this.checkCodeLoaded, this, projName) ); |
---|
684 | }, |
---|
685 | |
---|
686 | /** |
---|
687 | * Function: loadProjCodeSuccess |
---|
688 | * Loads any proj dependencies or continue on to final initialization. |
---|
689 | * |
---|
690 | */ |
---|
691 | loadProjCodeSuccess: function(projName) { |
---|
692 | if (Proj4js.Proj[projName].dependsOn){ |
---|
693 | this.loadProjCode(Proj4js.Proj[projName].dependsOn); |
---|
694 | } else { |
---|
695 | this.initTransforms(); |
---|
696 | } |
---|
697 | }, |
---|
698 | |
---|
699 | /** |
---|
700 | * Function: defsFailed |
---|
701 | * Report an error in loading the proj file. Initialization of the Proj |
---|
702 | * object has failed and the readyToUse flag will never be set. |
---|
703 | * |
---|
704 | */ |
---|
705 | loadProjCodeFailure: function(projName) { |
---|
706 | Proj4js.reportError("failed to find projection file for: " + projName); |
---|
707 | //TBD initialize with identity transforms so proj will still work? |
---|
708 | }, |
---|
709 | |
---|
710 | /** |
---|
711 | * Function: checkCodeLoaded |
---|
712 | * This is the loadCheck method to see if the projection code is loaded |
---|
713 | * |
---|
714 | */ |
---|
715 | checkCodeLoaded: function(projName) { |
---|
716 | if (Proj4js.Proj[projName]) { |
---|
717 | return true; |
---|
718 | } else { |
---|
719 | return false; |
---|
720 | } |
---|
721 | }, |
---|
722 | |
---|
723 | /** |
---|
724 | * Function: initTransforms |
---|
725 | * Finalize the initialization of the Proj object |
---|
726 | * |
---|
727 | */ |
---|
728 | initTransforms: function() { |
---|
729 | Proj4js.extend(this, Proj4js.Proj[this.projName]); |
---|
730 | this.init(); |
---|
731 | this.readyToUse = true; |
---|
732 | if( this.queue ) { |
---|
733 | var item; |
---|
734 | while( (item = this.queue.shift()) ) { |
---|
735 | item.call( this, this ); |
---|
736 | } |
---|
737 | } |
---|
738 | }, |
---|
739 | |
---|
740 | /** |
---|
741 | * Function: parseWKT |
---|
742 | * Parses a WKT string to get initialization parameters |
---|
743 | * |
---|
744 | */ |
---|
745 | wktRE: /^(\w+)\[(.*)\]$/, |
---|
746 | parseWKT: function(wkt) { |
---|
747 | var wktMatch = wkt.match(this.wktRE); |
---|
748 | if (!wktMatch) return; |
---|
749 | var wktObject = wktMatch[1]; |
---|
750 | var wktContent = wktMatch[2]; |
---|
751 | var wktTemp = wktContent.split(","); |
---|
752 | var wktName; |
---|
753 | if (wktObject.toUpperCase() == "TOWGS84") { |
---|
754 | wktName = wktObject; //no name supplied for the TOWGS84 array |
---|
755 | } else { |
---|
756 | wktName = wktTemp.shift(); |
---|
757 | } |
---|
758 | wktName = wktName.replace(/^\"/,""); |
---|
759 | wktName = wktName.replace(/\"$/,""); |
---|
760 | |
---|
761 | /* |
---|
762 | wktContent = wktTemp.join(","); |
---|
763 | var wktArray = wktContent.split("],"); |
---|
764 | for (var i=0; i<wktArray.length-1; ++i) { |
---|
765 | wktArray[i] += "]"; |
---|
766 | } |
---|
767 | */ |
---|
768 | |
---|
769 | var wktArray = new Array(); |
---|
770 | var bkCount = 0; |
---|
771 | var obj = ""; |
---|
772 | for (var i=0; i<wktTemp.length; ++i) { |
---|
773 | var token = wktTemp[i]; |
---|
774 | for (var j=0; j<token.length; ++j) { |
---|
775 | if (token.charAt(j) == "[") ++bkCount; |
---|
776 | if (token.charAt(j) == "]") --bkCount; |
---|
777 | } |
---|
778 | obj += token; |
---|
779 | if (bkCount === 0) { |
---|
780 | wktArray.push(obj); |
---|
781 | obj = ""; |
---|
782 | } else { |
---|
783 | obj += ","; |
---|
784 | } |
---|
785 | } |
---|
786 | |
---|
787 | //do something based on the type of the wktObject being parsed |
---|
788 | //add in variations in the spelling as required |
---|
789 | switch (wktObject) { |
---|
790 | case 'LOCAL_CS': |
---|
791 | this.projName = 'identity' |
---|
792 | this.localCS = true; |
---|
793 | this.srsCode = wktName; |
---|
794 | break; |
---|
795 | case 'GEOGCS': |
---|
796 | this.projName = 'longlat' |
---|
797 | this.geocsCode = wktName; |
---|
798 | if (!this.srsCode) this.srsCode = wktName; |
---|
799 | break; |
---|
800 | case 'PROJCS': |
---|
801 | this.srsCode = wktName; |
---|
802 | break; |
---|
803 | case 'GEOCCS': |
---|
804 | break; |
---|
805 | case 'PROJECTION': |
---|
806 | this.projName = Proj4js.wktProjections[wktName] |
---|
807 | break; |
---|
808 | case 'DATUM': |
---|
809 | this.datumName = wktName; |
---|
810 | break; |
---|
811 | case 'LOCAL_DATUM': |
---|
812 | this.datumCode = 'none'; |
---|
813 | break; |
---|
814 | case 'SPHEROID': |
---|
815 | this.ellps = wktName; |
---|
816 | this.a = parseFloat(wktArray.shift()); |
---|
817 | this.rf = parseFloat(wktArray.shift()); |
---|
818 | break; |
---|
819 | case 'PRIMEM': |
---|
820 | this.from_greenwich = parseFloat(wktArray.shift()); //to radians? |
---|
821 | break; |
---|
822 | case 'UNIT': |
---|
823 | this.units = wktName; |
---|
824 | this.unitsPerMeter = parseFloat(wktArray.shift()); |
---|
825 | break; |
---|
826 | case 'PARAMETER': |
---|
827 | var name = wktName.toLowerCase(); |
---|
828 | var value = parseFloat(wktArray.shift()); |
---|
829 | //there may be many variations on the wktName values, add in case |
---|
830 | //statements as required |
---|
831 | switch (name) { |
---|
832 | case 'false_easting': |
---|
833 | this.x0 = value; |
---|
834 | break; |
---|
835 | case 'false_northing': |
---|
836 | this.y0 = value; |
---|
837 | break; |
---|
838 | case 'scale_factor': |
---|
839 | this.k0 = value; |
---|
840 | break; |
---|
841 | case 'central_meridian': |
---|
842 | this.long0 = value*Proj4js.common.D2R; |
---|
843 | break; |
---|
844 | case 'latitude_of_origin': |
---|
845 | this.lat0 = value*Proj4js.common.D2R; |
---|
846 | break; |
---|
847 | case 'more_here': |
---|
848 | break; |
---|
849 | default: |
---|
850 | break; |
---|
851 | } |
---|
852 | break; |
---|
853 | case 'TOWGS84': |
---|
854 | this.datum_params = wktArray; |
---|
855 | break; |
---|
856 | //DGR 2010-11-12: AXIS |
---|
857 | case 'AXIS': |
---|
858 | var name= wktName.toLowerCase(); |
---|
859 | var value= wktArray.shift(); |
---|
860 | switch (value) { |
---|
861 | case 'EAST' : value= 'e'; break; |
---|
862 | case 'WEST' : value= 'w'; break; |
---|
863 | case 'NORTH': value= 'n'; break; |
---|
864 | case 'SOUTH': value= 's'; break; |
---|
865 | case 'UP' : value= 'u'; break; |
---|
866 | case 'DOWN' : value= 'd'; break; |
---|
867 | case 'OTHER': |
---|
868 | default : value= ' '; break;//FIXME |
---|
869 | } |
---|
870 | if (!this.axis) { this.axis= "enu"; } |
---|
871 | switch(name) { |
---|
872 | case 'X': this.axis= value + this.axis.substr(1,2); break; |
---|
873 | case 'Y': this.axis= this.axis.substr(0,1) + value + this.axis.substr(2,1); break; |
---|
874 | case 'Z': this.axis= this.axis.substr(0,2) + value ; break; |
---|
875 | default : break; |
---|
876 | } |
---|
877 | case 'MORE_HERE': |
---|
878 | break; |
---|
879 | default: |
---|
880 | break; |
---|
881 | } |
---|
882 | for (var i=0; i<wktArray.length; ++i) { |
---|
883 | this.parseWKT(wktArray[i]); |
---|
884 | } |
---|
885 | }, |
---|
886 | |
---|
887 | /** |
---|
888 | * Function: parseDefs |
---|
889 | * Parses the PROJ.4 initialization string and sets the associated properties. |
---|
890 | * |
---|
891 | */ |
---|
892 | parseDefs: function() { |
---|
893 | this.defData = Proj4js.defs[this.srsCode]; |
---|
894 | var paramName, paramVal; |
---|
895 | if (!this.defData) { |
---|
896 | return; |
---|
897 | } |
---|
898 | var paramArray=this.defData.split("+"); |
---|
899 | |
---|
900 | for (var prop=0; prop<paramArray.length; prop++) { |
---|
901 | var property = paramArray[prop].split("="); |
---|
902 | paramName = property[0].toLowerCase(); |
---|
903 | paramVal = property[1]; |
---|
904 | |
---|
905 | switch (paramName.replace(/\s/gi,"")) { // trim out spaces |
---|
906 | case "": break; // throw away nameless parameter |
---|
907 | case "title": this.title = paramVal; break; |
---|
908 | case "proj": this.projName = paramVal.replace(/\s/gi,""); break; |
---|
909 | case "units": this.units = paramVal.replace(/\s/gi,""); break; |
---|
910 | case "datum": this.datumCode = paramVal.replace(/\s/gi,""); break; |
---|
911 | case "nadgrids": this.nagrids = paramVal.replace(/\s/gi,""); break; |
---|
912 | case "ellps": this.ellps = paramVal.replace(/\s/gi,""); break; |
---|
913 | case "a": this.a = parseFloat(paramVal); break; // semi-major radius |
---|
914 | case "b": this.b = parseFloat(paramVal); break; // semi-minor radius |
---|
915 | // DGR 2007-11-20 |
---|
916 | case "rf": this.rf = parseFloat(paramVal); break; // inverse flattening rf= a/(a-b) |
---|
917 | case "lat_0": this.lat0 = paramVal*Proj4js.common.D2R; break; // phi0, central latitude |
---|
918 | case "lat_1": this.lat1 = paramVal*Proj4js.common.D2R; break; //standard parallel 1 |
---|
919 | case "lat_2": this.lat2 = paramVal*Proj4js.common.D2R; break; //standard parallel 2 |
---|
920 | case "lat_ts": this.lat_ts = paramVal*Proj4js.common.D2R; break; // used in merc and eqc |
---|
921 | case "lon_0": this.long0 = paramVal*Proj4js.common.D2R; break; // lam0, central longitude |
---|
922 | case "alpha": this.alpha = parseFloat(paramVal)*Proj4js.common.D2R; break; //for somerc projection |
---|
923 | case "lonc": this.longc = paramVal*Proj4js.common.D2R; break; //for somerc projection |
---|
924 | case "x_0": this.x0 = parseFloat(paramVal); break; // false easting |
---|
925 | case "y_0": this.y0 = parseFloat(paramVal); break; // false northing |
---|
926 | case "k_0": this.k0 = parseFloat(paramVal); break; // projection scale factor |
---|
927 | case "k": this.k0 = parseFloat(paramVal); break; // both forms returned |
---|
928 | case "r_a": this.R_A = true; break; // sphere--area of ellipsoid |
---|
929 | case "zone": this.zone = parseInt(paramVal); break; // UTM Zone |
---|
930 | case "south": this.utmSouth = true; break; // UTM north/south |
---|
931 | case "towgs84":this.datum_params = paramVal.split(","); break; |
---|
932 | case "to_meter": this.to_meter = parseFloat(paramVal); break; // cartesian scaling |
---|
933 | case "from_greenwich": this.from_greenwich = paramVal*Proj4js.common.D2R; break; |
---|
934 | // DGR 2008-07-09 : if pm is not a well-known prime meridian take |
---|
935 | // the value instead of 0.0, then convert to radians |
---|
936 | case "pm": paramVal = paramVal.replace(/\s/gi,""); |
---|
937 | this.from_greenwich = Proj4js.PrimeMeridian[paramVal] ? |
---|
938 | Proj4js.PrimeMeridian[paramVal] : parseFloat(paramVal); |
---|
939 | this.from_greenwich *= Proj4js.common.D2R; |
---|
940 | break; |
---|
941 | // DGR 2010-11-12: axis |
---|
942 | case "axis": paramVal = paramVal.replace(/\s/gi,""); |
---|
943 | var legalAxis= "ewnsud"; |
---|
944 | if (paramVal.length==3 && |
---|
945 | legalAxis.indexOf(paramVal.substr(0,1))!=-1 && |
---|
946 | legalAxis.indexOf(paramVal.substr(1,1))!=-1 && |
---|
947 | legalAxis.indexOf(paramVal.substr(2,1))!=-1) { |
---|
948 | this.axis= paramVal; |
---|
949 | } //FIXME: be silent ? |
---|
950 | break |
---|
951 | case "no_defs": break; |
---|
952 | default: //alert("Unrecognized parameter: " + paramName); |
---|
953 | } // switch() |
---|
954 | } // for paramArray |
---|
955 | this.deriveConstants(); |
---|
956 | }, |
---|
957 | |
---|
958 | /** |
---|
959 | * Function: deriveConstants |
---|
960 | * Sets several derived constant values and initialization of datum and ellipse |
---|
961 | * parameters. |
---|
962 | * |
---|
963 | */ |
---|
964 | deriveConstants: function() { |
---|
965 | if (this.nagrids == '@null') this.datumCode = 'none'; |
---|
966 | if (this.datumCode && this.datumCode != 'none') { |
---|
967 | var datumDef = Proj4js.Datum[this.datumCode]; |
---|
968 | if (datumDef) { |
---|
969 | this.datum_params = datumDef.towgs84 ? datumDef.towgs84.split(',') : null; |
---|
970 | this.ellps = datumDef.ellipse; |
---|
971 | this.datumName = datumDef.datumName ? datumDef.datumName : this.datumCode; |
---|
972 | } |
---|
973 | } |
---|
974 | if (!this.a) { // do we have an ellipsoid? |
---|
975 | var ellipse = Proj4js.Ellipsoid[this.ellps] ? Proj4js.Ellipsoid[this.ellps] : Proj4js.Ellipsoid['WGS84']; |
---|
976 | Proj4js.extend(this, ellipse); |
---|
977 | } |
---|
978 | if (this.rf && !this.b) this.b = (1.0 - 1.0/this.rf) * this.a; |
---|
979 | if (Math.abs(this.a - this.b)<Proj4js.common.EPSLN) { |
---|
980 | this.sphere = true; |
---|
981 | this.b= this.a; |
---|
982 | } |
---|
983 | this.a2 = this.a * this.a; // used in geocentric |
---|
984 | this.b2 = this.b * this.b; // used in geocentric |
---|
985 | this.es = (this.a2-this.b2)/this.a2; // e ^ 2 |
---|
986 | this.e = Math.sqrt(this.es); // eccentricity |
---|
987 | if (this.R_A) { |
---|
988 | this.a *= 1. - this.es * (Proj4js.common.SIXTH + this.es * (Proj4js.common.RA4 + this.es * Proj4js.common.RA6)); |
---|
989 | this.a2 = this.a * this.a; |
---|
990 | this.b2 = this.b * this.b; |
---|
991 | this.es = 0.; |
---|
992 | } |
---|
993 | this.ep2=(this.a2-this.b2)/this.b2; // used in geocentric |
---|
994 | if (!this.k0) this.k0 = 1.0; //default value |
---|
995 | //DGR 2010-11-12: axis |
---|
996 | if (!this.axis) { this.axis= "enu"; } |
---|
997 | |
---|
998 | this.datum = new Proj4js.datum(this); |
---|
999 | } |
---|
1000 | }); |
---|
1001 | |
---|
1002 | Proj4js.Proj.longlat = { |
---|
1003 | init: function() { |
---|
1004 | //no-op for longlat |
---|
1005 | }, |
---|
1006 | forward: function(pt) { |
---|
1007 | //identity transform |
---|
1008 | return pt; |
---|
1009 | }, |
---|
1010 | inverse: function(pt) { |
---|
1011 | //identity transform |
---|
1012 | return pt; |
---|
1013 | } |
---|
1014 | }; |
---|
1015 | Proj4js.Proj.identity = Proj4js.Proj.longlat; |
---|
1016 | |
---|
1017 | /** |
---|
1018 | Proj4js.defs is a collection of coordinate system definition objects in the |
---|
1019 | PROJ.4 command line format. |
---|
1020 | Generally a def is added by means of a separate .js file for example: |
---|
1021 | |
---|
1022 | <SCRIPT type="text/javascript" src="defs/EPSG26912.js"></SCRIPT> |
---|
1023 | |
---|
1024 | def is a CS definition in PROJ.4 WKT format, for example: |
---|
1025 | +proj="tmerc" //longlat, etc. |
---|
1026 | +a=majorRadius |
---|
1027 | +b=minorRadius |
---|
1028 | +lat0=somenumber |
---|
1029 | +long=somenumber |
---|
1030 | */ |
---|
1031 | Proj4js.defs = { |
---|
1032 | // These are so widely used, we'll go ahead and throw them in |
---|
1033 | // without requiring a separate .js file |
---|
1034 | 'WGS84': "+title=long/lat:WGS84 +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees", |
---|
1035 | 'EPSG:4326': "+title=long/lat:WGS84 +proj=longlat +a=6378137.0 +b=6356752.31424518 +ellps=WGS84 +datum=WGS84 +units=degrees", |
---|
1036 | 'EPSG:4269': "+title=long/lat:NAD83 +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees", |
---|
1037 | 'EPSG:3785': "+title= Google Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs" |
---|
1038 | }; |
---|
1039 | Proj4js.defs['GOOGLE'] = Proj4js.defs['EPSG:3785']; |
---|
1040 | Proj4js.defs['EPSG:900913'] = Proj4js.defs['EPSG:3785']; |
---|
1041 | Proj4js.defs['EPSG:102113'] = Proj4js.defs['EPSG:3785']; |
---|
1042 | |
---|
1043 | Proj4js.common = { |
---|
1044 | PI : 3.141592653589793238, //Math.PI, |
---|
1045 | HALF_PI : 1.570796326794896619, //Math.PI*0.5, |
---|
1046 | TWO_PI : 6.283185307179586477, //Math.PI*2, |
---|
1047 | FORTPI : 0.78539816339744833, |
---|
1048 | R2D : 57.29577951308232088, |
---|
1049 | D2R : 0.01745329251994329577, |
---|
1050 | SEC_TO_RAD : 4.84813681109535993589914102357e-6, /* SEC_TO_RAD = Pi/180/3600 */ |
---|
1051 | EPSLN : 1.0e-10, |
---|
1052 | MAX_ITER : 20, |
---|
1053 | // following constants from geocent.c |
---|
1054 | COS_67P5 : 0.38268343236508977, /* cosine of 67.5 degrees */ |
---|
1055 | AD_C : 1.0026000, /* Toms region 1 constant */ |
---|
1056 | |
---|
1057 | /* datum_type values */ |
---|
1058 | PJD_UNKNOWN : 0, |
---|
1059 | PJD_3PARAM : 1, |
---|
1060 | PJD_7PARAM : 2, |
---|
1061 | PJD_GRIDSHIFT: 3, |
---|
1062 | PJD_WGS84 : 4, // WGS84 or equivalent |
---|
1063 | PJD_NODATUM : 5, // WGS84 or equivalent |
---|
1064 | SRS_WGS84_SEMIMAJOR : 6378137.0, // only used in grid shift transforms |
---|
1065 | |
---|
1066 | // ellipoid pj_set_ell.c |
---|
1067 | SIXTH : .1666666666666666667, /* 1/6 */ |
---|
1068 | RA4 : .04722222222222222222, /* 17/360 */ |
---|
1069 | RA6 : .02215608465608465608, /* 67/3024 */ |
---|
1070 | RV4 : .06944444444444444444, /* 5/72 */ |
---|
1071 | RV6 : .04243827160493827160, /* 55/1296 */ |
---|
1072 | |
---|
1073 | // Function to compute the constant small m which is the radius of |
---|
1074 | // a parallel of latitude, phi, divided by the semimajor axis. |
---|
1075 | // ----------------------------------------------------------------- |
---|
1076 | msfnz : function(eccent, sinphi, cosphi) { |
---|
1077 | var con = eccent * sinphi; |
---|
1078 | return cosphi/(Math.sqrt(1.0 - con * con)); |
---|
1079 | }, |
---|
1080 | |
---|
1081 | // Function to compute the constant small t for use in the forward |
---|
1082 | // computations in the Lambert Conformal Conic and the Polar |
---|
1083 | // Stereographic projections. |
---|
1084 | // ----------------------------------------------------------------- |
---|
1085 | tsfnz : function(eccent, phi, sinphi) { |
---|
1086 | var con = eccent * sinphi; |
---|
1087 | var com = .5 * eccent; |
---|
1088 | con = Math.pow(((1.0 - con) / (1.0 + con)), com); |
---|
1089 | return (Math.tan(.5 * (this.HALF_PI - phi))/con); |
---|
1090 | }, |
---|
1091 | |
---|
1092 | // Function to compute the latitude angle, phi2, for the inverse of the |
---|
1093 | // Lambert Conformal Conic and Polar Stereographic projections. |
---|
1094 | // ---------------------------------------------------------------- |
---|
1095 | phi2z : function(eccent, ts) { |
---|
1096 | var eccnth = .5 * eccent; |
---|
1097 | var con, dphi; |
---|
1098 | var phi = this.HALF_PI - 2 * Math.atan(ts); |
---|
1099 | for (var i = 0; i <= 15; i++) { |
---|
1100 | con = eccent * Math.sin(phi); |
---|
1101 | dphi = this.HALF_PI - 2 * Math.atan(ts *(Math.pow(((1.0 - con)/(1.0 + con)),eccnth))) - phi; |
---|
1102 | phi += dphi; |
---|
1103 | if (Math.abs(dphi) <= .0000000001) return phi; |
---|
1104 | } |
---|
1105 | alert("phi2z has NoConvergence"); |
---|
1106 | return (-9999); |
---|
1107 | }, |
---|
1108 | |
---|
1109 | /* Function to compute constant small q which is the radius of a |
---|
1110 | parallel of latitude, phi, divided by the semimajor axis. |
---|
1111 | ------------------------------------------------------------*/ |
---|
1112 | qsfnz : function(eccent,sinphi) { |
---|
1113 | var con; |
---|
1114 | if (eccent > 1.0e-7) { |
---|
1115 | con = eccent * sinphi; |
---|
1116 | return (( 1.0- eccent * eccent) * (sinphi /(1.0 - con * con) - (.5/eccent)*Math.log((1.0 - con)/(1.0 + con)))); |
---|
1117 | } else { |
---|
1118 | return(2.0 * sinphi); |
---|
1119 | } |
---|
1120 | }, |
---|
1121 | |
---|
1122 | /* Function to eliminate roundoff errors in asin |
---|
1123 | ----------------------------------------------*/ |
---|
1124 | asinz : function(x) { |
---|
1125 | if (Math.abs(x)>1.0) { |
---|
1126 | x=(x>1.0)?1.0:-1.0; |
---|
1127 | } |
---|
1128 | return Math.asin(x); |
---|
1129 | }, |
---|
1130 | |
---|
1131 | // following functions from gctpc cproj.c for transverse mercator projections |
---|
1132 | e0fn : function(x) {return(1.0-0.25*x*(1.0+x/16.0*(3.0+1.25*x)));}, |
---|
1133 | e1fn : function(x) {return(0.375*x*(1.0+0.25*x*(1.0+0.46875*x)));}, |
---|
1134 | e2fn : function(x) {return(0.05859375*x*x*(1.0+0.75*x));}, |
---|
1135 | e3fn : function(x) {return(x*x*x*(35.0/3072.0));}, |
---|
1136 | mlfn : function(e0,e1,e2,e3,phi) {return(e0*phi-e1*Math.sin(2.0*phi)+e2*Math.sin(4.0*phi)-e3*Math.sin(6.0*phi));}, |
---|
1137 | |
---|
1138 | srat : function(esinp, exp) { |
---|
1139 | return(Math.pow((1.0-esinp)/(1.0+esinp), exp)); |
---|
1140 | }, |
---|
1141 | |
---|
1142 | // Function to return the sign of an argument |
---|
1143 | sign : function(x) { if (x < 0.0) return(-1); else return(1);}, |
---|
1144 | |
---|
1145 | // Function to adjust longitude to -180 to 180; input in radians |
---|
1146 | adjust_lon : function(x) { |
---|
1147 | x = (Math.abs(x) < this.PI) ? x: (x - (this.sign(x)*this.TWO_PI) ); |
---|
1148 | return x; |
---|
1149 | }, |
---|
1150 | |
---|
1151 | // IGNF - DGR : algorithms used by IGN France |
---|
1152 | |
---|
1153 | // Function to adjust latitude to -90 to 90; input in radians |
---|
1154 | adjust_lat : function(x) { |
---|
1155 | x= (Math.abs(x) < this.HALF_PI) ? x: (x - (this.sign(x)*this.PI) ); |
---|
1156 | return x; |
---|
1157 | }, |
---|
1158 | |
---|
1159 | // Latitude Isometrique - close to tsfnz ... |
---|
1160 | latiso : function(eccent, phi, sinphi) { |
---|
1161 | if (Math.abs(phi) > this.HALF_PI) return +Number.NaN; |
---|
1162 | if (phi==this.HALF_PI) return Number.POSITIVE_INFINITY; |
---|
1163 | if (phi==-1.0*this.HALF_PI) return -1.0*Number.POSITIVE_INFINITY; |
---|
1164 | |
---|
1165 | var con= eccent*sinphi; |
---|
1166 | return Math.log(Math.tan((this.HALF_PI+phi)/2.0))+eccent*Math.log((1.0-con)/(1.0+con))/2.0; |
---|
1167 | }, |
---|
1168 | |
---|
1169 | fL : function(x,L) { |
---|
1170 | return 2.0*Math.atan(x*Math.exp(L)) - this.HALF_PI; |
---|
1171 | }, |
---|
1172 | |
---|
1173 | // Inverse Latitude Isometrique - close to ph2z |
---|
1174 | invlatiso : function(eccent, ts) { |
---|
1175 | var phi= this.fL(1.0,ts); |
---|
1176 | var Iphi= 0.0; |
---|
1177 | var con= 0.0; |
---|
1178 | do { |
---|
1179 | Iphi= phi; |
---|
1180 | con= eccent*Math.sin(Iphi); |
---|
1181 | phi= this.fL(Math.exp(eccent*Math.log((1.0+con)/(1.0-con))/2.0),ts) |
---|
1182 | } while (Math.abs(phi-Iphi)>1.0e-12); |
---|
1183 | return phi; |
---|
1184 | }, |
---|
1185 | |
---|
1186 | // Needed for Gauss Schreiber |
---|
1187 | // Original: Denis Makarov (info@binarythings.com) |
---|
1188 | // Web Site: http://www.binarythings.com |
---|
1189 | sinh : function(x) |
---|
1190 | { |
---|
1191 | var r= Math.exp(x); |
---|
1192 | r= (r-1.0/r)/2.0; |
---|
1193 | return r; |
---|
1194 | }, |
---|
1195 | |
---|
1196 | cosh : function(x) |
---|
1197 | { |
---|
1198 | var r= Math.exp(x); |
---|
1199 | r= (r+1.0/r)/2.0; |
---|
1200 | return r; |
---|
1201 | }, |
---|
1202 | |
---|
1203 | tanh : function(x) |
---|
1204 | { |
---|
1205 | var r= Math.exp(x); |
---|
1206 | r= (r-1.0/r)/(r+1.0/r); |
---|
1207 | return r; |
---|
1208 | }, |
---|
1209 | |
---|
1210 | asinh : function(x) |
---|
1211 | { |
---|
1212 | var s= (x>= 0? 1.0:-1.0); |
---|
1213 | return s*(Math.log( Math.abs(x) + Math.sqrt(x*x+1.0) )); |
---|
1214 | }, |
---|
1215 | |
---|
1216 | acosh : function(x) |
---|
1217 | { |
---|
1218 | return 2.0*Math.log(Math.sqrt((x+1.0)/2.0) + Math.sqrt((x-1.0)/2.0)); |
---|
1219 | }, |
---|
1220 | |
---|
1221 | atanh : function(x) |
---|
1222 | { |
---|
1223 | return Math.log((x-1.0)/(x+1.0))/2.0; |
---|
1224 | }, |
---|
1225 | |
---|
1226 | // Grande Normale |
---|
1227 | gN : function(a,e,sinphi) |
---|
1228 | { |
---|
1229 | var temp= e*sinphi; |
---|
1230 | return a/Math.sqrt(1.0 - temp*temp); |
---|
1231 | } |
---|
1232 | |
---|
1233 | }; |
---|
1234 | |
---|
1235 | /** datum object |
---|
1236 | */ |
---|
1237 | Proj4js.datum = Proj4js.Class({ |
---|
1238 | |
---|
1239 | initialize : function(proj) { |
---|
1240 | this.datum_type = Proj4js.common.PJD_WGS84; //default setting |
---|
1241 | if (proj.datumCode && proj.datumCode == 'none') { |
---|
1242 | this.datum_type = Proj4js.common.PJD_NODATUM; |
---|
1243 | } |
---|
1244 | if (proj && proj.datum_params) { |
---|
1245 | for (var i=0; i<proj.datum_params.length; i++) { |
---|
1246 | proj.datum_params[i]=parseFloat(proj.datum_params[i]); |
---|
1247 | } |
---|
1248 | if (proj.datum_params[0] != 0 || proj.datum_params[1] != 0 || proj.datum_params[2] != 0 ) { |
---|
1249 | this.datum_type = Proj4js.common.PJD_3PARAM; |
---|
1250 | } |
---|
1251 | if (proj.datum_params.length > 3) { |
---|
1252 | if (proj.datum_params[3] != 0 || proj.datum_params[4] != 0 || |
---|
1253 | proj.datum_params[5] != 0 || proj.datum_params[6] != 0 ) { |
---|
1254 | this.datum_type = Proj4js.common.PJD_7PARAM; |
---|
1255 | proj.datum_params[3] *= Proj4js.common.SEC_TO_RAD; |
---|
1256 | proj.datum_params[4] *= Proj4js.common.SEC_TO_RAD; |
---|
1257 | proj.datum_params[5] *= Proj4js.common.SEC_TO_RAD; |
---|
1258 | proj.datum_params[6] = (proj.datum_params[6]/1000000.0) + 1.0; |
---|
1259 | } |
---|
1260 | } |
---|
1261 | } |
---|
1262 | if (proj) { |
---|
1263 | this.a = proj.a; //datum object also uses these values |
---|
1264 | this.b = proj.b; |
---|
1265 | this.es = proj.es; |
---|
1266 | this.ep2 = proj.ep2; |
---|
1267 | this.datum_params = proj.datum_params; |
---|
1268 | } |
---|
1269 | }, |
---|
1270 | |
---|
1271 | /****************************************************************/ |
---|
1272 | // cs_compare_datums() |
---|
1273 | // Returns 1 (TRUE) if the two datums match, otherwise 0 (FALSE). |
---|
1274 | compare_datums : function( dest ) { |
---|
1275 | if( this.datum_type != dest.datum_type ) { |
---|
1276 | return false; // false, datums are not equal |
---|
1277 | } else if( this.a != dest.a || Math.abs(this.es-dest.es) > 0.000000000050 ) { |
---|
1278 | // the tolerence for es is to ensure that GRS80 and WGS84 |
---|
1279 | // are considered identical |
---|
1280 | return false; |
---|
1281 | } else if( this.datum_type == Proj4js.common.PJD_3PARAM ) { |
---|
1282 | return (this.datum_params[0] == dest.datum_params[0] |
---|
1283 | && this.datum_params[1] == dest.datum_params[1] |
---|
1284 | && this.datum_params[2] == dest.datum_params[2]); |
---|
1285 | } else if( this.datum_type == Proj4js.common.PJD_7PARAM ) { |
---|
1286 | return (this.datum_params[0] == dest.datum_params[0] |
---|
1287 | && this.datum_params[1] == dest.datum_params[1] |
---|
1288 | && this.datum_params[2] == dest.datum_params[2] |
---|
1289 | && this.datum_params[3] == dest.datum_params[3] |
---|
1290 | && this.datum_params[4] == dest.datum_params[4] |
---|
1291 | && this.datum_params[5] == dest.datum_params[5] |
---|
1292 | && this.datum_params[6] == dest.datum_params[6]); |
---|
1293 | } else if( this.datum_type == Proj4js.common.PJD_GRIDSHIFT ) { |
---|
1294 | return strcmp( pj_param(this.params,"snadgrids").s, |
---|
1295 | pj_param(dest.params,"snadgrids").s ) == 0; |
---|
1296 | } else { |
---|
1297 | return true; // datums are equal |
---|
1298 | } |
---|
1299 | }, // cs_compare_datums() |
---|
1300 | |
---|
1301 | /* |
---|
1302 | * The function Convert_Geodetic_To_Geocentric converts geodetic coordinates |
---|
1303 | * (latitude, longitude, and height) to geocentric coordinates (X, Y, Z), |
---|
1304 | * according to the current ellipsoid parameters. |
---|
1305 | * |
---|
1306 | * Latitude : Geodetic latitude in radians (input) |
---|
1307 | * Longitude : Geodetic longitude in radians (input) |
---|
1308 | * Height : Geodetic height, in meters (input) |
---|
1309 | * X : Calculated Geocentric X coordinate, in meters (output) |
---|
1310 | * Y : Calculated Geocentric Y coordinate, in meters (output) |
---|
1311 | * Z : Calculated Geocentric Z coordinate, in meters (output) |
---|
1312 | * |
---|
1313 | */ |
---|
1314 | geodetic_to_geocentric : function(p) { |
---|
1315 | var Longitude = p.x; |
---|
1316 | var Latitude = p.y; |
---|
1317 | var Height = p.z ? p.z : 0; //Z value not always supplied |
---|
1318 | var X; // output |
---|
1319 | var Y; |
---|
1320 | var Z; |
---|
1321 | |
---|
1322 | var Error_Code=0; // GEOCENT_NO_ERROR; |
---|
1323 | var Rn; /* Earth radius at location */ |
---|
1324 | var Sin_Lat; /* Math.sin(Latitude) */ |
---|
1325 | var Sin2_Lat; /* Square of Math.sin(Latitude) */ |
---|
1326 | var Cos_Lat; /* Math.cos(Latitude) */ |
---|
1327 | |
---|
1328 | /* |
---|
1329 | ** Don't blow up if Latitude is just a little out of the value |
---|
1330 | ** range as it may just be a rounding issue. Also removed longitude |
---|
1331 | ** test, it should be wrapped by Math.cos() and Math.sin(). NFW for PROJ.4, Sep/2001. |
---|
1332 | */ |
---|
1333 | if( Latitude < -Proj4js.common.HALF_PI && Latitude > -1.001 * Proj4js.common.HALF_PI ) { |
---|
1334 | Latitude = -Proj4js.common.HALF_PI; |
---|
1335 | } else if( Latitude > Proj4js.common.HALF_PI && Latitude < 1.001 * Proj4js.common.HALF_PI ) { |
---|
1336 | Latitude = Proj4js.common.HALF_PI; |
---|
1337 | } else if ((Latitude < -Proj4js.common.HALF_PI) || (Latitude > Proj4js.common.HALF_PI)) { |
---|
1338 | /* Latitude out of range */ |
---|
1339 | Proj4js.reportError('geocent:lat out of range:'+Latitude); |
---|
1340 | return null; |
---|
1341 | } |
---|
1342 | |
---|
1343 | if (Longitude > Proj4js.common.PI) Longitude -= (2*Proj4js.common.PI); |
---|
1344 | Sin_Lat = Math.sin(Latitude); |
---|
1345 | Cos_Lat = Math.cos(Latitude); |
---|
1346 | Sin2_Lat = Sin_Lat * Sin_Lat; |
---|
1347 | Rn = this.a / (Math.sqrt(1.0e0 - this.es * Sin2_Lat)); |
---|
1348 | X = (Rn + Height) * Cos_Lat * Math.cos(Longitude); |
---|
1349 | Y = (Rn + Height) * Cos_Lat * Math.sin(Longitude); |
---|
1350 | Z = ((Rn * (1 - this.es)) + Height) * Sin_Lat; |
---|
1351 | |
---|
1352 | p.x = X; |
---|
1353 | p.y = Y; |
---|
1354 | p.z = Z; |
---|
1355 | return Error_Code; |
---|
1356 | }, // cs_geodetic_to_geocentric() |
---|
1357 | |
---|
1358 | |
---|
1359 | geocentric_to_geodetic : function (p) { |
---|
1360 | /* local defintions and variables */ |
---|
1361 | /* end-criterium of loop, accuracy of sin(Latitude) */ |
---|
1362 | var genau = 1.E-12; |
---|
1363 | var genau2 = (genau*genau); |
---|
1364 | var maxiter = 30; |
---|
1365 | |
---|
1366 | var P; /* distance between semi-minor axis and location */ |
---|
1367 | var RR; /* distance between center and location */ |
---|
1368 | var CT; /* sin of geocentric latitude */ |
---|
1369 | var ST; /* cos of geocentric latitude */ |
---|
1370 | var RX; |
---|
1371 | var RK; |
---|
1372 | var RN; /* Earth radius at location */ |
---|
1373 | var CPHI0; /* cos of start or old geodetic latitude in iterations */ |
---|
1374 | var SPHI0; /* sin of start or old geodetic latitude in iterations */ |
---|
1375 | var CPHI; /* cos of searched geodetic latitude */ |
---|
1376 | var SPHI; /* sin of searched geodetic latitude */ |
---|
1377 | var SDPHI; /* end-criterium: addition-theorem of sin(Latitude(iter)-Latitude(iter-1)) */ |
---|
1378 | var At_Pole; /* indicates location is in polar region */ |
---|
1379 | var iter; /* # of continous iteration, max. 30 is always enough (s.a.) */ |
---|
1380 | |
---|
1381 | var X = p.x; |
---|
1382 | var Y = p.y; |
---|
1383 | var Z = p.z ? p.z : 0.0; //Z value not always supplied |
---|
1384 | var Longitude; |
---|
1385 | var Latitude; |
---|
1386 | var Height; |
---|
1387 | |
---|
1388 | At_Pole = false; |
---|
1389 | P = Math.sqrt(X*X+Y*Y); |
---|
1390 | RR = Math.sqrt(X*X+Y*Y+Z*Z); |
---|
1391 | |
---|
1392 | /* special cases for latitude and longitude */ |
---|
1393 | if (P/this.a < genau) { |
---|
1394 | |
---|
1395 | /* special case, if P=0. (X=0., Y=0.) */ |
---|
1396 | At_Pole = true; |
---|
1397 | Longitude = 0.0; |
---|
1398 | |
---|
1399 | /* if (X,Y,Z)=(0.,0.,0.) then Height becomes semi-minor axis |
---|
1400 | * of ellipsoid (=center of mass), Latitude becomes PI/2 */ |
---|
1401 | if (RR/this.a < genau) { |
---|
1402 | Latitude = Proj4js.common.HALF_PI; |
---|
1403 | Height = -this.b; |
---|
1404 | return; |
---|
1405 | } |
---|
1406 | } else { |
---|
1407 | /* ellipsoidal (geodetic) longitude |
---|
1408 | * interval: -PI < Longitude <= +PI */ |
---|
1409 | Longitude=Math.atan2(Y,X); |
---|
1410 | } |
---|
1411 | |
---|
1412 | /* -------------------------------------------------------------- |
---|
1413 | * Following iterative algorithm was developped by |
---|
1414 | * "Institut fï¿œr Erdmessung", University of Hannover, July 1988. |
---|
1415 | * Internet: www.ife.uni-hannover.de |
---|
1416 | * Iterative computation of CPHI,SPHI and Height. |
---|
1417 | * Iteration of CPHI and SPHI to 10**-12 radian resp. |
---|
1418 | * 2*10**-7 arcsec. |
---|
1419 | * -------------------------------------------------------------- |
---|
1420 | */ |
---|
1421 | CT = Z/RR; |
---|
1422 | ST = P/RR; |
---|
1423 | RX = 1.0/Math.sqrt(1.0-this.es*(2.0-this.es)*ST*ST); |
---|
1424 | CPHI0 = ST*(1.0-this.es)*RX; |
---|
1425 | SPHI0 = CT*RX; |
---|
1426 | iter = 0; |
---|
1427 | |
---|
1428 | /* loop to find sin(Latitude) resp. Latitude |
---|
1429 | * until |sin(Latitude(iter)-Latitude(iter-1))| < genau */ |
---|
1430 | do |
---|
1431 | { |
---|
1432 | iter++; |
---|
1433 | RN = this.a/Math.sqrt(1.0-this.es*SPHI0*SPHI0); |
---|
1434 | |
---|
1435 | /* ellipsoidal (geodetic) height */ |
---|
1436 | Height = P*CPHI0+Z*SPHI0-RN*(1.0-this.es*SPHI0*SPHI0); |
---|
1437 | |
---|
1438 | RK = this.es*RN/(RN+Height); |
---|
1439 | RX = 1.0/Math.sqrt(1.0-RK*(2.0-RK)*ST*ST); |
---|
1440 | CPHI = ST*(1.0-RK)*RX; |
---|
1441 | SPHI = CT*RX; |
---|
1442 | SDPHI = SPHI*CPHI0-CPHI*SPHI0; |
---|
1443 | CPHI0 = CPHI; |
---|
1444 | SPHI0 = SPHI; |
---|
1445 | } |
---|
1446 | while (SDPHI*SDPHI > genau2 && iter < maxiter); |
---|
1447 | |
---|
1448 | /* ellipsoidal (geodetic) latitude */ |
---|
1449 | Latitude=Math.atan(SPHI/Math.abs(CPHI)); |
---|
1450 | |
---|
1451 | p.x = Longitude; |
---|
1452 | p.y = Latitude; |
---|
1453 | p.z = Height; |
---|
1454 | return p; |
---|
1455 | }, // cs_geocentric_to_geodetic() |
---|
1456 | |
---|
1457 | /** Convert_Geocentric_To_Geodetic |
---|
1458 | * The method used here is derived from 'An Improved Algorithm for |
---|
1459 | * Geocentric to Geodetic Coordinate Conversion', by Ralph Toms, Feb 1996 |
---|
1460 | */ |
---|
1461 | geocentric_to_geodetic_noniter : function (p) { |
---|
1462 | var X = p.x; |
---|
1463 | var Y = p.y; |
---|
1464 | var Z = p.z ? p.z : 0; //Z value not always supplied |
---|
1465 | var Longitude; |
---|
1466 | var Latitude; |
---|
1467 | var Height; |
---|
1468 | |
---|
1469 | var W; /* distance from Z axis */ |
---|
1470 | var W2; /* square of distance from Z axis */ |
---|
1471 | var T0; /* initial estimate of vertical component */ |
---|
1472 | var T1; /* corrected estimate of vertical component */ |
---|
1473 | var S0; /* initial estimate of horizontal component */ |
---|
1474 | var S1; /* corrected estimate of horizontal component */ |
---|
1475 | var Sin_B0; /* Math.sin(B0), B0 is estimate of Bowring aux variable */ |
---|
1476 | var Sin3_B0; /* cube of Math.sin(B0) */ |
---|
1477 | var Cos_B0; /* Math.cos(B0) */ |
---|
1478 | var Sin_p1; /* Math.sin(phi1), phi1 is estimated latitude */ |
---|
1479 | var Cos_p1; /* Math.cos(phi1) */ |
---|
1480 | var Rn; /* Earth radius at location */ |
---|
1481 | var Sum; /* numerator of Math.cos(phi1) */ |
---|
1482 | var At_Pole; /* indicates location is in polar region */ |
---|
1483 | |
---|
1484 | X = parseFloat(X); // cast from string to float |
---|
1485 | Y = parseFloat(Y); |
---|
1486 | Z = parseFloat(Z); |
---|
1487 | |
---|
1488 | At_Pole = false; |
---|
1489 | if (X != 0.0) |
---|
1490 | { |
---|
1491 | Longitude = Math.atan2(Y,X); |
---|
1492 | } |
---|
1493 | else |
---|
1494 | { |
---|
1495 | if (Y > 0) |
---|
1496 | { |
---|
1497 | Longitude = Proj4js.common.HALF_PI; |
---|
1498 | } |
---|
1499 | else if (Y < 0) |
---|
1500 | { |
---|
1501 | Longitude = -Proj4js.common.HALF_PI; |
---|
1502 | } |
---|
1503 | else |
---|
1504 | { |
---|
1505 | At_Pole = true; |
---|
1506 | Longitude = 0.0; |
---|
1507 | if (Z > 0.0) |
---|
1508 | { /* north pole */ |
---|
1509 | Latitude = Proj4js.common.HALF_PI; |
---|
1510 | } |
---|
1511 | else if (Z < 0.0) |
---|
1512 | { /* south pole */ |
---|
1513 | Latitude = -Proj4js.common.HALF_PI; |
---|
1514 | } |
---|
1515 | else |
---|
1516 | { /* center of earth */ |
---|
1517 | Latitude = Proj4js.common.HALF_PI; |
---|
1518 | Height = -this.b; |
---|
1519 | return; |
---|
1520 | } |
---|
1521 | } |
---|
1522 | } |
---|
1523 | W2 = X*X + Y*Y; |
---|
1524 | W = Math.sqrt(W2); |
---|
1525 | T0 = Z * Proj4js.common.AD_C; |
---|
1526 | S0 = Math.sqrt(T0 * T0 + W2); |
---|
1527 | Sin_B0 = T0 / S0; |
---|
1528 | Cos_B0 = W / S0; |
---|
1529 | Sin3_B0 = Sin_B0 * Sin_B0 * Sin_B0; |
---|
1530 | T1 = Z + this.b * this.ep2 * Sin3_B0; |
---|
1531 | Sum = W - this.a * this.es * Cos_B0 * Cos_B0 * Cos_B0; |
---|
1532 | S1 = Math.sqrt(T1*T1 + Sum * Sum); |
---|
1533 | Sin_p1 = T1 / S1; |
---|
1534 | Cos_p1 = Sum / S1; |
---|
1535 | Rn = this.a / Math.sqrt(1.0 - this.es * Sin_p1 * Sin_p1); |
---|
1536 | if (Cos_p1 >= Proj4js.common.COS_67P5) |
---|
1537 | { |
---|
1538 | Height = W / Cos_p1 - Rn; |
---|
1539 | } |
---|
1540 | else if (Cos_p1 <= -Proj4js.common.COS_67P5) |
---|
1541 | { |
---|
1542 | Height = W / -Cos_p1 - Rn; |
---|
1543 | } |
---|
1544 | else |
---|
1545 | { |
---|
1546 | Height = Z / Sin_p1 + Rn * (this.es - 1.0); |
---|
1547 | } |
---|
1548 | if (At_Pole == false) |
---|
1549 | { |
---|
1550 | Latitude = Math.atan(Sin_p1 / Cos_p1); |
---|
1551 | } |
---|
1552 | |
---|
1553 | p.x = Longitude; |
---|
1554 | p.y = Latitude; |
---|
1555 | p.z = Height; |
---|
1556 | return p; |
---|
1557 | }, // geocentric_to_geodetic_noniter() |
---|
1558 | |
---|
1559 | /****************************************************************/ |
---|
1560 | // pj_geocentic_to_wgs84( p ) |
---|
1561 | // p = point to transform in geocentric coordinates (x,y,z) |
---|
1562 | geocentric_to_wgs84 : function ( p ) { |
---|
1563 | |
---|
1564 | if( this.datum_type == Proj4js.common.PJD_3PARAM ) |
---|
1565 | { |
---|
1566 | // if( x[io] == HUGE_VAL ) |
---|
1567 | // continue; |
---|
1568 | p.x += this.datum_params[0]; |
---|
1569 | p.y += this.datum_params[1]; |
---|
1570 | p.z += this.datum_params[2]; |
---|
1571 | |
---|
1572 | } |
---|
1573 | else if (this.datum_type == Proj4js.common.PJD_7PARAM) |
---|
1574 | { |
---|
1575 | var Dx_BF =this.datum_params[0]; |
---|
1576 | var Dy_BF =this.datum_params[1]; |
---|
1577 | var Dz_BF =this.datum_params[2]; |
---|
1578 | var Rx_BF =this.datum_params[3]; |
---|
1579 | var Ry_BF =this.datum_params[4]; |
---|
1580 | var Rz_BF =this.datum_params[5]; |
---|
1581 | var M_BF =this.datum_params[6]; |
---|
1582 | // if( x[io] == HUGE_VAL ) |
---|
1583 | // continue; |
---|
1584 | var x_out = M_BF*( p.x - Rz_BF*p.y + Ry_BF*p.z) + Dx_BF; |
---|
1585 | var y_out = M_BF*( Rz_BF*p.x + p.y - Rx_BF*p.z) + Dy_BF; |
---|
1586 | var z_out = M_BF*(-Ry_BF*p.x + Rx_BF*p.y + p.z) + Dz_BF; |
---|
1587 | p.x = x_out; |
---|
1588 | p.y = y_out; |
---|
1589 | p.z = z_out; |
---|
1590 | } |
---|
1591 | }, // cs_geocentric_to_wgs84 |
---|
1592 | |
---|
1593 | /****************************************************************/ |
---|
1594 | // pj_geocentic_from_wgs84() |
---|
1595 | // coordinate system definition, |
---|
1596 | // point to transform in geocentric coordinates (x,y,z) |
---|
1597 | geocentric_from_wgs84 : function( p ) { |
---|
1598 | |
---|
1599 | if( this.datum_type == Proj4js.common.PJD_3PARAM ) |
---|
1600 | { |
---|
1601 | //if( x[io] == HUGE_VAL ) |
---|
1602 | // continue; |
---|
1603 | p.x -= this.datum_params[0]; |
---|
1604 | p.y -= this.datum_params[1]; |
---|
1605 | p.z -= this.datum_params[2]; |
---|
1606 | |
---|
1607 | } |
---|
1608 | else if (this.datum_type == Proj4js.common.PJD_7PARAM) |
---|
1609 | { |
---|
1610 | var Dx_BF =this.datum_params[0]; |
---|
1611 | var Dy_BF =this.datum_params[1]; |
---|
1612 | var Dz_BF =this.datum_params[2]; |
---|
1613 | var Rx_BF =this.datum_params[3]; |
---|
1614 | var Ry_BF =this.datum_params[4]; |
---|
1615 | var Rz_BF =this.datum_params[5]; |
---|
1616 | var M_BF =this.datum_params[6]; |
---|
1617 | var x_tmp = (p.x - Dx_BF) / M_BF; |
---|
1618 | var y_tmp = (p.y - Dy_BF) / M_BF; |
---|
1619 | var z_tmp = (p.z - Dz_BF) / M_BF; |
---|
1620 | //if( x[io] == HUGE_VAL ) |
---|
1621 | // continue; |
---|
1622 | |
---|
1623 | p.x = x_tmp + Rz_BF*y_tmp - Ry_BF*z_tmp; |
---|
1624 | p.y = -Rz_BF*x_tmp + y_tmp + Rx_BF*z_tmp; |
---|
1625 | p.z = Ry_BF*x_tmp - Rx_BF*y_tmp + z_tmp; |
---|
1626 | } //cs_geocentric_from_wgs84() |
---|
1627 | } |
---|
1628 | }); |
---|
1629 | |
---|
1630 | /** point object, nothing fancy, just allows values to be |
---|
1631 | passed back and forth by reference rather than by value. |
---|
1632 | Other point classes may be used as long as they have |
---|
1633 | x and y properties, which will get modified in the transform method. |
---|
1634 | */ |
---|
1635 | Proj4js.Point = Proj4js.Class({ |
---|
1636 | |
---|
1637 | /** |
---|
1638 | * Constructor: Proj4js.Point |
---|
1639 | * |
---|
1640 | * Parameters: |
---|
1641 | * - x {float} or {Array} either the first coordinates component or |
---|
1642 | * the full coordinates |
---|
1643 | * - y {float} the second component |
---|
1644 | * - z {float} the third component, optional. |
---|
1645 | */ |
---|
1646 | initialize : function(x,y,z) { |
---|
1647 | if (typeof x == 'object') { |
---|
1648 | this.x = x[0]; |
---|
1649 | this.y = x[1]; |
---|
1650 | this.z = x[2] || 0.0; |
---|
1651 | } else if (typeof x == 'string' && typeof y == 'undefined') { |
---|
1652 | var coords = x.split(','); |
---|
1653 | this.x = parseFloat(coords[0]); |
---|
1654 | this.y = parseFloat(coords[1]); |
---|
1655 | this.z = parseFloat(coords[2]) || 0.0; |
---|
1656 | } else { |
---|
1657 | this.x = x; |
---|
1658 | this.y = y; |
---|
1659 | this.z = z || 0.0; |
---|
1660 | } |
---|
1661 | }, |
---|
1662 | |
---|
1663 | /** |
---|
1664 | * APIMethod: clone |
---|
1665 | * Build a copy of a Proj4js.Point object. |
---|
1666 | * |
---|
1667 | * Return: |
---|
1668 | * {Proj4js}.Point the cloned point. |
---|
1669 | */ |
---|
1670 | clone : function() { |
---|
1671 | return new Proj4js.Point(this.x, this.y, this.z); |
---|
1672 | }, |
---|
1673 | |
---|
1674 | /** |
---|
1675 | * APIMethod: toString |
---|
1676 | * Return a readable string version of the point |
---|
1677 | * |
---|
1678 | * Return: |
---|
1679 | * {String} String representation of Proj4js.Point object. |
---|
1680 | * (ex. <i>"x=5,y=42"</i>) |
---|
1681 | */ |
---|
1682 | toString : function() { |
---|
1683 | return ("x=" + this.x + ",y=" + this.y); |
---|
1684 | }, |
---|
1685 | |
---|
1686 | /** |
---|
1687 | * APIMethod: toShortString |
---|
1688 | * Return a short string version of the point. |
---|
1689 | * |
---|
1690 | * Return: |
---|
1691 | * {String} Shortened String representation of Proj4js.Point object. |
---|
1692 | * (ex. <i>"5, 42"</i>) |
---|
1693 | */ |
---|
1694 | toShortString : function() { |
---|
1695 | return (this.x + ", " + this.y); |
---|
1696 | } |
---|
1697 | }); |
---|
1698 | |
---|
1699 | Proj4js.PrimeMeridian = { |
---|
1700 | "greenwich": 0.0, //"0dE", |
---|
1701 | "lisbon": -9.131906111111, //"9d07'54.862\"W", |
---|
1702 | "paris": 2.337229166667, //"2d20'14.025\"E", |
---|
1703 | "bogota": -74.080916666667, //"74d04'51.3\"W", |
---|
1704 | "madrid": -3.687938888889, //"3d41'16.58\"W", |
---|
1705 | "rome": 12.452333333333, //"12d27'8.4\"E", |
---|
1706 | "bern": 7.439583333333, //"7d26'22.5\"E", |
---|
1707 | "jakarta": 106.807719444444, //"106d48'27.79\"E", |
---|
1708 | "ferro": -17.666666666667, //"17d40'W", |
---|
1709 | "brussels": 4.367975, //"4d22'4.71\"E", |
---|
1710 | "stockholm": 18.058277777778, //"18d3'29.8\"E", |
---|
1711 | "athens": 23.7163375, //"23d42'58.815\"E", |
---|
1712 | "oslo": 10.722916666667 //"10d43'22.5\"E" |
---|
1713 | }; |
---|
1714 | |
---|
1715 | Proj4js.Ellipsoid = { |
---|
1716 | "MERIT": {a:6378137.0, rf:298.257, ellipseName:"MERIT 1983"}, |
---|
1717 | "SGS85": {a:6378136.0, rf:298.257, ellipseName:"Soviet Geodetic System 85"}, |
---|
1718 | "GRS80": {a:6378137.0, rf:298.257222101, ellipseName:"GRS 1980(IUGG, 1980)"}, |
---|
1719 | "IAU76": {a:6378140.0, rf:298.257, ellipseName:"IAU 1976"}, |
---|
1720 | "airy": {a:6377563.396, b:6356256.910, ellipseName:"Airy 1830"}, |
---|
1721 | "APL4.": {a:6378137, rf:298.25, ellipseName:"Appl. Physics. 1965"}, |
---|
1722 | "NWL9D": {a:6378145.0, rf:298.25, ellipseName:"Naval Weapons Lab., 1965"}, |
---|
1723 | "mod_airy": {a:6377340.189, b:6356034.446, ellipseName:"Modified Airy"}, |
---|
1724 | "andrae": {a:6377104.43, rf:300.0, ellipseName:"Andrae 1876 (Den., Iclnd.)"}, |
---|
1725 | "aust_SA": {a:6378160.0, rf:298.25, ellipseName:"Australian Natl & S. Amer. 1969"}, |
---|
1726 | "GRS67": {a:6378160.0, rf:298.2471674270, ellipseName:"GRS 67(IUGG 1967)"}, |
---|
1727 | "bessel": {a:6377397.155, rf:299.1528128, ellipseName:"Bessel 1841"}, |
---|
1728 | "bess_nam": {a:6377483.865, rf:299.1528128, ellipseName:"Bessel 1841 (Namibia)"}, |
---|
1729 | "clrk66": {a:6378206.4, b:6356583.8, ellipseName:"Clarke 1866"}, |
---|
1730 | "clrk80": {a:6378249.145, rf:293.4663, ellipseName:"Clarke 1880 mod."}, |
---|
1731 | "CPM": {a:6375738.7, rf:334.29, ellipseName:"Comm. des Poids et Mesures 1799"}, |
---|
1732 | "delmbr": {a:6376428.0, rf:311.5, ellipseName:"Delambre 1810 (Belgium)"}, |
---|
1733 | "engelis": {a:6378136.05, rf:298.2566, ellipseName:"Engelis 1985"}, |
---|
1734 | "evrst30": {a:6377276.345, rf:300.8017, ellipseName:"Everest 1830"}, |
---|
1735 | "evrst48": {a:6377304.063, rf:300.8017, ellipseName:"Everest 1948"}, |
---|
1736 | "evrst56": {a:6377301.243, rf:300.8017, ellipseName:"Everest 1956"}, |
---|
1737 | "evrst69": {a:6377295.664, rf:300.8017, ellipseName:"Everest 1969"}, |
---|
1738 | "evrstSS": {a:6377298.556, rf:300.8017, ellipseName:"Everest (Sabah & Sarawak)"}, |
---|
1739 | "fschr60": {a:6378166.0, rf:298.3, ellipseName:"Fischer (Mercury Datum) 1960"}, |
---|
1740 | "fschr60m": {a:6378155.0, rf:298.3, ellipseName:"Fischer 1960"}, |
---|
1741 | "fschr68": {a:6378150.0, rf:298.3, ellipseName:"Fischer 1968"}, |
---|
1742 | "helmert": {a:6378200.0, rf:298.3, ellipseName:"Helmert 1906"}, |
---|
1743 | "hough": {a:6378270.0, rf:297.0, ellipseName:"Hough"}, |
---|
1744 | "intl": {a:6378388.0, rf:297.0, ellipseName:"International 1909 (Hayford)"}, |
---|
1745 | "kaula": {a:6378163.0, rf:298.24, ellipseName:"Kaula 1961"}, |
---|
1746 | "lerch": {a:6378139.0, rf:298.257, ellipseName:"Lerch 1979"}, |
---|
1747 | "mprts": {a:6397300.0, rf:191.0, ellipseName:"Maupertius 1738"}, |
---|
1748 | "new_intl": {a:6378157.5, b:6356772.2, ellipseName:"New International 1967"}, |
---|
1749 | "plessis": {a:6376523.0, rf:6355863.0, ellipseName:"Plessis 1817 (France)"}, |
---|
1750 | "krass": {a:6378245.0, rf:298.3, ellipseName:"Krassovsky, 1942"}, |
---|
1751 | "SEasia": {a:6378155.0, b:6356773.3205, ellipseName:"Southeast Asia"}, |
---|
1752 | "walbeck": {a:6376896.0, b:6355834.8467, ellipseName:"Walbeck"}, |
---|
1753 | "WGS60": {a:6378165.0, rf:298.3, ellipseName:"WGS 60"}, |
---|
1754 | "WGS66": {a:6378145.0, rf:298.25, ellipseName:"WGS 66"}, |
---|
1755 | "WGS72": {a:6378135.0, rf:298.26, ellipseName:"WGS 72"}, |
---|
1756 | "WGS84": {a:6378137.0, rf:298.257223563, ellipseName:"WGS 84"}, |
---|
1757 | "sphere": {a:6370997.0, b:6370997.0, ellipseName:"Normal Sphere (r=6370997)"} |
---|
1758 | }; |
---|
1759 | |
---|
1760 | Proj4js.Datum = { |
---|
1761 | "WGS84": {towgs84: "0,0,0", ellipse: "WGS84", datumName: "WGS84"}, |
---|
1762 | "GGRS87": {towgs84: "-199.87,74.79,246.62", ellipse: "GRS80", datumName: "Greek_Geodetic_Reference_System_1987"}, |
---|
1763 | "NAD83": {towgs84: "0,0,0", ellipse: "GRS80", datumName: "North_American_Datum_1983"}, |
---|
1764 | "NAD27": {nadgrids: "@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat", ellipse: "clrk66", datumName: "North_American_Datum_1927"}, |
---|
1765 | "potsdam": {towgs84: "606.0,23.0,413.0", ellipse: "bessel", datumName: "Potsdam Rauenberg 1950 DHDN"}, |
---|
1766 | "carthage": {towgs84: "-263.0,6.0,431.0", ellipse: "clark80", datumName: "Carthage 1934 Tunisia"}, |
---|
1767 | "hermannskogel": {towgs84: "653.0,-212.0,449.0", ellipse: "bessel", datumName: "Hermannskogel"}, |
---|
1768 | "ire65": {towgs84: "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15", ellipse: "mod_airy", datumName: "Ireland 1965"}, |
---|
1769 | "nzgd49": {towgs84: "59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993", ellipse: "intl", datumName: "New Zealand Geodetic Datum 1949"}, |
---|
1770 | "OSGB36": {towgs84: "446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894", ellipse: "airy", datumName: "Airy 1830"} |
---|
1771 | }; |
---|
1772 | |
---|
1773 | Proj4js.WGS84 = new Proj4js.Proj('WGS84'); |
---|
1774 | Proj4js.Datum['OSB36'] = Proj4js.Datum['OSGB36']; //as returned from spatialreference.org |
---|
1775 | |
---|
1776 | //lookup table to go from the projection name in WKT to the Proj4js projection name |
---|
1777 | //build this out as required |
---|
1778 | Proj4js.wktProjections = { |
---|
1779 | "Lambert Tangential Conformal Conic Projection": "lcc", |
---|
1780 | "Mercator": "merc", |
---|
1781 | "Popular Visualisation Pseudo Mercator": "merc", |
---|
1782 | "Transverse_Mercator": "tmerc", |
---|
1783 | "Transverse Mercator": "tmerc", |
---|
1784 | "Lambert Azimuthal Equal Area": "laea", |
---|
1785 | "Universal Transverse Mercator System": "utm" |
---|
1786 | }; |
---|
1787 | |
---|
1788 | |
---|