/webportal/src/main/webapp/scripts/proj4js-combined.js
JavaScript | 4987 lines | 2984 code | 537 blank | 1466 comment | 547 complexity | 4f9fc4de15ecf4ff75223155d283a4c8 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
1/* 2 proj4js.js -- Javascript reprojection library. 3 4 Authors: Mike Adair madairATdmsolutions.ca 5 Richard Greenwood richATgreenwoodmap.com 6 Didier Richard didier.richardATign.fr 7 Stephen Irons 8 License: LGPL as per: http://www.gnu.org/copyleft/lesser.html 9 Note: This program is an almost direct port of the C library 10 Proj4. 11*/ 12/* ====================================================================== 13 proj4js.js 14 ====================================================================== */ 15 16/* 17Author: Mike Adair madairATdmsolutions.ca 18 Richard Greenwood rich@greenwoodmap.com 19License: LGPL as per: http://www.gnu.org/copyleft/lesser.html 20 21$Id: Proj.js 2956 2007-07-09 12:17:52Z steven $ 22*/ 23 24/** 25 * Namespace: Proj4js 26 * 27 * Proj4js is a JavaScript library to transform point coordinates from one 28 * coordinate system to another, including datum transformations. 29 * 30 * This library is a port of both the Proj.4 and GCTCP C libraries to JavaScript. 31 * Enabling these transformations in the browser allows geographic data stored 32 * in different projections to be combined in browser-based web mapping 33 * applications. 34 * 35 * Proj4js must have access to coordinate system initialization strings (which 36 * are the same as for PROJ.4 command line). Thes can be included in your 37 * application using a <script> tag or Proj4js can load CS initialization 38 * strings from a local directory or a web service such as spatialreference.org. 39 * 40 * Similarly, Proj4js must have access to projection transform code. These can 41 * be included individually using a <script> tag in your page, built into a 42 * custom build of Proj4js or loaded dynamically at run-time. Using the 43 * -combined and -compressed versions of Proj4js includes all projection class 44 * code by default. 45 * 46 * Note that dynamic loading of defs and code happens ascynchrously, check the 47 * Proj.readyToUse flag before using the Proj object. If the defs and code 48 * required by your application are loaded through script tags, dynamic loading 49 * is not required and the Proj object will be readyToUse on return from the 50 * constructor. 51 * 52 * All coordinates are handled as points which have a .x and a .y property 53 * which will be modified in place. 54 * 55 * Override Proj4js.reportError for output of alerts and warnings. 56 * 57 * See http://trac.osgeo.org/proj4js/wiki/UserGuide for full details. 58*/ 59 60/** 61 * Global namespace object for Proj4js library 62 */ 63Proj4js = { 64 65 /** 66 * Property: defaultDatum 67 * The datum to use when no others a specified 68 */ 69 defaultDatum: 'WGS84', //default datum 70 71 /** 72 * Method: transform(source, dest, point) 73 * Transform a point coordinate from one map projection to another. This is 74 * really the only public method you should need to use. 75 * 76 * Parameters: 77 * source - {Proj4js.Proj} source map projection for the transformation 78 * dest - {Proj4js.Proj} destination map projection for the transformation 79 * point - {Object} point to transform, may be geodetic (long, lat) or 80 * projected Cartesian (x,y), but should always have x,y properties. 81 */ 82 transform: function(source, dest, point) { 83 if (!source.readyToUse || !dest.readyToUse) { 84 this.reportError("Proj4js initialization for "+source.srsCode+" not yet complete"); 85 return point; 86 } 87 88 // Workaround for Spherical Mercator 89 if ((source.srsProjNumber =="900913" && dest.datumCode != "WGS84") || 90 (dest.srsProjNumber == "900913" && source.datumCode != "WGS84")) { 91 var wgs84 = Proj4js.WGS84; 92 this.transform(source, wgs84, point); 93 source = wgs84; 94 } 95 96 // Transform source points to long/lat, if they aren't already. 97 if ( source.projName=="longlat") { 98 point.x *= Proj4js.common.D2R; // convert degrees to radians 99 point.y *= Proj4js.common.D2R; 100 } else { 101 if (source.to_meter) { 102 point.x *= source.to_meter; 103 point.y *= source.to_meter; 104 } 105 source.inverse(point); // Convert Cartesian to longlat 106 } 107 108 // Adjust for the prime meridian if necessary 109 if (source.from_greenwich) { 110 point.x += source.from_greenwich; 111 } 112 113 // Convert datums if needed, and if possible. 114 point = this.datum_transform( source.datum, dest.datum, point ); 115 116 // Adjust for the prime meridian if necessary 117 if (dest.from_greenwich) { 118 point.x -= dest.from_greenwich; 119 } 120 121 if( dest.projName=="longlat" ) { 122 // convert radians to decimal degrees 123 point.x *= Proj4js.common.R2D; 124 point.y *= Proj4js.common.R2D; 125 } else { // else project 126 dest.forward(point); 127 if (dest.to_meter) { 128 point.x /= dest.to_meter; 129 point.y /= dest.to_meter; 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: reportError 218 * An internal method to report errors back to user. 219 * Override this in applications to report error messages or throw exceptions. 220 */ 221 reportError: function(msg) { 222 //console.log(msg); 223 }, 224 225/** 226 * 227 * Title: Private Methods 228 * The following properties and methods are intended for internal use only. 229 * 230 * This is a minimal implementation of JavaScript inheritance methods so that 231 * Proj4js can be used as a stand-alone library. 232 * These are copies of the equivalent OpenLayers methods at v2.7 233 */ 234 235/** 236 * Function: extend 237 * Copy all properties of a source object to a destination object. Modifies 238 * the passed in destination object. Any properties on the source object 239 * that are set to undefined will not be (re)set on the destination object. 240 * 241 * Parameters: 242 * destination - {Object} The object that will be modified 243 * source - {Object} The object with properties to be set on the destination 244 * 245 * Returns: 246 * {Object} The destination object. 247 */ 248 extend: function(destination, source) { 249 destination = destination || {}; 250 if(source) { 251 for(var property in source) { 252 var value = source[property]; 253 if(value !== undefined) { 254 destination[property] = value; 255 } 256 } 257 } 258 return destination; 259 }, 260 261/** 262 * Constructor: Class 263 * Base class used to construct all other classes. Includes support for 264 * multiple inheritance. 265 * 266 */ 267 Class: function() { 268 var Class = function() { 269 this.initialize.apply(this, arguments); 270 }; 271 272 var extended = {}; 273 var parent; 274 for(var i=0; i<arguments.length; ++i) { 275 if(typeof arguments[i] == "function") { 276 // get the prototype of the superclass 277 parent = arguments[i].prototype; 278 } else { 279 // in this case we're extending with the prototype 280 parent = arguments[i]; 281 } 282 Proj4js.extend(extended, parent); 283 } 284 Class.prototype = extended; 285 286 return Class; 287 }, 288 289 /** 290 * Function: bind 291 * Bind a function to an object. Method to easily create closures with 292 * 'this' altered. 293 * 294 * Parameters: 295 * func - {Function} Input function. 296 * object - {Object} The object to bind to the input function (as this). 297 * 298 * Returns: 299 * {Function} A closure with 'this' set to the passed in object. 300 */ 301 bind: function(func, object) { 302 // create a reference to all arguments past the second one 303 var args = Array.prototype.slice.apply(arguments, [2]); 304 return function() { 305 // Push on any additional arguments from the actual function call. 306 // These will come after those sent to the bind call. 307 var newArgs = args.concat( 308 Array.prototype.slice.apply(arguments, [0]) 309 ); 310 return func.apply(object, newArgs); 311 }; 312 }, 313 314/** 315 * The following properties and methods handle dynamic loading of JSON objects. 316 * 317 /** 318 * Property: scriptName 319 * {String} The filename of this script without any path. 320 */ 321 scriptName: "proj4js-combined.js", 322 323 /** 324 * Property: defsLookupService 325 * AJAX service to retreive projection definition parameters from 326 */ 327 defsLookupService: 'http://spatialreference.org/ref', 328 329 /** 330 * Property: libPath 331 * internal: http server path to library code. 332 */ 333 libPath: null, 334 335 /** 336 * Function: getScriptLocation 337 * Return the path to this script. 338 * 339 * Returns: 340 * Path to this script 341 */ 342 getScriptLocation: function () { 343 if (this.libPath) return this.libPath; 344 var scriptName = this.scriptName; 345 var scriptNameLen = scriptName.length; 346 347 var scripts = document.getElementsByTagName('script'); 348 for (var i = 0; i < scripts.length; i++) { 349 var src = scripts[i].getAttribute('src'); 350 if (src) { 351 var index = src.lastIndexOf(scriptName); 352 // is it found, at the end of the URL? 353 if ((index > -1) && (index + scriptNameLen == src.length)) { 354 this.libPath = src.slice(0, -scriptNameLen); 355 break; 356 } 357 } 358 } 359 return this.libPath||""; 360 }, 361 362 /** 363 * Function: loadScript 364 * Load a JS file from a URL into a <script> tag in the page. 365 * 366 * Parameters: 367 * url - {String} The URL containing the script to load 368 * onload - {Function} A method to be executed when the script loads successfully 369 * onfail - {Function} A method to be executed when there is an error loading the script 370 * loadCheck - {Function} A boolean method that checks to see if the script 371 * has loaded. Typically this just checks for the existance of 372 * an object in the file just loaded. 373 */ 374 loadScript: function(url, onload, onfail, loadCheck) { 375 var script = document.createElement('script'); 376 script.defer = false; 377 script.type = "text/javascript"; 378 script.id = url; 379 script.src = url; 380 script.onload = onload; 381 script.onerror = onfail; 382 script.loadCheck = loadCheck; 383 if (/MSIE/.test(navigator.userAgent)) { 384 script.onreadystatechange = this.checkReadyState; 385 } 386 document.getElementsByTagName('head')[0].appendChild(script); 387 }, 388 389 /** 390 * Function: checkReadyState 391 * IE workaround since there is no onerror handler. Calls the user defined 392 * loadCheck method to determine if the script is loaded. 393 * 394 */ 395 checkReadyState: function() { 396 if (this.readyState == 'loaded') { 397 if (!this.loadCheck()) { 398 this.onerror(); 399 } else { 400 this.onload(); 401 } 402 } 403 } 404}; 405 406/** 407 * Class: Proj4js.Proj 408 * 409 * Proj objects provide transformation methods for point coordinates 410 * between geodetic latitude/longitude and a projected coordinate system. 411 * once they have been initialized with a projection code. 412 * 413 * Initialization of Proj objects is with a projection code, usually EPSG codes, 414 * which is the key that will be used with the Proj4js.defs array. 415 * 416 * The code passed in will be stripped of colons and converted to uppercase 417 * to locate projection definition files. 418 * 419 * A projection object has properties for units and title strings. 420 */ 421Proj4js.Proj = Proj4js.Class({ 422 423 /** 424 * Property: readyToUse 425 * Flag to indicate if initialization is complete for this Proj object 426 */ 427 readyToUse: false, 428 429 /** 430 * Property: title 431 * The title to describe the projection 432 */ 433 title: null, 434 435 /** 436 * Property: projName 437 * The projection class for this projection, e.g. lcc (lambert conformal conic, 438 * or merc for mercator). These are exactly equivalent to their Proj4 439 * counterparts. 440 */ 441 projName: null, 442 /** 443 * Property: units 444 * The units of the projection. Values include 'm' and 'degrees' 445 */ 446 units: null, 447 /** 448 * Property: datum 449 * The datum specified for the projection 450 */ 451 datum: null, 452 /** 453 * Property: x0 454 * The x coordinate origin 455 */ 456 x0: 0, 457 /** 458 * Property: y0 459 * The y coordinate origin 460 */ 461 y0: 0, 462 463 /** 464 * Constructor: initialize 465 * Constructor for Proj4js.Proj objects 466 * 467 * Parameters: 468 * srsCode - a code for map projection definition parameters. These are usually 469 * (but not always) EPSG codes. 470 */ 471 initialize: function(srsCode) { 472 this.srsCodeInput = srsCode; 473 // DGR 2008-08-03 : support urn and url 474 if (srsCode.indexOf('urn:') == 0) { 475 //urn:ORIGINATOR:def:crs:CODESPACE:VERSION:ID 476 var urn = srsCode.split(':'); 477 if ((urn[1] == 'ogc' || urn[1] =='x-ogc') && 478 (urn[2] =='def') && 479 (urn[3] =='crs')) { 480 srsCode = urn[4]+':'+urn[urn.length-1]; 481 } 482 } else if (srsCode.indexOf('http://') == 0) { 483 //url#ID 484 var url = srsCode.split('#'); 485 if (url[0].match(/epsg.org/)) { 486 // http://www.epsg.org/# 487 srsCode = 'EPSG:'+url[1]; 488 } else if (url[0].match(/RIG.xml/)) { 489 //http://librairies.ign.fr/geoportail/resources/RIG.xml# 490 //http://interop.ign.fr/registers/ign/RIG.xml# 491 srsCode = 'IGNF:'+url[1]; 492 } 493 } 494 this.srsCode = srsCode.toUpperCase(); 495 if (this.srsCode.indexOf("EPSG") == 0) { 496 this.srsCode = this.srsCode; 497 this.srsAuth = 'epsg'; 498 this.srsProjNumber = this.srsCode.substring(5); 499 // DGR 2007-11-20 : authority IGNF 500 } else if (this.srsCode.indexOf("IGNF") == 0) { 501 this.srsCode = this.srsCode; 502 this.srsAuth = 'IGNF'; 503 this.srsProjNumber = this.srsCode.substring(5); 504 // DGR 2008-06-19 : pseudo-authority CRS for WMS 505 } else if (this.srsCode.indexOf("CRS") == 0) { 506 this.srsCode = this.srsCode; 507 this.srsAuth = 'CRS'; 508 this.srsProjNumber = this.srsCode.substring(4); 509 } else { 510 this.srsAuth = ''; 511 this.srsProjNumber = this.srsCode; 512 } 513 this.loadProjDefinition(); 514 }, 515 516/** 517 * Function: loadProjDefinition 518 * Loads the coordinate system initialization string if required. 519 * Note that dynamic loading happens asynchronously so an application must 520 * wait for the readyToUse property is set to true. 521 * To prevent dynamic loading, include the defs through a script tag in 522 * your application. 523 * 524 */ 525 loadProjDefinition: function() { 526 //check in memory 527 if (Proj4js.defs[this.srsCode]) { 528 this.defsLoaded(); 529 return; 530 } 531 532 //else check for def on the server 533 var url = Proj4js.getScriptLocation() + 'defs/' + this.srsAuth.toUpperCase() + this.srsProjNumber + '.js'; 534 Proj4js.loadScript(url, 535 Proj4js.bind(this.defsLoaded, this), 536 Proj4js.bind(this.loadFromService, this), 537 Proj4js.bind(this.checkDefsLoaded, this) ); 538 }, 539 540/** 541 * Function: loadFromService 542 * Creates the REST URL for loading the definition from a web service and 543 * loads it. 544 * 545 */ 546 loadFromService: function() { 547 //else load from web service 548 var url = Proj4js.defsLookupService +'/' + this.srsAuth +'/'+ this.srsProjNumber + '/proj4js/'; 549 Proj4js.loadScript(url, 550 Proj4js.bind(this.defsLoaded, this), 551 Proj4js.bind(this.defsFailed, this), 552 Proj4js.bind(this.checkDefsLoaded, this) ); 553 }, 554 555/** 556 * Function: defsLoaded 557 * Continues the Proj object initilization once the def file is loaded 558 * 559 */ 560 defsLoaded: function() { 561 this.parseDefs(); 562 this.loadProjCode(this.projName); 563 }, 564 565/** 566 * Function: checkDefsLoaded 567 * This is the loadCheck method to see if the def object exists 568 * 569 */ 570 checkDefsLoaded: function() { 571 if (Proj4js.defs[this.srsCode]) { 572 return true; 573 } else { 574 return false; 575 } 576 }, 577 578 /** 579 * Function: defsFailed 580 * Report an error in loading the defs file, but continue on using WGS84 581 * 582 */ 583 defsFailed: function() { 584 Proj4js.reportError('failed to load projection definition for: '+this.srsCode); 585 Proj4js.defs[this.srsCode] = Proj4js.defs['WGS84']; //set it to something so it can at least continue 586 this.defsLoaded(); 587 }, 588 589/** 590 * Function: loadProjCode 591 * Loads projection class code dynamically if required. 592 * Projection code may be included either through a script tag or in 593 * a built version of proj4js 594 * 595 */ 596 loadProjCode: function(projName) { 597 if (Proj4js.Proj[projName]) { 598 this.initTransforms(); 599 return; 600 } 601 602 //the URL for the projection code 603 var url = Proj4js.getScriptLocation() + 'projCode/' + projName + '.js'; 604 Proj4js.loadScript(url, 605 Proj4js.bind(this.loadProjCodeSuccess, this, projName), 606 Proj4js.bind(this.loadProjCodeFailure, this, projName), 607 Proj4js.bind(this.checkCodeLoaded, this, projName) ); 608 }, 609 610 /** 611 * Function: loadProjCodeSuccess 612 * Loads any proj dependencies or continue on to final initialization. 613 * 614 */ 615 loadProjCodeSuccess: function(projName) { 616 if (Proj4js.Proj[projName].dependsOn){ 617 this.loadProjCode(Proj4js.Proj[projName].dependsOn); 618 } else { 619 this.initTransforms(); 620 } 621 }, 622 623 /** 624 * Function: defsFailed 625 * Report an error in loading the proj file. Initialization of the Proj 626 * object has failed and the readyToUse flag will never be set. 627 * 628 */ 629 loadProjCodeFailure: function(projName) { 630 Proj4js.reportError("failed to find projection file for: " + projName); 631 //TBD initialize with identity transforms so proj will still work? 632 }, 633 634/** 635 * Function: checkCodeLoaded 636 * This is the loadCheck method to see if the projection code is loaded 637 * 638 */ 639 checkCodeLoaded: function(projName) { 640 if (Proj4js.Proj[projName]) { 641 return true; 642 } else { 643 return false; 644 } 645 }, 646 647/** 648 * Function: initTransforms 649 * Finalize the initialization of the Proj object 650 * 651 */ 652 initTransforms: function() { 653 Proj4js.extend(this, Proj4js.Proj[this.projName]); 654 this.init(); 655 this.readyToUse = true; 656 }, 657 658/** 659 * Function: parseDefs 660 * Parses the PROJ.4 initialization string and sets the associated properties. 661 * 662 */ 663 parseDefs: function() { 664 this.defData = Proj4js.defs[this.srsCode]; 665 var paramName, paramVal; 666 if (!this.defData) { 667 return; 668 } 669 var paramArray=this.defData.split("+"); 670 671 for (var prop=0; prop<paramArray.length; prop++) { 672 var property = paramArray[prop].split("="); 673 paramName = property[0].toLowerCase(); 674 paramVal = property[1]; 675 676 switch (paramName.replace(/\s/gi,"")) { // trim out spaces 677 case "": break; // throw away nameless parameter 678 case "title": this.title = paramVal; break; 679 case "proj": this.projName = paramVal.replace(/\s/gi,""); break; 680 case "units": this.units = paramVal.replace(/\s/gi,""); break; 681 case "datum": this.datumCode = paramVal.replace(/\s/gi,""); break; 682 case "nadgrids": this.nagrids = paramVal.replace(/\s/gi,""); break; 683 case "ellps": this.ellps = paramVal.replace(/\s/gi,""); break; 684 case "a": this.a = parseFloat(paramVal); break; // semi-major radius 685 case "b": this.b = parseFloat(paramVal); break; // semi-minor radius 686 // DGR 2007-11-20 687 case "rf": this.rf = parseFloat(paramVal); break; // inverse flattening rf= a/(a-b) 688 case "lat_0": this.lat0 = paramVal*Proj4js.common.D2R; break; // phi0, central latitude 689 case "lat_1": this.lat1 = paramVal*Proj4js.common.D2R; break; //standard parallel 1 690 case "lat_2": this.lat2 = paramVal*Proj4js.common.D2R; break; //standard parallel 2 691 case "lat_ts": this.lat_ts = paramVal*Proj4js.common.D2R; break; // used in merc and eqc 692 case "lon_0": this.long0 = paramVal*Proj4js.common.D2R; break; // lam0, central longitude 693 case "alpha": this.alpha = parseFloat(paramVal)*Proj4js.common.D2R; break; //for somerc projection 694 case "lonc": this.longc = paramVal*Proj4js.common.D2R; break; //for somerc projection 695 case "x_0": this.x0 = parseFloat(paramVal); break; // false easting 696 case "y_0": this.y0 = parseFloat(paramVal); break; // false northing 697 case "k_0": this.k0 = parseFloat(paramVal); break; // projection scale factor 698 case "k": this.k0 = parseFloat(paramVal); break; // both forms returned 699 case "r_a": this.R_A = true; break; // sphere--area of ellipsoid 700 case "zone": this.zone = parseInt(paramVal); break; // UTM Zone 701 case "south": this.utmSouth = true; break; // UTM north/south 702 case "towgs84":this.datum_params = paramVal.split(","); break; 703 case "to_meter": this.to_meter = parseFloat(paramVal); break; // cartesian scaling 704 case "from_greenwich": this.from_greenwich = paramVal*Proj4js.common.D2R; break; 705 // DGR 2008-07-09 : if pm is not a well-known prime meridian take 706 // the value instead of 0.0, then convert to radians 707 case "pm": paramVal = paramVal.replace(/\s/gi,""); 708 this.from_greenwich = Proj4js.PrimeMeridian[paramVal] ? 709 Proj4js.PrimeMeridian[paramVal] : parseFloat(paramVal); 710 this.from_greenwich *= Proj4js.common.D2R; 711 break; 712 case "no_defs": break; 713 default: //alert("Unrecognized parameter: " + paramName); 714 } // switch() 715 } // for paramArray 716 this.deriveConstants(); 717 }, 718 719/** 720 * Function: deriveConstants 721 * Sets several derived constant values and initialization of datum and ellipse 722 * parameters. 723 * 724 */ 725 deriveConstants: function() { 726 if (this.nagrids == '@null') this.datumCode = 'none'; 727 if (this.datumCode && this.datumCode != 'none') { 728 var datumDef = Proj4js.Datum[this.datumCode]; 729 if (datumDef) { 730 this.datum_params = datumDef.towgs84 ? datumDef.towgs84.split(',') : null; 731 this.ellps = datumDef.ellipse; 732 this.datumName = datumDef.datumName ? datumDef.datumName : this.datumCode; 733 } 734 } 735 if (!this.a) { // do we have an ellipsoid? 736 var ellipse = Proj4js.Ellipsoid[this.ellps] ? Proj4js.Ellipsoid[this.ellps] : Proj4js.Ellipsoid['WGS84']; 737 Proj4js.extend(this, ellipse); 738 } 739 if (this.rf && !this.b) this.b = (1.0 - 1.0/this.rf) * this.a; 740 if (Math.abs(this.a - this.b)<Proj4js.common.EPSLN) { 741 this.sphere = true; 742 this.b= this.a; 743 } 744 this.a2 = this.a * this.a; // used in geocentric 745 this.b2 = this.b * this.b; // used in geocentric 746 this.es = (this.a2-this.b2)/this.a2; // e ^ 2 747 this.e = Math.sqrt(this.es); // eccentricity 748 if (this.R_A) { 749 this.a *= 1. - this.es * (Proj4js.common.SIXTH + this.es * (Proj4js.common.RA4 + this.es * Proj4js.common.RA6)); 750 this.a2 = this.a * this.a; 751 this.b2 = this.b * this.b; 752 this.es = 0.; 753 } 754 this.ep2=(this.a2-this.b2)/this.b2; // used in geocentric 755 if (!this.k0) this.k0 = 1.0; //default value 756 757 this.datum = new Proj4js.datum(this); 758 } 759}); 760 761Proj4js.Proj.longlat = { 762 init: function() { 763 //no-op for longlat 764 }, 765 forward: function(pt) { 766 //identity transform 767 return pt; 768 }, 769 inverse: function(pt) { 770 //identity transform 771 return pt; 772 } 773}; 774 775/** 776 Proj4js.defs is a collection of coordinate system definition objects in the 777 PROJ.4 command line format. 778 Generally a def is added by means of a separate .js file for example: 779 780 <SCRIPT type="text/javascript" src="defs/EPSG26912.js"></SCRIPT> 781 782 def is a CS definition in PROJ.4 WKT format, for example: 783 +proj="tmerc" //longlat, etc. 784 +a=majorRadius 785 +b=minorRadius 786 +lat0=somenumber 787 +long=somenumber 788*/ 789Proj4js.defs = { 790 // These are so widely used, we'll go ahead and throw them in 791 // without requiring a separate .js file 792 'WGS84': "+title=long/lat:WGS84 +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees", 793 'EPSG:4326': "+title=long/lat:WGS84 +proj=longlat +a=6378137.0 +b=6356752.31424518 +ellps=WGS84 +datum=WGS84 +units=degrees", 794 'EPSG:4269': "+title=long/lat:NAD83 +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees", 795 '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" 796}; 797Proj4js.defs['GOOGLE'] = Proj4js.defs['EPSG:3785']; 798Proj4js.defs['EPSG:900913'] = Proj4js.defs['EPSG:3785']; 799Proj4js.defs['EPSG:102113'] = Proj4js.defs['EPSG:3785']; 800 801Proj4js.common = { 802 PI : 3.141592653589793238, //Math.PI, 803 HALF_PI : 1.570796326794896619, //Math.PI*0.5, 804 TWO_PI : 6.283185307179586477, //Math.PI*2, 805 FORTPI : 0.78539816339744833, 806 R2D : 57.29577951308232088, 807 D2R : 0.01745329251994329577, 808 SEC_TO_RAD : 4.84813681109535993589914102357e-6, /* SEC_TO_RAD = Pi/180/3600 */ 809 EPSLN : 1.0e-10, 810 MAX_ITER : 20, 811 // following constants from geocent.c 812 COS_67P5 : 0.38268343236508977, /* cosine of 67.5 degrees */ 813 AD_C : 1.0026000, /* Toms region 1 constant */ 814 815 /* datum_type values */ 816 PJD_UNKNOWN : 0, 817 PJD_3PARAM : 1, 818 PJD_7PARAM : 2, 819 PJD_GRIDSHIFT: 3, 820 PJD_WGS84 : 4, // WGS84 or equivalent 821 PJD_NODATUM : 5, // WGS84 or equivalent 822 SRS_WGS84_SEMIMAJOR : 6378137.0, // only used in grid shift transforms 823 824 // ellipoid pj_set_ell.c 825 SIXTH : .1666666666666666667, /* 1/6 */ 826 RA4 : .04722222222222222222, /* 17/360 */ 827 RA6 : .02215608465608465608, /* 67/3024 */ 828 RV4 : .06944444444444444444, /* 5/72 */ 829 RV6 : .04243827160493827160, /* 55/1296 */ 830 831// Function to compute the constant small m which is the radius of 832// a parallel of latitude, phi, divided by the semimajor axis. 833// ----------------------------------------------------------------- 834 msfnz : function(eccent, sinphi, cosphi) { 835 var con = eccent * sinphi; 836 return cosphi/(Math.sqrt(1.0 - con * con)); 837 }, 838 839// Function to compute the constant small t for use in the forward 840// computations in the Lambert Conformal Conic and the Polar 841// Stereographic projections. 842// ----------------------------------------------------------------- 843 tsfnz : function(eccent, phi, sinphi) { 844 var con = eccent * sinphi; 845 var com = .5 * eccent; 846 con = Math.pow(((1.0 - con) / (1.0 + con)), com); 847 return (Math.tan(.5 * (this.HALF_PI - phi))/con); 848 }, 849 850// Function to compute the latitude angle, phi2, for the inverse of the 851// Lambert Conformal Conic and Polar Stereographic projections. 852// ---------------------------------------------------------------- 853 phi2z : function(eccent, ts) { 854 var eccnth = .5 * eccent; 855 var con, dphi; 856 var phi = this.HALF_PI - 2 * Math.atan(ts); 857 for (i = 0; i <= 15; i++) { 858 con = eccent * Math.sin(phi); 859 dphi = this.HALF_PI - 2 * Math.atan(ts *(Math.pow(((1.0 - con)/(1.0 + con)),eccnth))) - phi; 860 phi += dphi; 861 if (Math.abs(dphi) <= .0000000001) return phi; 862 } 863 alert("phi2z has NoConvergence"); 864 return (-9999); 865 }, 866 867/* Function to compute constant small q which is the radius of a 868 parallel of latitude, phi, divided by the semimajor axis. 869------------------------------------------------------------*/ 870 qsfnz : function(eccent,sinphi) { 871 var con; 872 if (eccent > 1.0e-7) { 873 con = eccent * sinphi; 874 return (( 1.0- eccent * eccent) * (sinphi /(1.0 - con * con) - (.5/eccent)*Math.log((1.0 - con)/(1.0 + con)))); 875 } else { 876 return(2.0 * sinphi); 877 } 878 }, 879 880/* Function to eliminate roundoff errors in asin 881----------------------------------------------*/ 882 asinz : function(x) { 883 if (Math.abs(x)>1.0) { 884 x=(x>1.0)?1.0:-1.0; 885 } 886 return Math.asin(x); 887 }, 888 889// following functions from gctpc cproj.c for transverse mercator projections 890 e0fn : function(x) {return(1.0-0.25*x*(1.0+x/16.0*(3.0+1.25*x)));}, 891 e1fn : function(x) {return(0.375*x*(1.0+0.25*x*(1.0+0.46875*x)));}, 892 e2fn : function(x) {return(0.05859375*x*x*(1.0+0.75*x));}, 893 e3fn : function(x) {return(x*x*x*(35.0/3072.0));}, 894 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));}, 895 896 srat : function(esinp, exp) { 897 return(Math.pow((1.0-esinp)/(1.0+esinp), exp)); 898 }, 899 900// Function to return the sign of an argument 901 sign : function(x) { if (x < 0.0) return(-1); else return(1);}, 902 903// Function to adjust longitude to -180 to 180; input in radians 904 adjust_lon : function(x) { 905 x = (Math.abs(x) < this.PI) ? x: (x - (this.sign(x)*this.TWO_PI) ); 906 return x; 907 }, 908 909// IGNF - DGR : algorithms used by IGN France 910 911// Function to adjust latitude to -90 to 90; input in radians 912 adjust_lat : function(x) { 913 x= (Math.abs(x) < this.HALF_PI) ? x: (x - (this.sign(x)*this.PI) ); 914 return x; 915 }, 916 917// Latitude Isometrique - close to tsfnz ... 918 latiso : function(eccent, phi, sinphi) { 919 if (Math.abs(phi) > this.HALF_PI) return +Number.NaN; 920 if (phi==this.HALF_PI) return Number.POSITIVE_INFINITY; 921 if (phi==-1.0*this.HALF_PI) return -1.0*Number.POSITIVE_INFINITY; 922 923 var con= eccent*sinphi; 924 return Math.log(Math.tan((this.HALF_PI+phi)/2.0))+eccent*Math.log((1.0-con)/(1.0+con))/2.0; 925 }, 926 927 fL : function(x,L) { 928 return 2.0*Math.atan(x*Math.exp(L)) - this.HALF_PI; 929 }, 930 931// Inverse Latitude Isometrique - close to ph2z 932 invlatiso : function(eccent, ts) { 933 var phi= this.fL(1.0,ts); 934 var Iphi= 0.0; 935 var con= 0.0; 936 do { 937 Iphi= phi; 938 con= eccent*Math.sin(Iphi); 939 phi= this.fL(Math.exp(eccent*Math.log((1.0+con)/(1.0-con))/2.0),ts) 940 } while (Math.abs(phi-Iphi)>1.0e-12); 941 return phi; 942 }, 943 944// Needed for Gauss Schreiber 945// Original: Denis Makarov (info@binarythings.com) 946// Web Site: http://www.binarythings.com 947 sinh : function(x) 948 { 949 var r= Math.exp(x); 950 r= (r-1.0/r)/2.0; 951 return r; 952 }, 953 954 cosh : function(x) 955 { 956 var r= Math.exp(x); 957 r= (r+1.0/r)/2.0; 958 return r; 959 }, 960 961 tanh : function(x) 962 { 963 var r= Math.exp(x); 964 r= (r-1.0/r)/(r+1.0/r); 965 return r; 966 }, 967 968 asinh : function(x) 969 { 970 var s= (x>= 0? 1.0:-1.0); 971 return s*(Math.log( Math.abs(x) + Math.sqrt(x*x+1.0) )); 972 }, 973 974 acosh : function(x) 975 { 976 return 2.0*Math.log(Math.sqrt((x+1.0)/2.0) + Math.sqrt((x-1.0)/2.0)); 977 }, 978 979 atanh : function(x) 980 { 981 return Math.log((x-1.0)/(x+1.0))/2.0; 982 }, 983 984// Grande Normale 985 gN : function(a,e,sinphi) 986 { 987 var temp= e*sinphi; 988 return a/Math.sqrt(1.0 - temp*temp); 989 } 990 991}; 992 993/** datum object 994*/ 995Proj4js.datum = Proj4js.Class({ 996 997 initialize : function(proj) { 998 this.datum_type = Proj4js.common.PJD_WGS84; //default setting 999 if (proj.datumCode && proj.datumCode == 'none') { 1000 this.datum_type = Proj4js.common.PJD_NODATUM; 1001 } 1002 if (proj && proj.datum_params) { 1003 for (var i=0; i<proj.datum_params.length; i++) { 1004 proj.datum_params[i]=parseFloat(proj.datum_params[i]); 1005 } 1006 if (proj.datum_params[0] != 0 || proj.datum_params[1] != 0 || proj.datum_params[2] != 0 ) { 1007 this.datum_type = Proj4js.common.PJD_3PARAM; 1008 } 1009 if (proj.datum_params.length > 3) { 1010 if (proj.datum_params[3] != 0 || proj.datum_params[4] != 0 || 1011 proj.datum_params[5] != 0 || proj.datum_params[6] != 0 ) { 1012 this.datum_type = Proj4js.common.PJD_7PARAM; 1013 proj.datum_params[3] *= Proj4js.common.SEC_TO_RAD; 1014 proj.datum_params[4] *= Proj4js.common.SEC_TO_RAD; 1015 proj.datum_params[5] *= Proj4js.common.SEC_TO_RAD; 1016 proj.datum_params[6] = (proj.datum_params[6]/1000000.0) + 1.0; 1017 } 1018 } 1019 } 1020 if (proj) { 1021 this.a = proj.a; //datum object also uses these values 1022 this.b = proj.b; 1023 this.es = proj.es; 1024 this.ep2 = proj.ep2; 1025 this.datum_params = proj.datum_params; 1026 } 1027 }, 1028 1029 /****************************************************************/ 1030 // cs_compare_datums() 1031 // Returns 1 (TRUE) if the two datums match, otherwise 0 (FALSE). 1032 compare_datums : function( dest ) { 1033 if( this.datum_type != dest.datum_type ) { 1034 return false; // false, datums are not equal 1035 } else if( this.a != dest.a || Math.abs(this.es-dest.es) > 0.000000000050 ) { 1036 // the tolerence for es is to ensure that GRS80 and WGS84 1037 // are considered identical 1038 return false; 1039 } else if( this.datum_type == Proj4js.common.PJD_3PARAM ) { 1040 return (this.datum_params[0] == dest.datum_params[0] 1041 && this.datum_params[1] == dest.datum_params[1] 1042 && this.datum_params[2] == dest.datum_params[2]); 1043 } else if( this.datum_type == Proj4js.common.PJD_7PARAM ) { 1044 return (this.datum_params[0] == dest.datum_params[0] 1045 && this.datum_params[1] == dest.datum_params[1] 1046 && this.datum_params[2] == dest.datum_params[2] 1047 && this.datum_params[3] == dest.datum_params[3] 1048 && this.datum_params[4] == dest.datum_params[4] 1049 && this.datum_params[5] == dest.datum_params[5] 1050 && this.datum_params[6] == dest.datum_params[6]); 1051 } else if( this.datum_type == Proj4js.common.PJD_GRIDSHIFT ) { 1052 return strcmp( pj_param(this.params,"snadgrids").s, 1053 pj_param(dest.params,"snadgrids").s ) == 0; 1054 } else { 1055 return true; // datums are equal 1056 } 1057 }, // cs_compare_datums() 1058 1059 /* 1060 * The function Convert_Geodetic_To_Geocentric converts geodetic coordinates 1061 * (latitude, longitude, and height) to geocentric coordinates (X, Y, Z), 1062 * according to the current ellipsoid parameters. 1063 * 1064 * Latitude : Geodetic latitude in radians (input) 1065 * Longitude : Geodetic longitude in radians (input) 1066 * Height : Geodetic height, in meters (input) 1067 * X : Calculated Geocentric X coordinate, in meters (output) 1068 * Y : Calculated Geocentric Y coordinate, in meters (output) 1069 * Z : Calculated Geocentric Z coordinate, in meters (output) 1070 * 1071 */ 1072 geodetic_to_geocentric : function(p) { 1073 var Longitude = p.x; 1074 var Latitude = p.y; 1075 var Height = p.z ? p.z : 0; //Z value not always supplied 1076 var X; // output 1077 var Y; 1078 var Z; 1079 1080 var Error_Code=0; // GEOCENT_NO_ERROR; 1081 var Rn; /* Earth radius at location */ 1082 var Sin_Lat; /* Math.sin(Latitude) */ 1083 var Sin2_Lat; /* Square of Math.sin(Latitude) */ 1084 var Cos_Lat; /* Math.cos(Latitude) */ 1085 1086 /* 1087 ** Don't blow up if Latitude is just a little out of the value 1088 ** range as it may just be a rounding issue. Also removed longitude 1089 ** test, it should be wrapped by Math.cos() and Math.sin(). NFW for PROJ.4, Sep/2001. 1090 */ 1091 if( Latitude < -Proj4js.common.HALF_PI && Latitude > -1.001 * Proj4js.common.HALF_PI ) { 1092 Latitude = -Proj4js.common.HALF_PI; 1093 } else if( Latitude > Proj4js.common.HALF_PI && Latitude < 1.001 * Proj4js.common.HALF_PI ) { 1094 Latitude = Proj4js.common.HALF_PI; 1095 } else if ((Latitude < -Proj4js.common.HALF_PI) || (Latitude > Proj4js.common.HALF_PI)) { 1096 /* Latitude out of range */ 1097 Proj4js.reportError('geocent:lat out of range:'+Latitude); 1098 return null; 1099 } 1100 1101 if (Longitude > Proj4js.common.PI) Longitude -= (2*Proj4js.common.PI); 1102 Sin_Lat = Math.sin(Latitude); 1103 Cos_Lat = Math.cos(Latitude); 1104 Sin2_Lat = Sin_Lat * Sin_Lat; 1105 Rn = this.a / (Math.sqrt(1.0e0 - this.es * Sin2_Lat)); 1106 X = (Rn + Height) * Cos_Lat * Math.cos(Longitude); 1107 Y = (Rn + Height) * Cos_Lat * Math.sin(Longitude); 1108 Z = ((Rn * (1 - this.es)) + Height) * Sin_Lat; 1109 1110 p.x = X; 1111 p.y = Y; 1112 p.z = Z; 1113 return Error_Code; 1114 }, // cs_geodetic_to_geocentric() 1115 1116 1117 geocentric_to_geodetic : function (p) { 1118/* local defintions and variables */ 1119/* end-criterium of loop, accuracy of sin(Latitude) */ 1120var genau = 1.E-12; 1121var genau2 = (genau*genau); 1122var maxiter = 30; 1123 1124 var P; /* distance between semi-minor axis and location */ 1125 var RR; /* distance between center and location */ 1126 var CT; /* sin of geocentric latitude */ 1127 var ST; /* cos of geocentric latitude */ 1128 var RX; 1129 var RK; 1130 var RN; /* Earth radius at location */ 1131 var CPHI0; /* cos of start or old geodetic latitude in iterations */ 1132 var SPHI0; /* sin of start or old geodetic latitude in iterations */ 1133 var CPHI; /* cos of searched geodetic latitude */ 1134 var SPHI; /* sin of searched geodetic latitude */ 1135 var SDPHI; /* end-criterium: addition-theorem of sin(Latitude(iter)-Latitude(iter-1)) */ 1136 var At_Pole; /* indicates location is in polar region */ 1137 var iter; /* # of continous iteration, max. 30 is always enough (s.a.) */ 1138 1139 var X = p.x; 1140 var Y = p.y; 1141 var Z = p.z ? p.z : 0.0; //Z value not always supplied 1142 var Longitude; 1143 var Latitude; 1144 var Height; 1145 1146 At_Pole = false; 1147 P = Math.sqrt(X*X+Y*Y); 1148 RR = Math.sqrt(X*X+Y*Y+Z*Z); 1149 1150/* special cases for latitude and longitude */ 1151 if (P/this.a < genau) { 1152 1153/* special case, if P=0. (X=0., Y=0.) */ 1154 At_Pole = true; 1155 Longitude = 0.0; 1156 1157/* if (X,Y,Z)=(0.,0.,0.) then Height becomes semi-minor axis 1158 * of ellipsoid (=center of mass), Latitude becomes PI/2 */ 1159 if (RR/this.a < genau) { 1160 Latitude = Proj4js.common.HALF_PI; 1161 Height = -this.b; 1162 return; 1163 } 1164 } else { 1165/* ellipsoidal (geodetic) longitude 1166 * interval: -PI < Longitude <= +PI */ 1167 Longitude=Math.atan2(Y,X); 1168 } 1169 1170/* -------------------------------------------------------------- 1171 * Following iterative algorithm was developped by 1172 * "Institut für Erdmessung", University of Hannover, July 1988. 1173 * Internet: www.ife.uni-hannover.de 1174 * Iterative computation of CPHI,SPHI and Height. 1175 * Iteration of CPHI and SPHI to 10**-12 radian resp. 1176 * 2*10**-7 arcsec. 1177 * -------------------------------------------------------------- 1178 */ 1179 CT = Z/RR; 1180 ST = P/RR; 1181 RX = 1.0/Math.sqrt(1.0-this.es*(2.0-this.es)*ST*ST); 1182 CPHI0 = ST*(1.0-this.es)*RX; 1183 SPHI0 = CT*RX; 1184 iter = 0; 1185 1186/* loop to find sin(Latitude) resp. Latitude 1187 * until |sin(Latitude(iter)-Latitude(iter-1))| < genau */ 1188 do 1189 { 1190 iter++; 1191 RN = this.a/Math.sqrt(1.0-this.es*SPHI0*SPHI0); 1192 1193/* ellipsoidal (geodetic) height */ 1194 Height = P*CPHI0+Z*SPHI0-RN*(1.0-this.es*SPHI0*SPHI0); 1195 1196 RK = this.es*RN/(RN+Height); 1197 RX = 1.0/Math.sqrt(1.0-RK*(2.0-RK)*ST*ST); 1198 CPHI = ST*(1.0-RK)*RX; 1199 SPHI = CT*RX; 1200 SDPHI = SPHI*CPHI0-CPHI*SPHI0; 1201 CPHI0 = CPHI; 1202 SPHI0 = SPHI; 1203 } 1204 while (SDPHI*SDPHI > genau2 && iter < maxiter); 1205 1206/* ellipsoidal (geodetic) latitude */ 1207 Latitude=Math.atan(SPHI/Math.abs(CPHI)); 1208 1209 p.x = Longitude; 1210 p.y = Latitude; 1211 p.z = Height; 1212 return p; 1213 }, // cs_geocentric_to_geodetic() 1214 1215 /** Convert_Geocentric_To_Geodetic 1216 * The method used here is derived from 'An Improved Algorithm for 1217 * Geocentric to Geodetic Coordinate Conversion', by Ralph Toms, Feb 1996 1218 */ 1219 geocentric_to_geodetic_noniter : function (p) { 1220 var X = p.x; 1221 var Y = p.y; 1222 var Z = p.z ? p.z : 0; //Z value not always supplied 1223 var Longitude; 1224 var Latitude; 1225 var Height; 1226 1227 var W; /* distance from Z axis */ 1228 var W2; /* square of distance from Z axis */ 1229 var T0; /* initial estimate of vertical component */ 1230 var T1; /* corrected estimate of vertical component */ 1231 var S0; /* initial estimate of horizontal component */ 1232 var S1; /* corrected estimate of horizontal component */ 1233 var Sin_B0; /* Math.sin(B0), B0 is estimate of Bowring aux variable */ 1234 var Sin3_B0; /* cube of Math.sin(B0) */ 1235 var Cos_B0; /* Math.cos(B0) */ 1236 var Sin_p1; /* Math.sin(phi1), phi1 is estimated latitude */ 1237 var Cos_p1; /* Math.cos(phi1) */ 1238 var Rn; /* Earth radius at location */ 1239 var Sum; /* numerator of Math.cos(phi1) */ 1240 var At_Pole; /* indicates location is in polar region */ 1241 1242 X = parseFloat(X); // cast from string to float 1243 Y = parseFloat(Y); 1244 Z = parseFloat(Z); 1245 1246 At_Pole = false; 1247 if (X != 0.0) 1248 { 1249 Longitude = Math.atan2(Y,X); 1250 } 1251 else 1252 { 1253 if (Y > 0) 1254 { 1255 Longitude = Proj4js.common.HALF_PI; 1256 } 1257 else if (Y < 0) 1258 { 1259 Longitude = -Proj4js.common.HALF_PI; 1260 } 1261 else 1262 { 1263 At_Pole = true; 1264 Longitude = 0.0; 1265 if (Z > 0.0) 1266 { /* north pole */ 1267 Latitude = Proj4js.common.HALF_PI; 1268 } 1269 else if (Z < 0.0) 1270 { /* south pole */ 1271 Latitude = -Proj4js.common.HALF_PI; 1272 } 1273 else 1274 { /* center of earth */ 1275 Latitude = Proj4js.common.HALF_PI; 1276 Height = -this.b; 1277 return; 1278 } 1279 } 1280 } 1281 W2 = X*X + Y*Y; 1282 W = Math.sqrt(W2); 1283 T0 = Z * Proj4js.common.AD_C; 1284 S0 = Math.sqrt(T0 * T0 + W2); 1285 Sin_B0 = T0 / S0; 1286 Cos_B0 = W / S0; 1287 Sin3_B0 = Sin_B0 * Sin_B0 * Sin_B0; 1288 T1 = Z + this.b * this.ep2 * Sin3_B0; 1289 Sum = W - this.a * this.es * Cos_B0 * Cos_B0 * Cos_B0; 1290 S1 = Math.sqrt(T1*T1 + Sum * Sum); 1291 Sin_p1 = T1 / S1; 1292 Cos_p1 = Sum / S1; 1293 Rn = this.a / Math.sqrt(1.0 - this.es * Sin_p1 * Sin_p1); 1294 if (Cos_p1 >= Proj4js.common.COS_67P5) 1295 { 1296 Height = W / Cos_p1 - Rn; 1297 } 1298 else if (Cos_p1 <= -Proj4js.common.COS_67P5) 1299 { 1300 Height = W / -Cos_p1 - Rn; 1301 } 1302 else 1303 { 1304 Height = Z / Sin_p1 + Rn * (this.es - 1.0); 1305 } 1306 if (At_Pole == false) 1307 { 1308 Latitude = Math.atan(Sin_p1 / Cos_p1); 1309 } 1310 1311 p.x = Longitude; 1312 p.y = Latitude; 1313 p.z = Height; 1314 return p; 1315 }, // geocentric_to_geodetic_noniter() 1316 1317 /****************************************************************/ 1318 // pj_geocentic_to_wgs84( p ) 1319 // p = point to transform in geocentric coordinates (x,y,z) 1320 geocentric_to_wgs84 : function ( p ) { 1321 1322 if( this.datum_type == Proj4js.common.PJD_3PARAM ) 1323 { 1324 // if( x[io] == HUGE_VAL ) 1325 // continue; 1326 p.x += this.datum_params[0]; 1327 p.y += this.datum_params[1]; 1328 p.z += this.datum_params[2]; 1329 1330 } 1331 else if (this.datum_type == Proj4js.common.PJD_7PARAM) 1332 { 1333 var Dx_BF =this.datum_params[0]; 1334 var Dy_BF =this.datum_params[1]; 1335 var Dz_BF =this.datum_params[2]; 1336 var Rx_BF =this.datum_params[3]; 1337 var Ry_BF =this.datum_params[4]; 1338 var Rz_BF =this.datum_params[5]; 1339 var M_BF =this.datum_params[6]; 1340 // if( x[io] == HUGE_VAL ) 1341 // continue; 1342 var x_out = M_BF*( p.x - Rz_BF*p.y + Ry_BF*p.z) + Dx_BF; 1343 var y_out = M_BF*( Rz_BF*p.x + p.y - Rx_BF*p.z) + Dy_BF; 1344 var z_out = M_BF*(-Ry_BF*p.x + Rx_BF*p.y + p.z) + Dz_BF; 1345 p.x = x_out; 1346 p.y = y_out; 1347 p.z = z_out; 1348 } 1349 }, // cs_geocentric_to_wgs84 1350 1351 /****************************************************************/ 1352 // pj_geocentic_from_wgs84() 1353 // coordinate system definition, 1354 // point to transform in geocentric coordinates (x,y,z) 1355 geocentric_from_wgs84 : function( p ) { 1356 1357 if( this.datum_type == Proj4js.common.PJD_3PARAM ) 1358 { 1359 //if( x[io] == HUGE_VAL ) 1360 // continue; 1361 p.x -= this.datum_params[0]; 1362 p.y -= this.datum_params[1]; 1363 p.z -= this.datum_params[2]; 1364 1365 } 1366 else if (this.datum_type == Proj4js.common.PJD_7PARAM) 1367 { 1368 var Dx_BF =this.datum_params[0]; 1369 var Dy_BF =this.datum_params[1]; 1370 var Dz_BF =this.datum_params[2]; 1371 var Rx_BF =this.datum_params[3]; 1372 var Ry_BF =this.datum_params[4]; 1373 var Rz_BF =this.datum_params[5]; 1374 var M_BF =this.datum_params[6]; 1375 var x_tmp = (p.x - Dx_BF) / M_BF; 1376 var y_tmp = (p.y - Dy_BF) / M_BF; 1377 var z_tmp = (p.z - Dz_BF) / M_BF; 1378 //if( x[io] == HUGE_VAL ) 1379 // continue; 1380 1381 p.x = x_tmp + Rz_BF*y_tmp - Ry_BF*z_tmp; 1382 p.y = -Rz_BF*x_tmp + y_tmp + Rx_BF*z_tmp; 1383 p.z = Ry_BF*x_tmp - Rx_BF*y_tmp + z_tmp; 1384 } //cs_geocentric_from_wgs84() 1385 } 1386}); 1387 1388/** point object, nothing fancy, just allows values to be 1389 passed back and forth by reference rather than by value. 1390 Other point classes may be used as long as they have 1391 x and y properties, which will get modified in the transform method. 1392*/ 1393Proj4js.Point = Proj4js.Class({ 1394 1395 /** 1396 * Constructor: Proj4js.Point 1397 * 1398 * Parameters: 1399 * - x {float} or {Array} either the first coordinates component or 1400 * the full coordinates 1401 * - y {float} the second component 1402 * - z {float} the third component, optional. 1403 */ 1404 initialize : function(x,y,z) { 1405 if (typeof x == 'object') { 1406 this.x = x[0]; 1407 this.y = x[1]; 1408 this.z = x[2] || 0.0; 1409 } else if (typeof x == 'string') { 1410 var coords = x.split(','); 1411 this.x = parseFloat(coords[0]); 1412 this.y = parseFloat(coords[1]); 1413 this.z = parseFloat(coords[2]) || 0.0; 1414 } else { 1415 this.x = x; 1416 this.y = y; 1417 this.z = z || 0.0; 1418 } 1419 }, 1420 1421 /** 1422 * APIMethod: clone 1423 * Build a copy of a Proj4js.Point object. 1424 * 1425 * Return: 1426 * {Proj4js}.Point the cloned point. 1427 */ 1428 clone : function() { 1429 return new Proj4js.Point(this.x, this.y, this.z); 1430 }, 1431 1432 /** 1433 * APIMethod: toString 1434 * Return a readable string version of the point 1435 * 1436 * Return: 1437 * {String} String representation of Proj4js.Point object. 1438 * (ex. <i>"x=5,y=42"</i>) 1439 */ 1440 toString : function() { 1441 return ("x=" + this.x + ",y=" + this.y); 1442 }, 1443 1444 /** 1445 * APIMethod: toShortString 1446 * Return a short string version of the point. 1447 * 1448 * Return: 1449 * {String} Shortened String representation of Proj4js.Point object. 1450 * (ex. <i>"5, 42"</i>) 1451 */ 1452 toShortString : function() { 1453 return (this.x + ", " + this.y); 1454 } 1455}); 1456 1457Proj4js.PrimeMeridian = { 1458 "greenwich": 0.0, //"0dE", 1459 "lisbon": -9.131906111111, //"9d07'54.862\"W", 1460 "paris": 2.337229166667, //"2d20'14.025\"E"…
Large files files are truncated, but you can click here to view the full file