proj4js.js 62 KB

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