proj4-src.js 182 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('wkt-parser')) :
  3. typeof define === 'function' && define.amd ? define(['wkt-parser'], factory) :
  4. (global.proj4 = factory(global.wkt));
  5. }(this, (function (wkt) { 'use strict';
  6. wkt = wkt && wkt.hasOwnProperty('default') ? wkt['default'] : wkt;
  7. var globals = function(defs) {
  8. defs('EPSG:4326', "+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees");
  9. defs('EPSG:4269', "+title=NAD83 (long/lat) +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees");
  10. defs('EPSG:3857', "+title=WGS 84 / Pseudo-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");
  11. defs.WGS84 = defs['EPSG:4326'];
  12. defs['EPSG:3785'] = defs['EPSG:3857']; // maintain backward compat, official code is 3857
  13. defs.GOOGLE = defs['EPSG:3857'];
  14. defs['EPSG:900913'] = defs['EPSG:3857'];
  15. defs['EPSG:102113'] = defs['EPSG:3857'];
  16. };
  17. var PJD_3PARAM = 1;
  18. var PJD_7PARAM = 2;
  19. var PJD_WGS84 = 4; // WGS84 or equivalent
  20. var PJD_NODATUM = 5; // WGS84 or equivalent
  21. var SEC_TO_RAD = 4.84813681109535993589914102357e-6;
  22. var HALF_PI = Math.PI/2;
  23. // ellipoid pj_set_ell.c
  24. var SIXTH = 0.1666666666666666667;
  25. /* 1/6 */
  26. var RA4 = 0.04722222222222222222;
  27. /* 17/360 */
  28. var RA6 = 0.02215608465608465608;
  29. var EPSLN = 1.0e-10;
  30. // you'd think you could use Number.EPSILON above but that makes
  31. // Mollweide get into an infinate loop.
  32. var D2R = 0.01745329251994329577;
  33. var R2D = 57.29577951308232088;
  34. var FORTPI = Math.PI/4;
  35. var TWO_PI = Math.PI * 2;
  36. // SPI is slightly greater than Math.PI, so values that exceed the -180..180
  37. // degree range by a tiny amount don't get wrapped. This prevents points that
  38. // have drifted from their original location along the 180th meridian (due to
  39. // floating point error) from changing their sign.
  40. var SPI = 3.14159265359;
  41. var exports$1 = {};
  42. exports$1.greenwich = 0.0; //"0dE",
  43. exports$1.lisbon = -9.131906111111; //"9d07'54.862\"W",
  44. exports$1.paris = 2.337229166667; //"2d20'14.025\"E",
  45. exports$1.bogota = -74.080916666667; //"74d04'51.3\"W",
  46. exports$1.madrid = -3.687938888889; //"3d41'16.58\"W",
  47. exports$1.rome = 12.452333333333; //"12d27'8.4\"E",
  48. exports$1.bern = 7.439583333333; //"7d26'22.5\"E",
  49. exports$1.jakarta = 106.807719444444; //"106d48'27.79\"E",
  50. exports$1.ferro = -17.666666666667; //"17d40'W",
  51. exports$1.brussels = 4.367975; //"4d22'4.71\"E",
  52. exports$1.stockholm = 18.058277777778; //"18d3'29.8\"E",
  53. exports$1.athens = 23.7163375; //"23d42'58.815\"E",
  54. exports$1.oslo = 10.722916666667; //"10d43'22.5\"E"
  55. var units = {
  56. ft: {to_meter: 0.3048},
  57. 'us-ft': {to_meter: 1200 / 3937}
  58. };
  59. var ignoredChar = /[\s_\-\/\(\)]/g;
  60. function match(obj, key) {
  61. if (obj[key]) {
  62. return obj[key];
  63. }
  64. var keys = Object.keys(obj);
  65. var lkey = key.toLowerCase().replace(ignoredChar, '');
  66. var i = -1;
  67. var testkey, processedKey;
  68. while (++i < keys.length) {
  69. testkey = keys[i];
  70. processedKey = testkey.toLowerCase().replace(ignoredChar, '');
  71. if (processedKey === lkey) {
  72. return obj[testkey];
  73. }
  74. }
  75. }
  76. var parseProj = function(defData) {
  77. var self = {};
  78. var paramObj = defData.split('+').map(function(v) {
  79. return v.trim();
  80. }).filter(function(a) {
  81. return a;
  82. }).reduce(function(p, a) {
  83. var split = a.split('=');
  84. split.push(true);
  85. p[split[0].toLowerCase()] = split[1];
  86. return p;
  87. }, {});
  88. var paramName, paramVal, paramOutname;
  89. var params = {
  90. proj: 'projName',
  91. datum: 'datumCode',
  92. rf: function(v) {
  93. self.rf = parseFloat(v);
  94. },
  95. lat_0: function(v) {
  96. self.lat0 = v * D2R;
  97. },
  98. lat_1: function(v) {
  99. self.lat1 = v * D2R;
  100. },
  101. lat_2: function(v) {
  102. self.lat2 = v * D2R;
  103. },
  104. lat_ts: function(v) {
  105. self.lat_ts = v * D2R;
  106. },
  107. lon_0: function(v) {
  108. self.long0 = v * D2R;
  109. },
  110. lon_1: function(v) {
  111. self.long1 = v * D2R;
  112. },
  113. lon_2: function(v) {
  114. self.long2 = v * D2R;
  115. },
  116. alpha: function(v) {
  117. self.alpha = parseFloat(v) * D2R;
  118. },
  119. lonc: function(v) {
  120. self.longc = v * D2R;
  121. },
  122. x_0: function(v) {
  123. self.x0 = parseFloat(v);
  124. },
  125. y_0: function(v) {
  126. self.y0 = parseFloat(v);
  127. },
  128. k_0: function(v) {
  129. self.k0 = parseFloat(v);
  130. },
  131. k: function(v) {
  132. self.k0 = parseFloat(v);
  133. },
  134. a: function(v) {
  135. self.a = parseFloat(v);
  136. },
  137. b: function(v) {
  138. self.b = parseFloat(v);
  139. },
  140. r_a: function() {
  141. self.R_A = true;
  142. },
  143. zone: function(v) {
  144. self.zone = parseInt(v, 10);
  145. },
  146. south: function() {
  147. self.utmSouth = true;
  148. },
  149. towgs84: function(v) {
  150. self.datum_params = v.split(",").map(function(a) {
  151. return parseFloat(a);
  152. });
  153. },
  154. to_meter: function(v) {
  155. self.to_meter = parseFloat(v);
  156. },
  157. units: function(v) {
  158. self.units = v;
  159. var unit = match(units, v);
  160. if (unit) {
  161. self.to_meter = unit.to_meter;
  162. }
  163. },
  164. from_greenwich: function(v) {
  165. self.from_greenwich = v * D2R;
  166. },
  167. pm: function(v) {
  168. var pm = match(exports$1, v);
  169. self.from_greenwich = (pm ? pm : parseFloat(v)) * D2R;
  170. },
  171. nadgrids: function(v) {
  172. if (v === '@null') {
  173. self.datumCode = 'none';
  174. }
  175. else {
  176. self.nadgrids = v;
  177. }
  178. },
  179. axis: function(v) {
  180. var legalAxis = "ewnsud";
  181. if (v.length === 3 && legalAxis.indexOf(v.substr(0, 1)) !== -1 && legalAxis.indexOf(v.substr(1, 1)) !== -1 && legalAxis.indexOf(v.substr(2, 1)) !== -1) {
  182. self.axis = v;
  183. }
  184. }
  185. };
  186. for (paramName in paramObj) {
  187. paramVal = paramObj[paramName];
  188. if (paramName in params) {
  189. paramOutname = params[paramName];
  190. if (typeof paramOutname === 'function') {
  191. paramOutname(paramVal);
  192. }
  193. else {
  194. self[paramOutname] = paramVal;
  195. }
  196. }
  197. else {
  198. self[paramName] = paramVal;
  199. }
  200. }
  201. if(typeof self.datumCode === 'string' && self.datumCode !== "WGS84"){
  202. self.datumCode = self.datumCode.toLowerCase();
  203. }
  204. return self;
  205. };
  206. function defs(name) {
  207. /*global console*/
  208. var that = this;
  209. if (arguments.length === 2) {
  210. var def = arguments[1];
  211. if (typeof def === 'string') {
  212. if (def.charAt(0) === '+') {
  213. defs[name] = parseProj(arguments[1]);
  214. }
  215. else {
  216. defs[name] = wkt(arguments[1]);
  217. }
  218. } else {
  219. defs[name] = def;
  220. }
  221. }
  222. else if (arguments.length === 1) {
  223. if (Array.isArray(name)) {
  224. return name.map(function(v) {
  225. if (Array.isArray(v)) {
  226. defs.apply(that, v);
  227. }
  228. else {
  229. defs(v);
  230. }
  231. });
  232. }
  233. else if (typeof name === 'string') {
  234. if (name in defs) {
  235. return defs[name];
  236. }
  237. }
  238. else if ('EPSG' in name) {
  239. defs['EPSG:' + name.EPSG] = name;
  240. }
  241. else if ('ESRI' in name) {
  242. defs['ESRI:' + name.ESRI] = name;
  243. }
  244. else if ('IAU2000' in name) {
  245. defs['IAU2000:' + name.IAU2000] = name;
  246. }
  247. else {
  248. console.log(name);
  249. }
  250. return;
  251. }
  252. }
  253. globals(defs);
  254. function testObj(code){
  255. return typeof code === 'string';
  256. }
  257. function testDef(code){
  258. return code in defs;
  259. }
  260. var codeWords = ['PROJECTEDCRS', 'PROJCRS', 'GEOGCS','GEOCCS','PROJCS','LOCAL_CS', 'GEODCRS', 'GEODETICCRS', 'GEODETICDATUM', 'ENGCRS', 'ENGINEERINGCRS'];
  261. function testWKT(code){
  262. return codeWords.some(function (word) {
  263. return code.indexOf(word) > -1;
  264. });
  265. }
  266. var codes = ['3857', '900913', '3785', '102113'];
  267. function checkMercator(item) {
  268. var auth = match(item, 'authority');
  269. if (!auth) {
  270. return;
  271. }
  272. var code = match(auth, 'epsg');
  273. return code && codes.indexOf(code) > -1;
  274. }
  275. function checkProjStr(item) {
  276. var ext = match(item, 'extension');
  277. if (!ext) {
  278. return;
  279. }
  280. return match(ext, 'proj4');
  281. }
  282. function testProj(code){
  283. return code[0] === '+';
  284. }
  285. function parse(code){
  286. if (testObj(code)) {
  287. //check to see if this is a WKT string
  288. if (testDef(code)) {
  289. return defs[code];
  290. }
  291. if (testWKT(code)) {
  292. var out = wkt(code);
  293. // test of spetial case, due to this being a very common and often malformed
  294. if (checkMercator(out)) {
  295. return defs['EPSG:3857'];
  296. }
  297. var maybeProjStr = checkProjStr(out);
  298. if (maybeProjStr) {
  299. return parseProj(maybeProjStr);
  300. }
  301. return out;
  302. }
  303. if (testProj(code)) {
  304. return parseProj(code);
  305. }
  306. }else{
  307. return code;
  308. }
  309. }
  310. var extend = function(destination, source) {
  311. destination = destination || {};
  312. var value, property;
  313. if (!source) {
  314. return destination;
  315. }
  316. for (property in source) {
  317. value = source[property];
  318. if (value !== undefined) {
  319. destination[property] = value;
  320. }
  321. }
  322. return destination;
  323. };
  324. var msfnz = function(eccent, sinphi, cosphi) {
  325. var con = eccent * sinphi;
  326. return cosphi / (Math.sqrt(1 - con * con));
  327. };
  328. var sign = function(x) {
  329. return x<0 ? -1 : 1;
  330. };
  331. var adjust_lon = function(x) {
  332. return (Math.abs(x) <= SPI) ? x : (x - (sign(x) * TWO_PI));
  333. };
  334. var tsfnz = function(eccent, phi, sinphi) {
  335. var con = eccent * sinphi;
  336. var com = 0.5 * eccent;
  337. con = Math.pow(((1 - con) / (1 + con)), com);
  338. return (Math.tan(0.5 * (HALF_PI - phi)) / con);
  339. };
  340. var phi2z = function(eccent, ts) {
  341. var eccnth = 0.5 * eccent;
  342. var con, dphi;
  343. var phi = HALF_PI - 2 * Math.atan(ts);
  344. for (var i = 0; i <= 15; i++) {
  345. con = eccent * Math.sin(phi);
  346. dphi = HALF_PI - 2 * Math.atan(ts * (Math.pow(((1 - con) / (1 + con)), eccnth))) - phi;
  347. phi += dphi;
  348. if (Math.abs(dphi) <= 0.0000000001) {
  349. return phi;
  350. }
  351. }
  352. //console.log("phi2z has NoConvergence");
  353. return -9999;
  354. };
  355. function init() {
  356. var con = this.b / this.a;
  357. this.es = 1 - con * con;
  358. if(!('x0' in this)){
  359. this.x0 = 0;
  360. }
  361. if(!('y0' in this)){
  362. this.y0 = 0;
  363. }
  364. this.e = Math.sqrt(this.es);
  365. if (this.lat_ts) {
  366. if (this.sphere) {
  367. this.k0 = Math.cos(this.lat_ts);
  368. }
  369. else {
  370. this.k0 = msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts));
  371. }
  372. }
  373. else {
  374. if (!this.k0) {
  375. if (this.k) {
  376. this.k0 = this.k;
  377. }
  378. else {
  379. this.k0 = 1;
  380. }
  381. }
  382. }
  383. }
  384. /* Mercator forward equations--mapping lat,long to x,y
  385. --------------------------------------------------*/
  386. function forward(p) {
  387. var lon = p.x;
  388. var lat = p.y;
  389. // convert to radians
  390. if (lat * R2D > 90 && lat * R2D < -90 && lon * R2D > 180 && lon * R2D < -180) {
  391. return null;
  392. }
  393. var x, y;
  394. if (Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN) {
  395. return null;
  396. }
  397. else {
  398. if (this.sphere) {
  399. x = this.x0 + this.a * this.k0 * adjust_lon(lon - this.long0);
  400. y = this.y0 + this.a * this.k0 * Math.log(Math.tan(FORTPI + 0.5 * lat));
  401. }
  402. else {
  403. var sinphi = Math.sin(lat);
  404. var ts = tsfnz(this.e, lat, sinphi);
  405. x = this.x0 + this.a * this.k0 * adjust_lon(lon - this.long0);
  406. y = this.y0 - this.a * this.k0 * Math.log(ts);
  407. }
  408. p.x = x;
  409. p.y = y;
  410. return p;
  411. }
  412. }
  413. /* Mercator inverse equations--mapping x,y to lat/long
  414. --------------------------------------------------*/
  415. function inverse(p) {
  416. var x = p.x - this.x0;
  417. var y = p.y - this.y0;
  418. var lon, lat;
  419. if (this.sphere) {
  420. lat = HALF_PI - 2 * Math.atan(Math.exp(-y / (this.a * this.k0)));
  421. }
  422. else {
  423. var ts = Math.exp(-y / (this.a * this.k0));
  424. lat = phi2z(this.e, ts);
  425. if (lat === -9999) {
  426. return null;
  427. }
  428. }
  429. lon = adjust_lon(this.long0 + x / (this.a * this.k0));
  430. p.x = lon;
  431. p.y = lat;
  432. return p;
  433. }
  434. var names$1 = ["Mercator", "Popular Visualisation Pseudo Mercator", "Mercator_1SP", "Mercator_Auxiliary_Sphere", "merc"];
  435. var merc = {
  436. init: init,
  437. forward: forward,
  438. inverse: inverse,
  439. names: names$1
  440. };
  441. function init$1() {
  442. //no-op for longlat
  443. }
  444. function identity(pt) {
  445. return pt;
  446. }
  447. var names$2 = ["longlat", "identity"];
  448. var longlat = {
  449. init: init$1,
  450. forward: identity,
  451. inverse: identity,
  452. names: names$2
  453. };
  454. var projs = [merc, longlat];
  455. var names = {};
  456. var projStore = [];
  457. function add(proj, i) {
  458. var len = projStore.length;
  459. if (!proj.names) {
  460. console.log(i);
  461. return true;
  462. }
  463. projStore[len] = proj;
  464. proj.names.forEach(function(n) {
  465. names[n.toLowerCase()] = len;
  466. });
  467. return this;
  468. }
  469. function get(name) {
  470. if (!name) {
  471. return false;
  472. }
  473. var n = name.toLowerCase();
  474. if (typeof names[n] !== 'undefined' && projStore[names[n]]) {
  475. return projStore[names[n]];
  476. }
  477. }
  478. function start() {
  479. projs.forEach(add);
  480. }
  481. var projections = {
  482. start: start,
  483. add: add,
  484. get: get
  485. };
  486. var exports$2 = {};
  487. exports$2.MERIT = {
  488. a: 6378137.0,
  489. rf: 298.257,
  490. ellipseName: "MERIT 1983"
  491. };
  492. exports$2.SGS85 = {
  493. a: 6378136.0,
  494. rf: 298.257,
  495. ellipseName: "Soviet Geodetic System 85"
  496. };
  497. exports$2.GRS80 = {
  498. a: 6378137.0,
  499. rf: 298.257222101,
  500. ellipseName: "GRS 1980(IUGG, 1980)"
  501. };
  502. exports$2.IAU76 = {
  503. a: 6378140.0,
  504. rf: 298.257,
  505. ellipseName: "IAU 1976"
  506. };
  507. exports$2.airy = {
  508. a: 6377563.396,
  509. b: 6356256.910,
  510. ellipseName: "Airy 1830"
  511. };
  512. exports$2.APL4 = {
  513. a: 6378137,
  514. rf: 298.25,
  515. ellipseName: "Appl. Physics. 1965"
  516. };
  517. exports$2.NWL9D = {
  518. a: 6378145.0,
  519. rf: 298.25,
  520. ellipseName: "Naval Weapons Lab., 1965"
  521. };
  522. exports$2.mod_airy = {
  523. a: 6377340.189,
  524. b: 6356034.446,
  525. ellipseName: "Modified Airy"
  526. };
  527. exports$2.andrae = {
  528. a: 6377104.43,
  529. rf: 300.0,
  530. ellipseName: "Andrae 1876 (Den., Iclnd.)"
  531. };
  532. exports$2.aust_SA = {
  533. a: 6378160.0,
  534. rf: 298.25,
  535. ellipseName: "Australian Natl & S. Amer. 1969"
  536. };
  537. exports$2.GRS67 = {
  538. a: 6378160.0,
  539. rf: 298.2471674270,
  540. ellipseName: "GRS 67(IUGG 1967)"
  541. };
  542. exports$2.bessel = {
  543. a: 6377397.155,
  544. rf: 299.1528128,
  545. ellipseName: "Bessel 1841"
  546. };
  547. exports$2.bess_nam = {
  548. a: 6377483.865,
  549. rf: 299.1528128,
  550. ellipseName: "Bessel 1841 (Namibia)"
  551. };
  552. exports$2.clrk66 = {
  553. a: 6378206.4,
  554. b: 6356583.8,
  555. ellipseName: "Clarke 1866"
  556. };
  557. exports$2.clrk80 = {
  558. a: 6378249.145,
  559. rf: 293.4663,
  560. ellipseName: "Clarke 1880 mod."
  561. };
  562. exports$2.clrk58 = {
  563. a: 6378293.645208759,
  564. rf: 294.2606763692654,
  565. ellipseName: "Clarke 1858"
  566. };
  567. exports$2.CPM = {
  568. a: 6375738.7,
  569. rf: 334.29,
  570. ellipseName: "Comm. des Poids et Mesures 1799"
  571. };
  572. exports$2.delmbr = {
  573. a: 6376428.0,
  574. rf: 311.5,
  575. ellipseName: "Delambre 1810 (Belgium)"
  576. };
  577. exports$2.engelis = {
  578. a: 6378136.05,
  579. rf: 298.2566,
  580. ellipseName: "Engelis 1985"
  581. };
  582. exports$2.evrst30 = {
  583. a: 6377276.345,
  584. rf: 300.8017,
  585. ellipseName: "Everest 1830"
  586. };
  587. exports$2.evrst48 = {
  588. a: 6377304.063,
  589. rf: 300.8017,
  590. ellipseName: "Everest 1948"
  591. };
  592. exports$2.evrst56 = {
  593. a: 6377301.243,
  594. rf: 300.8017,
  595. ellipseName: "Everest 1956"
  596. };
  597. exports$2.evrst69 = {
  598. a: 6377295.664,
  599. rf: 300.8017,
  600. ellipseName: "Everest 1969"
  601. };
  602. exports$2.evrstSS = {
  603. a: 6377298.556,
  604. rf: 300.8017,
  605. ellipseName: "Everest (Sabah & Sarawak)"
  606. };
  607. exports$2.fschr60 = {
  608. a: 6378166.0,
  609. rf: 298.3,
  610. ellipseName: "Fischer (Mercury Datum) 1960"
  611. };
  612. exports$2.fschr60m = {
  613. a: 6378155.0,
  614. rf: 298.3,
  615. ellipseName: "Fischer 1960"
  616. };
  617. exports$2.fschr68 = {
  618. a: 6378150.0,
  619. rf: 298.3,
  620. ellipseName: "Fischer 1968"
  621. };
  622. exports$2.helmert = {
  623. a: 6378200.0,
  624. rf: 298.3,
  625. ellipseName: "Helmert 1906"
  626. };
  627. exports$2.hough = {
  628. a: 6378270.0,
  629. rf: 297.0,
  630. ellipseName: "Hough"
  631. };
  632. exports$2.intl = {
  633. a: 6378388.0,
  634. rf: 297.0,
  635. ellipseName: "International 1909 (Hayford)"
  636. };
  637. exports$2.kaula = {
  638. a: 6378163.0,
  639. rf: 298.24,
  640. ellipseName: "Kaula 1961"
  641. };
  642. exports$2.lerch = {
  643. a: 6378139.0,
  644. rf: 298.257,
  645. ellipseName: "Lerch 1979"
  646. };
  647. exports$2.mprts = {
  648. a: 6397300.0,
  649. rf: 191.0,
  650. ellipseName: "Maupertius 1738"
  651. };
  652. exports$2.new_intl = {
  653. a: 6378157.5,
  654. b: 6356772.2,
  655. ellipseName: "New International 1967"
  656. };
  657. exports$2.plessis = {
  658. a: 6376523.0,
  659. rf: 6355863.0,
  660. ellipseName: "Plessis 1817 (France)"
  661. };
  662. exports$2.krass = {
  663. a: 6378245.0,
  664. rf: 298.3,
  665. ellipseName: "Krassovsky, 1942"
  666. };
  667. exports$2.SEasia = {
  668. a: 6378155.0,
  669. b: 6356773.3205,
  670. ellipseName: "Southeast Asia"
  671. };
  672. exports$2.walbeck = {
  673. a: 6376896.0,
  674. b: 6355834.8467,
  675. ellipseName: "Walbeck"
  676. };
  677. exports$2.WGS60 = {
  678. a: 6378165.0,
  679. rf: 298.3,
  680. ellipseName: "WGS 60"
  681. };
  682. exports$2.WGS66 = {
  683. a: 6378145.0,
  684. rf: 298.25,
  685. ellipseName: "WGS 66"
  686. };
  687. exports$2.WGS7 = {
  688. a: 6378135.0,
  689. rf: 298.26,
  690. ellipseName: "WGS 72"
  691. };
  692. var WGS84 = exports$2.WGS84 = {
  693. a: 6378137.0,
  694. rf: 298.257223563,
  695. ellipseName: "WGS 84"
  696. };
  697. exports$2.sphere = {
  698. a: 6370997.0,
  699. b: 6370997.0,
  700. ellipseName: "Normal Sphere (r=6370997)"
  701. };
  702. function eccentricity(a, b, rf, R_A) {
  703. var a2 = a * a; // used in geocentric
  704. var b2 = b * b; // used in geocentric
  705. var es = (a2 - b2) / a2; // e ^ 2
  706. var e = 0;
  707. if (R_A) {
  708. a *= 1 - es * (SIXTH + es * (RA4 + es * RA6));
  709. a2 = a * a;
  710. es = 0;
  711. } else {
  712. e = Math.sqrt(es); // eccentricity
  713. }
  714. var ep2 = (a2 - b2) / b2; // used in geocentric
  715. return {
  716. es: es,
  717. e: e,
  718. ep2: ep2
  719. };
  720. }
  721. function sphere(a, b, rf, ellps, sphere) {
  722. if (!a) { // do we have an ellipsoid?
  723. var ellipse = match(exports$2, ellps);
  724. if (!ellipse) {
  725. ellipse = WGS84;
  726. }
  727. a = ellipse.a;
  728. b = ellipse.b;
  729. rf = ellipse.rf;
  730. }
  731. if (rf && !b) {
  732. b = (1.0 - 1.0 / rf) * a;
  733. }
  734. if (rf === 0 || Math.abs(a - b) < EPSLN) {
  735. sphere = true;
  736. b = a;
  737. }
  738. return {
  739. a: a,
  740. b: b,
  741. rf: rf,
  742. sphere: sphere
  743. };
  744. }
  745. var exports$3 = {};
  746. exports$3.wgs84 = {
  747. towgs84: "0,0,0",
  748. ellipse: "WGS84",
  749. datumName: "WGS84"
  750. };
  751. exports$3.ch1903 = {
  752. towgs84: "674.374,15.056,405.346",
  753. ellipse: "bessel",
  754. datumName: "swiss"
  755. };
  756. exports$3.ggrs87 = {
  757. towgs84: "-199.87,74.79,246.62",
  758. ellipse: "GRS80",
  759. datumName: "Greek_Geodetic_Reference_System_1987"
  760. };
  761. exports$3.nad83 = {
  762. towgs84: "0,0,0",
  763. ellipse: "GRS80",
  764. datumName: "North_American_Datum_1983"
  765. };
  766. exports$3.nad27 = {
  767. nadgrids: "@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat",
  768. ellipse: "clrk66",
  769. datumName: "North_American_Datum_1927"
  770. };
  771. exports$3.potsdam = {
  772. towgs84: "606.0,23.0,413.0",
  773. ellipse: "bessel",
  774. datumName: "Potsdam Rauenberg 1950 DHDN"
  775. };
  776. exports$3.carthage = {
  777. towgs84: "-263.0,6.0,431.0",
  778. ellipse: "clark80",
  779. datumName: "Carthage 1934 Tunisia"
  780. };
  781. exports$3.hermannskogel = {
  782. towgs84: "653.0,-212.0,449.0",
  783. ellipse: "bessel",
  784. datumName: "Hermannskogel"
  785. };
  786. exports$3.osni52 = {
  787. towgs84: "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",
  788. ellipse: "airy",
  789. datumName: "Irish National"
  790. };
  791. exports$3.ire65 = {
  792. towgs84: "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",
  793. ellipse: "mod_airy",
  794. datumName: "Ireland 1965"
  795. };
  796. exports$3.rassadiran = {
  797. towgs84: "-133.63,-157.5,-158.62",
  798. ellipse: "intl",
  799. datumName: "Rassadiran"
  800. };
  801. exports$3.nzgd49 = {
  802. towgs84: "59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993",
  803. ellipse: "intl",
  804. datumName: "New Zealand Geodetic Datum 1949"
  805. };
  806. exports$3.osgb36 = {
  807. towgs84: "446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894",
  808. ellipse: "airy",
  809. datumName: "Airy 1830"
  810. };
  811. exports$3.s_jtsk = {
  812. towgs84: "589,76,480",
  813. ellipse: 'bessel',
  814. datumName: 'S-JTSK (Ferro)'
  815. };
  816. exports$3.beduaram = {
  817. towgs84: '-106,-87,188',
  818. ellipse: 'clrk80',
  819. datumName: 'Beduaram'
  820. };
  821. exports$3.gunung_segara = {
  822. towgs84: '-403,684,41',
  823. ellipse: 'bessel',
  824. datumName: 'Gunung Segara Jakarta'
  825. };
  826. exports$3.rnb72 = {
  827. towgs84: "106.869,-52.2978,103.724,-0.33657,0.456955,-1.84218,1",
  828. ellipse: "intl",
  829. datumName: "Reseau National Belge 1972"
  830. };
  831. function datum(datumCode, datum_params, a, b, es, ep2) {
  832. var out = {};
  833. if (datumCode === undefined || datumCode === 'none') {
  834. out.datum_type = PJD_NODATUM;
  835. } else {
  836. out.datum_type = PJD_WGS84;
  837. }
  838. if (datum_params) {
  839. out.datum_params = datum_params.map(parseFloat);
  840. if (out.datum_params[0] !== 0 || out.datum_params[1] !== 0 || out.datum_params[2] !== 0) {
  841. out.datum_type = PJD_3PARAM;
  842. }
  843. if (out.datum_params.length > 3) {
  844. if (out.datum_params[3] !== 0 || out.datum_params[4] !== 0 || out.datum_params[5] !== 0 || out.datum_params[6] !== 0) {
  845. out.datum_type = PJD_7PARAM;
  846. out.datum_params[3] *= SEC_TO_RAD;
  847. out.datum_params[4] *= SEC_TO_RAD;
  848. out.datum_params[5] *= SEC_TO_RAD;
  849. out.datum_params[6] = (out.datum_params[6] / 1000000.0) + 1.0;
  850. }
  851. }
  852. }
  853. out.a = a; //datum object also uses these values
  854. out.b = b;
  855. out.es = es;
  856. out.ep2 = ep2;
  857. return out;
  858. }
  859. function Projection(srsCode,callback) {
  860. if (!(this instanceof Projection)) {
  861. return new Projection(srsCode);
  862. }
  863. callback = callback || function(error){
  864. if(error){
  865. throw error;
  866. }
  867. };
  868. var json = parse(srsCode);
  869. if(typeof json !== 'object'){
  870. callback(srsCode);
  871. return;
  872. }
  873. var ourProj = Projection.projections.get(json.projName);
  874. if(!ourProj){
  875. callback(srsCode);
  876. return;
  877. }
  878. if (json.datumCode && json.datumCode !== 'none') {
  879. var datumDef = match(exports$3, json.datumCode);
  880. if (datumDef) {
  881. json.datum_params = datumDef.towgs84 ? datumDef.towgs84.split(',') : null;
  882. json.ellps = datumDef.ellipse;
  883. json.datumName = datumDef.datumName ? datumDef.datumName : json.datumCode;
  884. }
  885. }
  886. json.k0 = json.k0 || 1.0;
  887. json.axis = json.axis || 'enu';
  888. json.ellps = json.ellps || 'wgs84';
  889. var sphere_ = sphere(json.a, json.b, json.rf, json.ellps, json.sphere);
  890. var ecc = eccentricity(sphere_.a, sphere_.b, sphere_.rf, json.R_A);
  891. var datumObj = json.datum || datum(json.datumCode, json.datum_params, sphere_.a, sphere_.b, ecc.es, ecc.ep2);
  892. extend(this, json); // transfer everything over from the projection because we don't know what we'll need
  893. extend(this, ourProj); // transfer all the methods from the projection
  894. // copy the 4 things over we calulated in deriveConstants.sphere
  895. this.a = sphere_.a;
  896. this.b = sphere_.b;
  897. this.rf = sphere_.rf;
  898. this.sphere = sphere_.sphere;
  899. // copy the 3 things we calculated in deriveConstants.eccentricity
  900. this.es = ecc.es;
  901. this.e = ecc.e;
  902. this.ep2 = ecc.ep2;
  903. // add in the datum object
  904. this.datum = datumObj;
  905. // init the projection
  906. this.init();
  907. // legecy callback from back in the day when it went to spatialreference.org
  908. callback(null, this);
  909. }
  910. Projection.projections = projections;
  911. Projection.projections.start();
  912. 'use strict';
  913. function compareDatums(source, dest) {
  914. if (source.datum_type !== dest.datum_type) {
  915. return false; // false, datums are not equal
  916. } else if (source.a !== dest.a || Math.abs(source.es - dest.es) > 0.000000000050) {
  917. // the tolerance for es is to ensure that GRS80 and WGS84
  918. // are considered identical
  919. return false;
  920. } else if (source.datum_type === PJD_3PARAM) {
  921. return (source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2]);
  922. } else if (source.datum_type === PJD_7PARAM) {
  923. return (source.datum_params[0] === dest.datum_params[0] && source.datum_params[1] === dest.datum_params[1] && source.datum_params[2] === dest.datum_params[2] && source.datum_params[3] === dest.datum_params[3] && source.datum_params[4] === dest.datum_params[4] && source.datum_params[5] === dest.datum_params[5] && source.datum_params[6] === dest.datum_params[6]);
  924. } else {
  925. return true; // datums are equal
  926. }
  927. } // cs_compare_datums()
  928. /*
  929. * The function Convert_Geodetic_To_Geocentric converts geodetic coordinates
  930. * (latitude, longitude, and height) to geocentric coordinates (X, Y, Z),
  931. * according to the current ellipsoid parameters.
  932. *
  933. * Latitude : Geodetic latitude in radians (input)
  934. * Longitude : Geodetic longitude in radians (input)
  935. * Height : Geodetic height, in meters (input)
  936. * X : Calculated Geocentric X coordinate, in meters (output)
  937. * Y : Calculated Geocentric Y coordinate, in meters (output)
  938. * Z : Calculated Geocentric Z coordinate, in meters (output)
  939. *
  940. */
  941. function geodeticToGeocentric(p, es, a) {
  942. var Longitude = p.x;
  943. var Latitude = p.y;
  944. var Height = p.z ? p.z : 0; //Z value not always supplied
  945. var Rn; /* Earth radius at location */
  946. var Sin_Lat; /* Math.sin(Latitude) */
  947. var Sin2_Lat; /* Square of Math.sin(Latitude) */
  948. var Cos_Lat; /* Math.cos(Latitude) */
  949. /*
  950. ** Don't blow up if Latitude is just a little out of the value
  951. ** range as it may just be a rounding issue. Also removed longitude
  952. ** test, it should be wrapped by Math.cos() and Math.sin(). NFW for PROJ.4, Sep/2001.
  953. */
  954. if (Latitude < -HALF_PI && Latitude > -1.001 * HALF_PI) {
  955. Latitude = -HALF_PI;
  956. } else if (Latitude > HALF_PI && Latitude < 1.001 * HALF_PI) {
  957. Latitude = HALF_PI;
  958. } else if (Latitude < -HALF_PI) {
  959. /* Latitude out of range */
  960. //..reportError('geocent:lat out of range:' + Latitude);
  961. return { x: -Infinity, y: -Infinity, z: p.z };
  962. } else if (Latitude > HALF_PI) {
  963. /* Latitude out of range */
  964. return { x: Infinity, y: Infinity, z: p.z };
  965. }
  966. if (Longitude > Math.PI) {
  967. Longitude -= (2 * Math.PI);
  968. }
  969. Sin_Lat = Math.sin(Latitude);
  970. Cos_Lat = Math.cos(Latitude);
  971. Sin2_Lat = Sin_Lat * Sin_Lat;
  972. Rn = a / (Math.sqrt(1.0e0 - es * Sin2_Lat));
  973. return {
  974. x: (Rn + Height) * Cos_Lat * Math.cos(Longitude),
  975. y: (Rn + Height) * Cos_Lat * Math.sin(Longitude),
  976. z: ((Rn * (1 - es)) + Height) * Sin_Lat
  977. };
  978. } // cs_geodetic_to_geocentric()
  979. function geocentricToGeodetic(p, es, a, b) {
  980. /* local defintions and variables */
  981. /* end-criterium of loop, accuracy of sin(Latitude) */
  982. var genau = 1e-12;
  983. var genau2 = (genau * genau);
  984. var maxiter = 30;
  985. var P; /* distance between semi-minor axis and location */
  986. var RR; /* distance between center and location */
  987. var CT; /* sin of geocentric latitude */
  988. var ST; /* cos of geocentric latitude */
  989. var RX;
  990. var RK;
  991. var RN; /* Earth radius at location */
  992. var CPHI0; /* cos of start or old geodetic latitude in iterations */
  993. var SPHI0; /* sin of start or old geodetic latitude in iterations */
  994. var CPHI; /* cos of searched geodetic latitude */
  995. var SPHI; /* sin of searched geodetic latitude */
  996. var SDPHI; /* end-criterium: addition-theorem of sin(Latitude(iter)-Latitude(iter-1)) */
  997. var iter; /* # of continous iteration, max. 30 is always enough (s.a.) */
  998. var X = p.x;
  999. var Y = p.y;
  1000. var Z = p.z ? p.z : 0.0; //Z value not always supplied
  1001. var Longitude;
  1002. var Latitude;
  1003. var Height;
  1004. P = Math.sqrt(X * X + Y * Y);
  1005. RR = Math.sqrt(X * X + Y * Y + Z * Z);
  1006. /* special cases for latitude and longitude */
  1007. if (P / a < genau) {
  1008. /* special case, if P=0. (X=0., Y=0.) */
  1009. Longitude = 0.0;
  1010. /* if (X,Y,Z)=(0.,0.,0.) then Height becomes semi-minor axis
  1011. * of ellipsoid (=center of mass), Latitude becomes PI/2 */
  1012. if (RR / a < genau) {
  1013. Latitude = HALF_PI;
  1014. Height = -b;
  1015. return {
  1016. x: p.x,
  1017. y: p.y,
  1018. z: p.z
  1019. };
  1020. }
  1021. } else {
  1022. /* ellipsoidal (geodetic) longitude
  1023. * interval: -PI < Longitude <= +PI */
  1024. Longitude = Math.atan2(Y, X);
  1025. }
  1026. /* --------------------------------------------------------------
  1027. * Following iterative algorithm was developped by
  1028. * "Institut for Erdmessung", University of Hannover, July 1988.
  1029. * Internet: www.ife.uni-hannover.de
  1030. * Iterative computation of CPHI,SPHI and Height.
  1031. * Iteration of CPHI and SPHI to 10**-12 radian resp.
  1032. * 2*10**-7 arcsec.
  1033. * --------------------------------------------------------------
  1034. */
  1035. CT = Z / RR;
  1036. ST = P / RR;
  1037. RX = 1.0 / Math.sqrt(1.0 - es * (2.0 - es) * ST * ST);
  1038. CPHI0 = ST * (1.0 - es) * RX;
  1039. SPHI0 = CT * RX;
  1040. iter = 0;
  1041. /* loop to find sin(Latitude) resp. Latitude
  1042. * until |sin(Latitude(iter)-Latitude(iter-1))| < genau */
  1043. do {
  1044. iter++;
  1045. RN = a / Math.sqrt(1.0 - es * SPHI0 * SPHI0);
  1046. /* ellipsoidal (geodetic) height */
  1047. Height = P * CPHI0 + Z * SPHI0 - RN * (1.0 - es * SPHI0 * SPHI0);
  1048. RK = es * RN / (RN + Height);
  1049. RX = 1.0 / Math.sqrt(1.0 - RK * (2.0 - RK) * ST * ST);
  1050. CPHI = ST * (1.0 - RK) * RX;
  1051. SPHI = CT * RX;
  1052. SDPHI = SPHI * CPHI0 - CPHI * SPHI0;
  1053. CPHI0 = CPHI;
  1054. SPHI0 = SPHI;
  1055. }
  1056. while (SDPHI * SDPHI > genau2 && iter < maxiter);
  1057. /* ellipsoidal (geodetic) latitude */
  1058. Latitude = Math.atan(SPHI / Math.abs(CPHI));
  1059. return {
  1060. x: Longitude,
  1061. y: Latitude,
  1062. z: Height
  1063. };
  1064. } // cs_geocentric_to_geodetic()
  1065. /****************************************************************/
  1066. // pj_geocentic_to_wgs84( p )
  1067. // p = point to transform in geocentric coordinates (x,y,z)
  1068. /** point object, nothing fancy, just allows values to be
  1069. passed back and forth by reference rather than by value.
  1070. Other point classes may be used as long as they have
  1071. x and y properties, which will get modified in the transform method.
  1072. */
  1073. function geocentricToWgs84(p, datum_type, datum_params) {
  1074. if (datum_type === PJD_3PARAM) {
  1075. // if( x[io] === HUGE_VAL )
  1076. // continue;
  1077. return {
  1078. x: p.x + datum_params[0],
  1079. y: p.y + datum_params[1],
  1080. z: p.z + datum_params[2],
  1081. };
  1082. } else if (datum_type === PJD_7PARAM) {
  1083. var Dx_BF = datum_params[0];
  1084. var Dy_BF = datum_params[1];
  1085. var Dz_BF = datum_params[2];
  1086. var Rx_BF = datum_params[3];
  1087. var Ry_BF = datum_params[4];
  1088. var Rz_BF = datum_params[5];
  1089. var M_BF = datum_params[6];
  1090. // if( x[io] === HUGE_VAL )
  1091. // continue;
  1092. return {
  1093. x: M_BF * (p.x - Rz_BF * p.y + Ry_BF * p.z) + Dx_BF,
  1094. y: M_BF * (Rz_BF * p.x + p.y - Rx_BF * p.z) + Dy_BF,
  1095. z: M_BF * (-Ry_BF * p.x + Rx_BF * p.y + p.z) + Dz_BF
  1096. };
  1097. }
  1098. } // cs_geocentric_to_wgs84
  1099. /****************************************************************/
  1100. // pj_geocentic_from_wgs84()
  1101. // coordinate system definition,
  1102. // point to transform in geocentric coordinates (x,y,z)
  1103. function geocentricFromWgs84(p, datum_type, datum_params) {
  1104. if (datum_type === PJD_3PARAM) {
  1105. //if( x[io] === HUGE_VAL )
  1106. // continue;
  1107. return {
  1108. x: p.x - datum_params[0],
  1109. y: p.y - datum_params[1],
  1110. z: p.z - datum_params[2],
  1111. };
  1112. } else if (datum_type === PJD_7PARAM) {
  1113. var Dx_BF = datum_params[0];
  1114. var Dy_BF = datum_params[1];
  1115. var Dz_BF = datum_params[2];
  1116. var Rx_BF = datum_params[3];
  1117. var Ry_BF = datum_params[4];
  1118. var Rz_BF = datum_params[5];
  1119. var M_BF = datum_params[6];
  1120. var x_tmp = (p.x - Dx_BF) / M_BF;
  1121. var y_tmp = (p.y - Dy_BF) / M_BF;
  1122. var z_tmp = (p.z - Dz_BF) / M_BF;
  1123. //if( x[io] === HUGE_VAL )
  1124. // continue;
  1125. return {
  1126. x: x_tmp + Rz_BF * y_tmp - Ry_BF * z_tmp,
  1127. y: -Rz_BF * x_tmp + y_tmp + Rx_BF * z_tmp,
  1128. z: Ry_BF * x_tmp - Rx_BF * y_tmp + z_tmp
  1129. };
  1130. } //cs_geocentric_from_wgs84()
  1131. }
  1132. function checkParams(type) {
  1133. return (type === PJD_3PARAM || type === PJD_7PARAM);
  1134. }
  1135. var datum_transform = function(source, dest, point) {
  1136. // Short cut if the datums are identical.
  1137. if (compareDatums(source, dest)) {
  1138. return point; // in this case, zero is sucess,
  1139. // whereas cs_compare_datums returns 1 to indicate TRUE
  1140. // confusing, should fix this
  1141. }
  1142. // Explicitly skip datum transform by setting 'datum=none' as parameter for either source or dest
  1143. if (source.datum_type === PJD_NODATUM || dest.datum_type === PJD_NODATUM) {
  1144. return point;
  1145. }
  1146. // If this datum requires grid shifts, then apply it to geodetic coordinates.
  1147. // Do we need to go through geocentric coordinates?
  1148. if (source.es === dest.es && source.a === dest.a && !checkParams(source.datum_type) && !checkParams(dest.datum_type)) {
  1149. return point;
  1150. }
  1151. // Convert to geocentric coordinates.
  1152. point = geodeticToGeocentric(point, source.es, source.a);
  1153. // Convert between datums
  1154. if (checkParams(source.datum_type)) {
  1155. point = geocentricToWgs84(point, source.datum_type, source.datum_params);
  1156. }
  1157. if (checkParams(dest.datum_type)) {
  1158. point = geocentricFromWgs84(point, dest.datum_type, dest.datum_params);
  1159. }
  1160. return geocentricToGeodetic(point, dest.es, dest.a, dest.b);
  1161. };
  1162. var adjust_axis = function(crs, denorm, point) {
  1163. var xin = point.x,
  1164. yin = point.y,
  1165. zin = point.z || 0.0;
  1166. var v, t, i;
  1167. var out = {};
  1168. for (i = 0; i < 3; i++) {
  1169. if (denorm && i === 2 && point.z === undefined) {
  1170. continue;
  1171. }
  1172. if (i === 0) {
  1173. v = xin;
  1174. if ("ew".indexOf(crs.axis[i]) !== -1) {
  1175. t = 'x';
  1176. } else {
  1177. t = 'y';
  1178. }
  1179. }
  1180. else if (i === 1) {
  1181. v = yin;
  1182. if ("ns".indexOf(crs.axis[i]) !== -1) {
  1183. t = 'y';
  1184. } else {
  1185. t = 'x';
  1186. }
  1187. }
  1188. else {
  1189. v = zin;
  1190. t = 'z';
  1191. }
  1192. switch (crs.axis[i]) {
  1193. case 'e':
  1194. case 'w':
  1195. case 'n':
  1196. case 's':
  1197. out[t] = v;
  1198. break;
  1199. case 'u':
  1200. if (point[t] !== undefined) {
  1201. out.z = v;
  1202. }
  1203. break;
  1204. case 'd':
  1205. if (point[t] !== undefined) {
  1206. out.z = -v;
  1207. }
  1208. break;
  1209. default:
  1210. //console.log("ERROR: unknow axis ("+crs.axis[i]+") - check definition of "+crs.projName);
  1211. return null;
  1212. }
  1213. }
  1214. return out;
  1215. };
  1216. var toPoint = function (array){
  1217. var out = {
  1218. x: array[0],
  1219. y: array[1]
  1220. };
  1221. if (array.length>2) {
  1222. out.z = array[2];
  1223. }
  1224. if (array.length>3) {
  1225. out.m = array[3];
  1226. }
  1227. return out;
  1228. };
  1229. var checkSanity = function (point) {
  1230. checkCoord(point.x);
  1231. checkCoord(point.y);
  1232. };
  1233. function checkCoord(num) {
  1234. if (typeof Number.isFinite === 'function') {
  1235. if (Number.isFinite(num)) {
  1236. return;
  1237. }
  1238. throw new TypeError('coordinates must be finite numbers');
  1239. }
  1240. if (typeof num !== 'number' || num !== num || !isFinite(num)) {
  1241. throw new TypeError('coordinates must be finite numbers');
  1242. }
  1243. }
  1244. function checkNotWGS(source, dest) {
  1245. return ((source.datum.datum_type === PJD_3PARAM || source.datum.datum_type === PJD_7PARAM) && dest.datumCode !== 'WGS84') || ((dest.datum.datum_type === PJD_3PARAM || dest.datum.datum_type === PJD_7PARAM) && source.datumCode !== 'WGS84');
  1246. }
  1247. function transform(source, dest, point) {
  1248. var wgs84;
  1249. if (Array.isArray(point)) {
  1250. point = toPoint(point);
  1251. }
  1252. checkSanity(point);
  1253. // Workaround for datum shifts towgs84, if either source or destination projection is not wgs84
  1254. if (source.datum && dest.datum && checkNotWGS(source, dest)) {
  1255. wgs84 = new Projection('WGS84');
  1256. point = transform(source, wgs84, point);
  1257. source = wgs84;
  1258. }
  1259. // DGR, 2010/11/12
  1260. if (source.axis !== 'enu') {
  1261. point = adjust_axis(source, false, point);
  1262. }
  1263. // Transform source points to long/lat, if they aren't already.
  1264. if (source.projName === 'longlat') {
  1265. point = {
  1266. x: point.x * D2R,
  1267. y: point.y * D2R,
  1268. z: point.z || 0
  1269. };
  1270. } else {
  1271. if (source.to_meter) {
  1272. point = {
  1273. x: point.x * source.to_meter,
  1274. y: point.y * source.to_meter,
  1275. z: point.z || 0
  1276. };
  1277. }
  1278. point = source.inverse(point); // Convert Cartesian to longlat
  1279. if (!point) {
  1280. return;
  1281. }
  1282. }
  1283. // Adjust for the prime meridian if necessary
  1284. if (source.from_greenwich) {
  1285. point.x += source.from_greenwich;
  1286. }
  1287. // Convert datums if needed, and if possible.
  1288. point = datum_transform(source.datum, dest.datum, point);
  1289. // Adjust for the prime meridian if necessary
  1290. if (dest.from_greenwich) {
  1291. point = {
  1292. x: point.x - dest.from_greenwich,
  1293. y: point.y,
  1294. z: point.z || 0
  1295. };
  1296. }
  1297. if (dest.projName === 'longlat') {
  1298. // convert radians to decimal degrees
  1299. point = {
  1300. x: point.x * R2D,
  1301. y: point.y * R2D,
  1302. z: point.z || 0
  1303. };
  1304. } else { // else project
  1305. point = dest.forward(point);
  1306. if (dest.to_meter) {
  1307. point = {
  1308. x: point.x / dest.to_meter,
  1309. y: point.y / dest.to_meter,
  1310. z: point.z || 0
  1311. };
  1312. }
  1313. }
  1314. // DGR, 2010/11/12
  1315. if (dest.axis !== 'enu') {
  1316. return adjust_axis(dest, true, point);
  1317. }
  1318. return point;
  1319. }
  1320. var wgs84 = Projection('WGS84');
  1321. function transformer(from, to, coords) {
  1322. var transformedArray, out, keys;
  1323. if (Array.isArray(coords)) {
  1324. transformedArray = transform(from, to, coords) || {x: NaN, y: NaN};
  1325. if (coords.length > 2) {
  1326. if ((typeof from.name !== 'undefined' && from.name === 'geocent') || (typeof to.name !== 'undefined' && to.name === 'geocent')) {
  1327. if (typeof transformedArray.z === 'number') {
  1328. return [transformedArray.x, transformedArray.y, transformedArray.z].concat(coords.splice(3));
  1329. } else {
  1330. return [transformedArray.x, transformedArray.y, coords[2]].concat(coords.splice(3));
  1331. }
  1332. } else {
  1333. return [transformedArray.x, transformedArray.y].concat(coords.splice(2));
  1334. }
  1335. } else {
  1336. return [transformedArray.x, transformedArray.y];
  1337. }
  1338. } else {
  1339. out = transform(from, to, coords);
  1340. keys = Object.keys(coords);
  1341. if (keys.length === 2) {
  1342. return out;
  1343. }
  1344. keys.forEach(function (key) {
  1345. if ((typeof from.name !== 'undefined' && from.name === 'geocent') || (typeof to.name !== 'undefined' && to.name === 'geocent')) {
  1346. if (key === 'x' || key === 'y' || key === 'z') {
  1347. return;
  1348. }
  1349. } else {
  1350. if (key === 'x' || key === 'y') {
  1351. return;
  1352. }
  1353. }
  1354. out[key] = coords[key];
  1355. });
  1356. return out;
  1357. }
  1358. }
  1359. function checkProj(item) {
  1360. if (item instanceof Projection) {
  1361. return item;
  1362. }
  1363. if (item.oProj) {
  1364. return item.oProj;
  1365. }
  1366. return Projection(item);
  1367. }
  1368. function proj4$1(fromProj, toProj, coord) {
  1369. fromProj = checkProj(fromProj);
  1370. var single = false;
  1371. var obj;
  1372. if (typeof toProj === 'undefined') {
  1373. toProj = fromProj;
  1374. fromProj = wgs84;
  1375. single = true;
  1376. } else if (typeof toProj.x !== 'undefined' || Array.isArray(toProj)) {
  1377. coord = toProj;
  1378. toProj = fromProj;
  1379. fromProj = wgs84;
  1380. single = true;
  1381. }
  1382. toProj = checkProj(toProj);
  1383. if (coord) {
  1384. return transformer(fromProj, toProj, coord);
  1385. } else {
  1386. obj = {
  1387. forward: function (coords) {
  1388. return transformer(fromProj, toProj, coords);
  1389. },
  1390. inverse: function (coords) {
  1391. return transformer(toProj, fromProj, coords);
  1392. }
  1393. };
  1394. if (single) {
  1395. obj.oProj = toProj;
  1396. }
  1397. return obj;
  1398. }
  1399. }
  1400. /**
  1401. * UTM zones are grouped, and assigned to one of a group of 6
  1402. * sets.
  1403. *
  1404. * {int} @private
  1405. */
  1406. var NUM_100K_SETS = 6;
  1407. /**
  1408. * The column letters (for easting) of the lower left value, per
  1409. * set.
  1410. *
  1411. * {string} @private
  1412. */
  1413. var SET_ORIGIN_COLUMN_LETTERS = 'AJSAJS';
  1414. /**
  1415. * The row letters (for northing) of the lower left value, per
  1416. * set.
  1417. *
  1418. * {string} @private
  1419. */
  1420. var SET_ORIGIN_ROW_LETTERS = 'AFAFAF';
  1421. var A = 65; // A
  1422. var I = 73; // I
  1423. var O = 79; // O
  1424. var V = 86; // V
  1425. var Z = 90; // Z
  1426. var mgrs = {
  1427. forward: forward$1,
  1428. inverse: inverse$1,
  1429. toPoint: toPoint$1
  1430. };
  1431. /**
  1432. * Conversion of lat/lon to MGRS.
  1433. *
  1434. * @param {object} ll Object literal with lat and lon properties on a
  1435. * WGS84 ellipsoid.
  1436. * @param {int} accuracy Accuracy in digits (5 for 1 m, 4 for 10 m, 3 for
  1437. * 100 m, 2 for 1000 m or 1 for 10000 m). Optional, default is 5.
  1438. * @return {string} the MGRS string for the given location and accuracy.
  1439. */
  1440. function forward$1(ll, accuracy) {
  1441. accuracy = accuracy || 5; // default accuracy 1m
  1442. return encode(LLtoUTM({
  1443. lat: ll[1],
  1444. lon: ll[0]
  1445. }), accuracy);
  1446. }
  1447. /**
  1448. * Conversion of MGRS to lat/lon.
  1449. *
  1450. * @param {string} mgrs MGRS string.
  1451. * @return {array} An array with left (longitude), bottom (latitude), right
  1452. * (longitude) and top (latitude) values in WGS84, representing the
  1453. * bounding box for the provided MGRS reference.
  1454. */
  1455. function inverse$1(mgrs) {
  1456. var bbox = UTMtoLL(decode(mgrs.toUpperCase()));
  1457. if (bbox.lat && bbox.lon) {
  1458. return [bbox.lon, bbox.lat, bbox.lon, bbox.lat];
  1459. }
  1460. return [bbox.left, bbox.bottom, bbox.right, bbox.top];
  1461. }
  1462. function toPoint$1(mgrs) {
  1463. var bbox = UTMtoLL(decode(mgrs.toUpperCase()));
  1464. if (bbox.lat && bbox.lon) {
  1465. return [bbox.lon, bbox.lat];
  1466. }
  1467. return [(bbox.left + bbox.right) / 2, (bbox.top + bbox.bottom) / 2];
  1468. }
  1469. /**
  1470. * Conversion from degrees to radians.
  1471. *
  1472. * @private
  1473. * @param {number} deg the angle in degrees.
  1474. * @return {number} the angle in radians.
  1475. */
  1476. function degToRad(deg) {
  1477. return (deg * (Math.PI / 180.0));
  1478. }
  1479. /**
  1480. * Conversion from radians to degrees.
  1481. *
  1482. * @private
  1483. * @param {number} rad the angle in radians.
  1484. * @return {number} the angle in degrees.
  1485. */
  1486. function radToDeg(rad) {
  1487. return (180.0 * (rad / Math.PI));
  1488. }
  1489. /**
  1490. * Converts a set of Longitude and Latitude co-ordinates to UTM
  1491. * using the WGS84 ellipsoid.
  1492. *
  1493. * @private
  1494. * @param {object} ll Object literal with lat and lon properties
  1495. * representing the WGS84 coordinate to be converted.
  1496. * @return {object} Object literal containing the UTM value with easting,
  1497. * northing, zoneNumber and zoneLetter properties, and an optional
  1498. * accuracy property in digits. Returns null if the conversion failed.
  1499. */
  1500. function LLtoUTM(ll) {
  1501. var Lat = ll.lat;
  1502. var Long = ll.lon;
  1503. var a = 6378137.0; //ellip.radius;
  1504. var eccSquared = 0.00669438; //ellip.eccsq;
  1505. var k0 = 0.9996;
  1506. var LongOrigin;
  1507. var eccPrimeSquared;
  1508. var N, T, C, A, M;
  1509. var LatRad = degToRad(Lat);
  1510. var LongRad = degToRad(Long);
  1511. var LongOriginRad;
  1512. var ZoneNumber;
  1513. // (int)
  1514. ZoneNumber = Math.floor((Long + 180) / 6) + 1;
  1515. //Make sure the longitude 180.00 is in Zone 60
  1516. if (Long === 180) {
  1517. ZoneNumber = 60;
  1518. }
  1519. // Special zone for Norway
  1520. if (Lat >= 56.0 && Lat < 64.0 && Long >= 3.0 && Long < 12.0) {
  1521. ZoneNumber = 32;
  1522. }
  1523. // Special zones for Svalbard
  1524. if (Lat >= 72.0 && Lat < 84.0) {
  1525. if (Long >= 0.0 && Long < 9.0) {
  1526. ZoneNumber = 31;
  1527. }
  1528. else if (Long >= 9.0 && Long < 21.0) {
  1529. ZoneNumber = 33;
  1530. }
  1531. else if (Long >= 21.0 && Long < 33.0) {
  1532. ZoneNumber = 35;
  1533. }
  1534. else if (Long >= 33.0 && Long < 42.0) {
  1535. ZoneNumber = 37;
  1536. }
  1537. }
  1538. LongOrigin = (ZoneNumber - 1) * 6 - 180 + 3; //+3 puts origin
  1539. // in middle of
  1540. // zone
  1541. LongOriginRad = degToRad(LongOrigin);
  1542. eccPrimeSquared = (eccSquared) / (1 - eccSquared);
  1543. N = a / Math.sqrt(1 - eccSquared * Math.sin(LatRad) * Math.sin(LatRad));
  1544. T = Math.tan(LatRad) * Math.tan(LatRad);
  1545. C = eccPrimeSquared * Math.cos(LatRad) * Math.cos(LatRad);
  1546. A = Math.cos(LatRad) * (LongRad - LongOriginRad);
  1547. M = a * ((1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256) * LatRad - (3 * eccSquared / 8 + 3 * eccSquared * eccSquared / 32 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(2 * LatRad) + (15 * eccSquared * eccSquared / 256 + 45 * eccSquared * eccSquared * eccSquared / 1024) * Math.sin(4 * LatRad) - (35 * eccSquared * eccSquared * eccSquared / 3072) * Math.sin(6 * LatRad));
  1548. var UTMEasting = (k0 * N * (A + (1 - T + C) * A * A * A / 6.0 + (5 - 18 * T + T * T + 72 * C - 58 * eccPrimeSquared) * A * A * A * A * A / 120.0) + 500000.0);
  1549. var UTMNorthing = (k0 * (M + N * Math.tan(LatRad) * (A * A / 2 + (5 - T + 9 * C + 4 * C * C) * A * A * A * A / 24.0 + (61 - 58 * T + T * T + 600 * C - 330 * eccPrimeSquared) * A * A * A * A * A * A / 720.0)));
  1550. if (Lat < 0.0) {
  1551. UTMNorthing += 10000000.0; //10000000 meter offset for
  1552. // southern hemisphere
  1553. }
  1554. return {
  1555. northing: Math.round(UTMNorthing),
  1556. easting: Math.round(UTMEasting),
  1557. zoneNumber: ZoneNumber,
  1558. zoneLetter: getLetterDesignator(Lat)
  1559. };
  1560. }
  1561. /**
  1562. * Converts UTM coords to lat/long, using the WGS84 ellipsoid. This is a convenience
  1563. * class where the Zone can be specified as a single string eg."60N" which
  1564. * is then broken down into the ZoneNumber and ZoneLetter.
  1565. *
  1566. * @private
  1567. * @param {object} utm An object literal with northing, easting, zoneNumber
  1568. * and zoneLetter properties. If an optional accuracy property is
  1569. * provided (in meters), a bounding box will be returned instead of
  1570. * latitude and longitude.
  1571. * @return {object} An object literal containing either lat and lon values
  1572. * (if no accuracy was provided), or top, right, bottom and left values
  1573. * for the bounding box calculated according to the provided accuracy.
  1574. * Returns null if the conversion failed.
  1575. */
  1576. function UTMtoLL(utm) {
  1577. var UTMNorthing = utm.northing;
  1578. var UTMEasting = utm.easting;
  1579. var zoneLetter = utm.zoneLetter;
  1580. var zoneNumber = utm.zoneNumber;
  1581. // check the ZoneNummber is valid
  1582. if (zoneNumber < 0 || zoneNumber > 60) {
  1583. return null;
  1584. }
  1585. var k0 = 0.9996;
  1586. var a = 6378137.0; //ellip.radius;
  1587. var eccSquared = 0.00669438; //ellip.eccsq;
  1588. var eccPrimeSquared;
  1589. var e1 = (1 - Math.sqrt(1 - eccSquared)) / (1 + Math.sqrt(1 - eccSquared));
  1590. var N1, T1, C1, R1, D, M;
  1591. var LongOrigin;
  1592. var mu, phi1Rad;
  1593. // remove 500,000 meter offset for longitude
  1594. var x = UTMEasting - 500000.0;
  1595. var y = UTMNorthing;
  1596. // We must know somehow if we are in the Northern or Southern
  1597. // hemisphere, this is the only time we use the letter So even
  1598. // if the Zone letter isn't exactly correct it should indicate
  1599. // the hemisphere correctly
  1600. if (zoneLetter < 'N') {
  1601. y -= 10000000.0; // remove 10,000,000 meter offset used
  1602. // for southern hemisphere
  1603. }
  1604. // There are 60 zones with zone 1 being at West -180 to -174
  1605. LongOrigin = (zoneNumber - 1) * 6 - 180 + 3; // +3 puts origin
  1606. // in middle of
  1607. // zone
  1608. eccPrimeSquared = (eccSquared) / (1 - eccSquared);
  1609. M = y / k0;
  1610. mu = M / (a * (1 - eccSquared / 4 - 3 * eccSquared * eccSquared / 64 - 5 * eccSquared * eccSquared * eccSquared / 256));
  1611. phi1Rad = mu + (3 * e1 / 2 - 27 * e1 * e1 * e1 / 32) * Math.sin(2 * mu) + (21 * e1 * e1 / 16 - 55 * e1 * e1 * e1 * e1 / 32) * Math.sin(4 * mu) + (151 * e1 * e1 * e1 / 96) * Math.sin(6 * mu);
  1612. // double phi1 = ProjMath.radToDeg(phi1Rad);
  1613. N1 = a / Math.sqrt(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad));
  1614. T1 = Math.tan(phi1Rad) * Math.tan(phi1Rad);
  1615. C1 = eccPrimeSquared * Math.cos(phi1Rad) * Math.cos(phi1Rad);
  1616. R1 = a * (1 - eccSquared) / Math.pow(1 - eccSquared * Math.sin(phi1Rad) * Math.sin(phi1Rad), 1.5);
  1617. D = x / (N1 * k0);
  1618. var lat = phi1Rad - (N1 * Math.tan(phi1Rad) / R1) * (D * D / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1 * C1 - 9 * eccPrimeSquared) * D * D * D * D / 24 + (61 + 90 * T1 + 298 * C1 + 45 * T1 * T1 - 252 * eccPrimeSquared - 3 * C1 * C1) * D * D * D * D * D * D / 720);
  1619. lat = radToDeg(lat);
  1620. var lon = (D - (1 + 2 * T1 + C1) * D * D * D / 6 + (5 - 2 * C1 + 28 * T1 - 3 * C1 * C1 + 8 * eccPrimeSquared + 24 * T1 * T1) * D * D * D * D * D / 120) / Math.cos(phi1Rad);
  1621. lon = LongOrigin + radToDeg(lon);
  1622. var result;
  1623. if (utm.accuracy) {
  1624. var topRight = UTMtoLL({
  1625. northing: utm.northing + utm.accuracy,
  1626. easting: utm.easting + utm.accuracy,
  1627. zoneLetter: utm.zoneLetter,
  1628. zoneNumber: utm.zoneNumber
  1629. });
  1630. result = {
  1631. top: topRight.lat,
  1632. right: topRight.lon,
  1633. bottom: lat,
  1634. left: lon
  1635. };
  1636. }
  1637. else {
  1638. result = {
  1639. lat: lat,
  1640. lon: lon
  1641. };
  1642. }
  1643. return result;
  1644. }
  1645. /**
  1646. * Calculates the MGRS letter designator for the given latitude.
  1647. *
  1648. * @private
  1649. * @param {number} lat The latitude in WGS84 to get the letter designator
  1650. * for.
  1651. * @return {char} The letter designator.
  1652. */
  1653. function getLetterDesignator(lat) {
  1654. //This is here as an error flag to show that the Latitude is
  1655. //outside MGRS limits
  1656. var LetterDesignator = 'Z';
  1657. if ((84 >= lat) && (lat >= 72)) {
  1658. LetterDesignator = 'X';
  1659. }
  1660. else if ((72 > lat) && (lat >= 64)) {
  1661. LetterDesignator = 'W';
  1662. }
  1663. else if ((64 > lat) && (lat >= 56)) {
  1664. LetterDesignator = 'V';
  1665. }
  1666. else if ((56 > lat) && (lat >= 48)) {
  1667. LetterDesignator = 'U';
  1668. }
  1669. else if ((48 > lat) && (lat >= 40)) {
  1670. LetterDesignator = 'T';
  1671. }
  1672. else if ((40 > lat) && (lat >= 32)) {
  1673. LetterDesignator = 'S';
  1674. }
  1675. else if ((32 > lat) && (lat >= 24)) {
  1676. LetterDesignator = 'R';
  1677. }
  1678. else if ((24 > lat) && (lat >= 16)) {
  1679. LetterDesignator = 'Q';
  1680. }
  1681. else if ((16 > lat) && (lat >= 8)) {
  1682. LetterDesignator = 'P';
  1683. }
  1684. else if ((8 > lat) && (lat >= 0)) {
  1685. LetterDesignator = 'N';
  1686. }
  1687. else if ((0 > lat) && (lat >= -8)) {
  1688. LetterDesignator = 'M';
  1689. }
  1690. else if ((-8 > lat) && (lat >= -16)) {
  1691. LetterDesignator = 'L';
  1692. }
  1693. else if ((-16 > lat) && (lat >= -24)) {
  1694. LetterDesignator = 'K';
  1695. }
  1696. else if ((-24 > lat) && (lat >= -32)) {
  1697. LetterDesignator = 'J';
  1698. }
  1699. else if ((-32 > lat) && (lat >= -40)) {
  1700. LetterDesignator = 'H';
  1701. }
  1702. else if ((-40 > lat) && (lat >= -48)) {
  1703. LetterDesignator = 'G';
  1704. }
  1705. else if ((-48 > lat) && (lat >= -56)) {
  1706. LetterDesignator = 'F';
  1707. }
  1708. else if ((-56 > lat) && (lat >= -64)) {
  1709. LetterDesignator = 'E';
  1710. }
  1711. else if ((-64 > lat) && (lat >= -72)) {
  1712. LetterDesignator = 'D';
  1713. }
  1714. else if ((-72 > lat) && (lat >= -80)) {
  1715. LetterDesignator = 'C';
  1716. }
  1717. return LetterDesignator;
  1718. }
  1719. /**
  1720. * Encodes a UTM location as MGRS string.
  1721. *
  1722. * @private
  1723. * @param {object} utm An object literal with easting, northing,
  1724. * zoneLetter, zoneNumber
  1725. * @param {number} accuracy Accuracy in digits (1-5).
  1726. * @return {string} MGRS string for the given UTM location.
  1727. */
  1728. function encode(utm, accuracy) {
  1729. // prepend with leading zeroes
  1730. var seasting = "00000" + utm.easting,
  1731. snorthing = "00000" + utm.northing;
  1732. return utm.zoneNumber + utm.zoneLetter + get100kID(utm.easting, utm.northing, utm.zoneNumber) + seasting.substr(seasting.length - 5, accuracy) + snorthing.substr(snorthing.length - 5, accuracy);
  1733. }
  1734. /**
  1735. * Get the two letter 100k designator for a given UTM easting,
  1736. * northing and zone number value.
  1737. *
  1738. * @private
  1739. * @param {number} easting
  1740. * @param {number} northing
  1741. * @param {number} zoneNumber
  1742. * @return the two letter 100k designator for the given UTM location.
  1743. */
  1744. function get100kID(easting, northing, zoneNumber) {
  1745. var setParm = get100kSetForZone(zoneNumber);
  1746. var setColumn = Math.floor(easting / 100000);
  1747. var setRow = Math.floor(northing / 100000) % 20;
  1748. return getLetter100kID(setColumn, setRow, setParm);
  1749. }
  1750. /**
  1751. * Given a UTM zone number, figure out the MGRS 100K set it is in.
  1752. *
  1753. * @private
  1754. * @param {number} i An UTM zone number.
  1755. * @return {number} the 100k set the UTM zone is in.
  1756. */
  1757. function get100kSetForZone(i) {
  1758. var setParm = i % NUM_100K_SETS;
  1759. if (setParm === 0) {
  1760. setParm = NUM_100K_SETS;
  1761. }
  1762. return setParm;
  1763. }
  1764. /**
  1765. * Get the two-letter MGRS 100k designator given information
  1766. * translated from the UTM northing, easting and zone number.
  1767. *
  1768. * @private
  1769. * @param {number} column the column index as it relates to the MGRS
  1770. * 100k set spreadsheet, created from the UTM easting.
  1771. * Values are 1-8.
  1772. * @param {number} row the row index as it relates to the MGRS 100k set
  1773. * spreadsheet, created from the UTM northing value. Values
  1774. * are from 0-19.
  1775. * @param {number} parm the set block, as it relates to the MGRS 100k set
  1776. * spreadsheet, created from the UTM zone. Values are from
  1777. * 1-60.
  1778. * @return two letter MGRS 100k code.
  1779. */
  1780. function getLetter100kID(column, row, parm) {
  1781. // colOrigin and rowOrigin are the letters at the origin of the set
  1782. var index = parm - 1;
  1783. var colOrigin = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(index);
  1784. var rowOrigin = SET_ORIGIN_ROW_LETTERS.charCodeAt(index);
  1785. // colInt and rowInt are the letters to build to return
  1786. var colInt = colOrigin + column - 1;
  1787. var rowInt = rowOrigin + row;
  1788. var rollover = false;
  1789. if (colInt > Z) {
  1790. colInt = colInt - Z + A - 1;
  1791. rollover = true;
  1792. }
  1793. if (colInt === I || (colOrigin < I && colInt > I) || ((colInt > I || colOrigin < I) && rollover)) {
  1794. colInt++;
  1795. }
  1796. if (colInt === O || (colOrigin < O && colInt > O) || ((colInt > O || colOrigin < O) && rollover)) {
  1797. colInt++;
  1798. if (colInt === I) {
  1799. colInt++;
  1800. }
  1801. }
  1802. if (colInt > Z) {
  1803. colInt = colInt - Z + A - 1;
  1804. }
  1805. if (rowInt > V) {
  1806. rowInt = rowInt - V + A - 1;
  1807. rollover = true;
  1808. }
  1809. else {
  1810. rollover = false;
  1811. }
  1812. if (((rowInt === I) || ((rowOrigin < I) && (rowInt > I))) || (((rowInt > I) || (rowOrigin < I)) && rollover)) {
  1813. rowInt++;
  1814. }
  1815. if (((rowInt === O) || ((rowOrigin < O) && (rowInt > O))) || (((rowInt > O) || (rowOrigin < O)) && rollover)) {
  1816. rowInt++;
  1817. if (rowInt === I) {
  1818. rowInt++;
  1819. }
  1820. }
  1821. if (rowInt > V) {
  1822. rowInt = rowInt - V + A - 1;
  1823. }
  1824. var twoLetter = String.fromCharCode(colInt) + String.fromCharCode(rowInt);
  1825. return twoLetter;
  1826. }
  1827. /**
  1828. * Decode the UTM parameters from a MGRS string.
  1829. *
  1830. * @private
  1831. * @param {string} mgrsString an UPPERCASE coordinate string is expected.
  1832. * @return {object} An object literal with easting, northing, zoneLetter,
  1833. * zoneNumber and accuracy (in meters) properties.
  1834. */
  1835. function decode(mgrsString) {
  1836. if (mgrsString && mgrsString.length === 0) {
  1837. throw ("MGRSPoint coverting from nothing");
  1838. }
  1839. var length = mgrsString.length;
  1840. var hunK = null;
  1841. var sb = "";
  1842. var testChar;
  1843. var i = 0;
  1844. // get Zone number
  1845. while (!(/[A-Z]/).test(testChar = mgrsString.charAt(i))) {
  1846. if (i >= 2) {
  1847. throw ("MGRSPoint bad conversion from: " + mgrsString);
  1848. }
  1849. sb += testChar;
  1850. i++;
  1851. }
  1852. var zoneNumber = parseInt(sb, 10);
  1853. if (i === 0 || i + 3 > length) {
  1854. // A good MGRS string has to be 4-5 digits long,
  1855. // ##AAA/#AAA at least.
  1856. throw ("MGRSPoint bad conversion from: " + mgrsString);
  1857. }
  1858. var zoneLetter = mgrsString.charAt(i++);
  1859. // Should we check the zone letter here? Why not.
  1860. if (zoneLetter <= 'A' || zoneLetter === 'B' || zoneLetter === 'Y' || zoneLetter >= 'Z' || zoneLetter === 'I' || zoneLetter === 'O') {
  1861. throw ("MGRSPoint zone letter " + zoneLetter + " not handled: " + mgrsString);
  1862. }
  1863. hunK = mgrsString.substring(i, i += 2);
  1864. var set = get100kSetForZone(zoneNumber);
  1865. var east100k = getEastingFromChar(hunK.charAt(0), set);
  1866. var north100k = getNorthingFromChar(hunK.charAt(1), set);
  1867. // We have a bug where the northing may be 2000000 too low.
  1868. // How
  1869. // do we know when to roll over?
  1870. while (north100k < getMinNorthing(zoneLetter)) {
  1871. north100k += 2000000;
  1872. }
  1873. // calculate the char index for easting/northing separator
  1874. var remainder = length - i;
  1875. if (remainder % 2 !== 0) {
  1876. throw ("MGRSPoint has to have an even number \nof digits after the zone letter and two 100km letters - front \nhalf for easting meters, second half for \nnorthing meters" + mgrsString);
  1877. }
  1878. var sep = remainder / 2;
  1879. var sepEasting = 0.0;
  1880. var sepNorthing = 0.0;
  1881. var accuracyBonus, sepEastingString, sepNorthingString, easting, northing;
  1882. if (sep > 0) {
  1883. accuracyBonus = 100000.0 / Math.pow(10, sep);
  1884. sepEastingString = mgrsString.substring(i, i + sep);
  1885. sepEasting = parseFloat(sepEastingString) * accuracyBonus;
  1886. sepNorthingString = mgrsString.substring(i + sep);
  1887. sepNorthing = parseFloat(sepNorthingString) * accuracyBonus;
  1888. }
  1889. easting = sepEasting + east100k;
  1890. northing = sepNorthing + north100k;
  1891. return {
  1892. easting: easting,
  1893. northing: northing,
  1894. zoneLetter: zoneLetter,
  1895. zoneNumber: zoneNumber,
  1896. accuracy: accuracyBonus
  1897. };
  1898. }
  1899. /**
  1900. * Given the first letter from a two-letter MGRS 100k zone, and given the
  1901. * MGRS table set for the zone number, figure out the easting value that
  1902. * should be added to the other, secondary easting value.
  1903. *
  1904. * @private
  1905. * @param {char} e The first letter from a two-letter MGRS 100´k zone.
  1906. * @param {number} set The MGRS table set for the zone number.
  1907. * @return {number} The easting value for the given letter and set.
  1908. */
  1909. function getEastingFromChar(e, set) {
  1910. // colOrigin is the letter at the origin of the set for the
  1911. // column
  1912. var curCol = SET_ORIGIN_COLUMN_LETTERS.charCodeAt(set - 1);
  1913. var eastingValue = 100000.0;
  1914. var rewindMarker = false;
  1915. while (curCol !== e.charCodeAt(0)) {
  1916. curCol++;
  1917. if (curCol === I) {
  1918. curCol++;
  1919. }
  1920. if (curCol === O) {
  1921. curCol++;
  1922. }
  1923. if (curCol > Z) {
  1924. if (rewindMarker) {
  1925. throw ("Bad character: " + e);
  1926. }
  1927. curCol = A;
  1928. rewindMarker = true;
  1929. }
  1930. eastingValue += 100000.0;
  1931. }
  1932. return eastingValue;
  1933. }
  1934. /**
  1935. * Given the second letter from a two-letter MGRS 100k zone, and given the
  1936. * MGRS table set for the zone number, figure out the northing value that
  1937. * should be added to the other, secondary northing value. You have to
  1938. * remember that Northings are determined from the equator, and the vertical
  1939. * cycle of letters mean a 2000000 additional northing meters. This happens
  1940. * approx. every 18 degrees of latitude. This method does *NOT* count any
  1941. * additional northings. You have to figure out how many 2000000 meters need
  1942. * to be added for the zone letter of the MGRS coordinate.
  1943. *
  1944. * @private
  1945. * @param {char} n Second letter of the MGRS 100k zone
  1946. * @param {number} set The MGRS table set number, which is dependent on the
  1947. * UTM zone number.
  1948. * @return {number} The northing value for the given letter and set.
  1949. */
  1950. function getNorthingFromChar(n, set) {
  1951. if (n > 'V') {
  1952. throw ("MGRSPoint given invalid Northing " + n);
  1953. }
  1954. // rowOrigin is the letter at the origin of the set for the
  1955. // column
  1956. var curRow = SET_ORIGIN_ROW_LETTERS.charCodeAt(set - 1);
  1957. var northingValue = 0.0;
  1958. var rewindMarker = false;
  1959. while (curRow !== n.charCodeAt(0)) {
  1960. curRow++;
  1961. if (curRow === I) {
  1962. curRow++;
  1963. }
  1964. if (curRow === O) {
  1965. curRow++;
  1966. }
  1967. // fixing a bug making whole application hang in this loop
  1968. // when 'n' is a wrong character
  1969. if (curRow > V) {
  1970. if (rewindMarker) { // making sure that this loop ends
  1971. throw ("Bad character: " + n);
  1972. }
  1973. curRow = A;
  1974. rewindMarker = true;
  1975. }
  1976. northingValue += 100000.0;
  1977. }
  1978. return northingValue;
  1979. }
  1980. /**
  1981. * The function getMinNorthing returns the minimum northing value of a MGRS
  1982. * zone.
  1983. *
  1984. * Ported from Geotrans' c Lattitude_Band_Value structure table.
  1985. *
  1986. * @private
  1987. * @param {char} zoneLetter The MGRS zone to get the min northing for.
  1988. * @return {number}
  1989. */
  1990. function getMinNorthing(zoneLetter) {
  1991. var northing;
  1992. switch (zoneLetter) {
  1993. case 'C':
  1994. northing = 1100000.0;
  1995. break;
  1996. case 'D':
  1997. northing = 2000000.0;
  1998. break;
  1999. case 'E':
  2000. northing = 2800000.0;
  2001. break;
  2002. case 'F':
  2003. northing = 3700000.0;
  2004. break;
  2005. case 'G':
  2006. northing = 4600000.0;
  2007. break;
  2008. case 'H':
  2009. northing = 5500000.0;
  2010. break;
  2011. case 'J':
  2012. northing = 6400000.0;
  2013. break;
  2014. case 'K':
  2015. northing = 7300000.0;
  2016. break;
  2017. case 'L':
  2018. northing = 8200000.0;
  2019. break;
  2020. case 'M':
  2021. northing = 9100000.0;
  2022. break;
  2023. case 'N':
  2024. northing = 0.0;
  2025. break;
  2026. case 'P':
  2027. northing = 800000.0;
  2028. break;
  2029. case 'Q':
  2030. northing = 1700000.0;
  2031. break;
  2032. case 'R':
  2033. northing = 2600000.0;
  2034. break;
  2035. case 'S':
  2036. northing = 3500000.0;
  2037. break;
  2038. case 'T':
  2039. northing = 4400000.0;
  2040. break;
  2041. case 'U':
  2042. northing = 5300000.0;
  2043. break;
  2044. case 'V':
  2045. northing = 6200000.0;
  2046. break;
  2047. case 'W':
  2048. northing = 7000000.0;
  2049. break;
  2050. case 'X':
  2051. northing = 7900000.0;
  2052. break;
  2053. default:
  2054. northing = -1.0;
  2055. }
  2056. if (northing >= 0.0) {
  2057. return northing;
  2058. }
  2059. else {
  2060. throw ("Invalid zone letter: " + zoneLetter);
  2061. }
  2062. }
  2063. function Point(x, y, z) {
  2064. if (!(this instanceof Point)) {
  2065. return new Point(x, y, z);
  2066. }
  2067. if (Array.isArray(x)) {
  2068. this.x = x[0];
  2069. this.y = x[1];
  2070. this.z = x[2] || 0.0;
  2071. } else if(typeof x === 'object') {
  2072. this.x = x.x;
  2073. this.y = x.y;
  2074. this.z = x.z || 0.0;
  2075. } else if (typeof x === 'string' && typeof y === 'undefined') {
  2076. var coords = x.split(',');
  2077. this.x = parseFloat(coords[0], 10);
  2078. this.y = parseFloat(coords[1], 10);
  2079. this.z = parseFloat(coords[2], 10) || 0.0;
  2080. } else {
  2081. this.x = x;
  2082. this.y = y;
  2083. this.z = z || 0.0;
  2084. }
  2085. console.warn('proj4.Point will be removed in version 3, use proj4.toPoint');
  2086. }
  2087. Point.fromMGRS = function(mgrsStr) {
  2088. return new Point(toPoint$1(mgrsStr));
  2089. };
  2090. Point.prototype.toMGRS = function(accuracy) {
  2091. return forward$1([this.x, this.y], accuracy);
  2092. };
  2093. var C00 = 1;
  2094. var C02 = 0.25;
  2095. var C04 = 0.046875;
  2096. var C06 = 0.01953125;
  2097. var C08 = 0.01068115234375;
  2098. var C22 = 0.75;
  2099. var C44 = 0.46875;
  2100. var C46 = 0.01302083333333333333;
  2101. var C48 = 0.00712076822916666666;
  2102. var C66 = 0.36458333333333333333;
  2103. var C68 = 0.00569661458333333333;
  2104. var C88 = 0.3076171875;
  2105. var pj_enfn = function(es) {
  2106. var en = [];
  2107. en[0] = C00 - es * (C02 + es * (C04 + es * (C06 + es * C08)));
  2108. en[1] = es * (C22 - es * (C04 + es * (C06 + es * C08)));
  2109. var t = es * es;
  2110. en[2] = t * (C44 - es * (C46 + es * C48));
  2111. t *= es;
  2112. en[3] = t * (C66 - es * C68);
  2113. en[4] = t * es * C88;
  2114. return en;
  2115. };
  2116. var pj_mlfn = function(phi, sphi, cphi, en) {
  2117. cphi *= sphi;
  2118. sphi *= sphi;
  2119. return (en[0] * phi - cphi * (en[1] + sphi * (en[2] + sphi * (en[3] + sphi * en[4]))));
  2120. };
  2121. var MAX_ITER = 20;
  2122. var pj_inv_mlfn = function(arg, es, en) {
  2123. var k = 1 / (1 - es);
  2124. var phi = arg;
  2125. for (var i = MAX_ITER; i; --i) { /* rarely goes over 2 iterations */
  2126. var s = Math.sin(phi);
  2127. var t = 1 - es * s * s;
  2128. //t = this.pj_mlfn(phi, s, Math.cos(phi), en) - arg;
  2129. //phi -= t * (t * Math.sqrt(t)) * k;
  2130. t = (pj_mlfn(phi, s, Math.cos(phi), en) - arg) * (t * Math.sqrt(t)) * k;
  2131. phi -= t;
  2132. if (Math.abs(t) < EPSLN) {
  2133. return phi;
  2134. }
  2135. }
  2136. //..reportError("cass:pj_inv_mlfn: Convergence error");
  2137. return phi;
  2138. };
  2139. // Heavily based on this tmerc projection implementation
  2140. // https://github.com/mbloch/mapshaper-proj/blob/master/src/projections/tmerc.js
  2141. function init$2() {
  2142. this.x0 = this.x0 !== undefined ? this.x0 : 0;
  2143. this.y0 = this.y0 !== undefined ? this.y0 : 0;
  2144. this.long0 = this.long0 !== undefined ? this.long0 : 0;
  2145. this.lat0 = this.lat0 !== undefined ? this.lat0 : 0;
  2146. if (this.es) {
  2147. this.en = pj_enfn(this.es);
  2148. this.ml0 = pj_mlfn(this.lat0, Math.sin(this.lat0), Math.cos(this.lat0), this.en);
  2149. }
  2150. }
  2151. /**
  2152. Transverse Mercator Forward - long/lat to x/y
  2153. long/lat in radians
  2154. */
  2155. function forward$2(p) {
  2156. var lon = p.x;
  2157. var lat = p.y;
  2158. var delta_lon = adjust_lon(lon - this.long0);
  2159. var con;
  2160. var x, y;
  2161. var sin_phi = Math.sin(lat);
  2162. var cos_phi = Math.cos(lat);
  2163. if (!this.es) {
  2164. var b = cos_phi * Math.sin(delta_lon);
  2165. if ((Math.abs(Math.abs(b) - 1)) < EPSLN) {
  2166. return (93);
  2167. }
  2168. else {
  2169. x = 0.5 * this.a * this.k0 * Math.log((1 + b) / (1 - b)) + this.x0;
  2170. y = cos_phi * Math.cos(delta_lon) / Math.sqrt(1 - Math.pow(b, 2));
  2171. b = Math.abs(y);
  2172. if (b >= 1) {
  2173. if ((b - 1) > EPSLN) {
  2174. return (93);
  2175. }
  2176. else {
  2177. y = 0;
  2178. }
  2179. }
  2180. else {
  2181. y = Math.acos(y);
  2182. }
  2183. if (lat < 0) {
  2184. y = -y;
  2185. }
  2186. y = this.a * this.k0 * (y - this.lat0) + this.y0;
  2187. }
  2188. }
  2189. else {
  2190. var al = cos_phi * delta_lon;
  2191. var als = Math.pow(al, 2);
  2192. var c = this.ep2 * Math.pow(cos_phi, 2);
  2193. var cs = Math.pow(c, 2);
  2194. var tq = Math.abs(cos_phi) > EPSLN ? Math.tan(lat) : 0;
  2195. var t = Math.pow(tq, 2);
  2196. var ts = Math.pow(t, 2);
  2197. con = 1 - this.es * Math.pow(sin_phi, 2);
  2198. al = al / Math.sqrt(con);
  2199. var ml = pj_mlfn(lat, sin_phi, cos_phi, this.en);
  2200. x = this.a * (this.k0 * al * (1 +
  2201. als / 6 * (1 - t + c +
  2202. als / 20 * (5 - 18 * t + ts + 14 * c - 58 * t * c +
  2203. als / 42 * (61 + 179 * ts - ts * t - 479 * t))))) +
  2204. this.x0;
  2205. y = this.a * (this.k0 * (ml - this.ml0 +
  2206. sin_phi * delta_lon * al / 2 * (1 +
  2207. als / 12 * (5 - t + 9 * c + 4 * cs +
  2208. als / 30 * (61 + ts - 58 * t + 270 * c - 330 * t * c +
  2209. als / 56 * (1385 + 543 * ts - ts * t - 3111 * t)))))) +
  2210. this.y0;
  2211. }
  2212. p.x = x;
  2213. p.y = y;
  2214. return p;
  2215. }
  2216. /**
  2217. Transverse Mercator Inverse - x/y to long/lat
  2218. */
  2219. function inverse$2(p) {
  2220. var con, phi;
  2221. var lat, lon;
  2222. var x = (p.x - this.x0) * (1 / this.a);
  2223. var y = (p.y - this.y0) * (1 / this.a);
  2224. if (!this.es) {
  2225. var f = Math.exp(x / this.k0);
  2226. var g = 0.5 * (f - 1 / f);
  2227. var temp = this.lat0 + y / this.k0;
  2228. var h = Math.cos(temp);
  2229. con = Math.sqrt((1 - Math.pow(h, 2)) / (1 + Math.pow(g, 2)));
  2230. lat = Math.asin(con);
  2231. if (y < 0) {
  2232. lat = -lat;
  2233. }
  2234. if ((g === 0) && (h === 0)) {
  2235. lon = 0;
  2236. }
  2237. else {
  2238. lon = adjust_lon(Math.atan2(g, h) + this.long0);
  2239. }
  2240. }
  2241. else { // ellipsoidal form
  2242. con = this.ml0 + y / this.k0;
  2243. phi = pj_inv_mlfn(con, this.es, this.en);
  2244. if (Math.abs(phi) < HALF_PI) {
  2245. var sin_phi = Math.sin(phi);
  2246. var cos_phi = Math.cos(phi);
  2247. var tan_phi = Math.abs(cos_phi) > EPSLN ? Math.tan(phi) : 0;
  2248. var c = this.ep2 * Math.pow(cos_phi, 2);
  2249. var cs = Math.pow(c, 2);
  2250. var t = Math.pow(tan_phi, 2);
  2251. var ts = Math.pow(t, 2);
  2252. con = 1 - this.es * Math.pow(sin_phi, 2);
  2253. var d = x * Math.sqrt(con) / this.k0;
  2254. var ds = Math.pow(d, 2);
  2255. con = con * tan_phi;
  2256. lat = phi - (con * ds / (1 - this.es)) * 0.5 * (1 -
  2257. ds / 12 * (5 + 3 * t - 9 * c * t + c - 4 * cs -
  2258. ds / 30 * (61 + 90 * t - 252 * c * t + 45 * ts + 46 * c -
  2259. ds / 56 * (1385 + 3633 * t + 4095 * ts + 1574 * ts * t))));
  2260. lon = adjust_lon(this.long0 + (d * (1 -
  2261. ds / 6 * (1 + 2 * t + c -
  2262. ds / 20 * (5 + 28 * t + 24 * ts + 8 * c * t + 6 * c -
  2263. ds / 42 * (61 + 662 * t + 1320 * ts + 720 * ts * t)))) / cos_phi));
  2264. }
  2265. else {
  2266. lat = HALF_PI * sign(y);
  2267. lon = 0;
  2268. }
  2269. }
  2270. p.x = lon;
  2271. p.y = lat;
  2272. return p;
  2273. }
  2274. var names$3 = ["Transverse_Mercator", "Transverse Mercator", "tmerc"];
  2275. var tmerc = {
  2276. init: init$2,
  2277. forward: forward$2,
  2278. inverse: inverse$2,
  2279. names: names$3
  2280. };
  2281. var sinh = function(x) {
  2282. var r = Math.exp(x);
  2283. r = (r - 1 / r) / 2;
  2284. return r;
  2285. };
  2286. var hypot = function(x, y) {
  2287. x = Math.abs(x);
  2288. y = Math.abs(y);
  2289. var a = Math.max(x, y);
  2290. var b = Math.min(x, y) / (a ? a : 1);
  2291. return a * Math.sqrt(1 + Math.pow(b, 2));
  2292. };
  2293. var log1py = function(x) {
  2294. var y = 1 + x;
  2295. var z = y - 1;
  2296. return z === 0 ? x : x * Math.log(y) / z;
  2297. };
  2298. var asinhy = function(x) {
  2299. var y = Math.abs(x);
  2300. y = log1py(y * (1 + y / (hypot(1, y) + 1)));
  2301. return x < 0 ? -y : y;
  2302. };
  2303. var gatg = function(pp, B) {
  2304. var cos_2B = 2 * Math.cos(2 * B);
  2305. var i = pp.length - 1;
  2306. var h1 = pp[i];
  2307. var h2 = 0;
  2308. var h;
  2309. while (--i >= 0) {
  2310. h = -h2 + cos_2B * h1 + pp[i];
  2311. h2 = h1;
  2312. h1 = h;
  2313. }
  2314. return (B + h * Math.sin(2 * B));
  2315. };
  2316. var clens = function(pp, arg_r) {
  2317. var r = 2 * Math.cos(arg_r);
  2318. var i = pp.length - 1;
  2319. var hr1 = pp[i];
  2320. var hr2 = 0;
  2321. var hr;
  2322. while (--i >= 0) {
  2323. hr = -hr2 + r * hr1 + pp[i];
  2324. hr2 = hr1;
  2325. hr1 = hr;
  2326. }
  2327. return Math.sin(arg_r) * hr;
  2328. };
  2329. var cosh = function(x) {
  2330. var r = Math.exp(x);
  2331. r = (r + 1 / r) / 2;
  2332. return r;
  2333. };
  2334. var clens_cmplx = function(pp, arg_r, arg_i) {
  2335. var sin_arg_r = Math.sin(arg_r);
  2336. var cos_arg_r = Math.cos(arg_r);
  2337. var sinh_arg_i = sinh(arg_i);
  2338. var cosh_arg_i = cosh(arg_i);
  2339. var r = 2 * cos_arg_r * cosh_arg_i;
  2340. var i = -2 * sin_arg_r * sinh_arg_i;
  2341. var j = pp.length - 1;
  2342. var hr = pp[j];
  2343. var hi1 = 0;
  2344. var hr1 = 0;
  2345. var hi = 0;
  2346. var hr2;
  2347. var hi2;
  2348. while (--j >= 0) {
  2349. hr2 = hr1;
  2350. hi2 = hi1;
  2351. hr1 = hr;
  2352. hi1 = hi;
  2353. hr = -hr2 + r * hr1 - i * hi1 + pp[j];
  2354. hi = -hi2 + i * hr1 + r * hi1;
  2355. }
  2356. r = sin_arg_r * cosh_arg_i;
  2357. i = cos_arg_r * sinh_arg_i;
  2358. return [r * hr - i * hi, r * hi + i * hr];
  2359. };
  2360. // Heavily based on this etmerc projection implementation
  2361. // https://github.com/mbloch/mapshaper-proj/blob/master/src/projections/etmerc.js
  2362. function init$3() {
  2363. if (this.es === undefined || this.es <= 0) {
  2364. throw new Error('incorrect elliptical usage');
  2365. }
  2366. this.x0 = this.x0 !== undefined ? this.x0 : 0;
  2367. this.y0 = this.y0 !== undefined ? this.y0 : 0;
  2368. this.long0 = this.long0 !== undefined ? this.long0 : 0;
  2369. this.lat0 = this.lat0 !== undefined ? this.lat0 : 0;
  2370. this.cgb = [];
  2371. this.cbg = [];
  2372. this.utg = [];
  2373. this.gtu = [];
  2374. var f = this.es / (1 + Math.sqrt(1 - this.es));
  2375. var n = f / (2 - f);
  2376. var np = n;
  2377. this.cgb[0] = n * (2 + n * (-2 / 3 + n * (-2 + n * (116 / 45 + n * (26 / 45 + n * (-2854 / 675 ))))));
  2378. this.cbg[0] = n * (-2 + n * ( 2 / 3 + n * ( 4 / 3 + n * (-82 / 45 + n * (32 / 45 + n * (4642 / 4725))))));
  2379. np = np * n;
  2380. this.cgb[1] = np * (7 / 3 + n * (-8 / 5 + n * (-227 / 45 + n * (2704 / 315 + n * (2323 / 945)))));
  2381. this.cbg[1] = np * (5 / 3 + n * (-16 / 15 + n * ( -13 / 9 + n * (904 / 315 + n * (-1522 / 945)))));
  2382. np = np * n;
  2383. this.cgb[2] = np * (56 / 15 + n * (-136 / 35 + n * (-1262 / 105 + n * (73814 / 2835))));
  2384. this.cbg[2] = np * (-26 / 15 + n * (34 / 21 + n * (8 / 5 + n * (-12686 / 2835))));
  2385. np = np * n;
  2386. this.cgb[3] = np * (4279 / 630 + n * (-332 / 35 + n * (-399572 / 14175)));
  2387. this.cbg[3] = np * (1237 / 630 + n * (-12 / 5 + n * ( -24832 / 14175)));
  2388. np = np * n;
  2389. this.cgb[4] = np * (4174 / 315 + n * (-144838 / 6237));
  2390. this.cbg[4] = np * (-734 / 315 + n * (109598 / 31185));
  2391. np = np * n;
  2392. this.cgb[5] = np * (601676 / 22275);
  2393. this.cbg[5] = np * (444337 / 155925);
  2394. np = Math.pow(n, 2);
  2395. this.Qn = this.k0 / (1 + n) * (1 + np * (1 / 4 + np * (1 / 64 + np / 256)));
  2396. this.utg[0] = n * (-0.5 + n * ( 2 / 3 + n * (-37 / 96 + n * ( 1 / 360 + n * (81 / 512 + n * (-96199 / 604800))))));
  2397. this.gtu[0] = n * (0.5 + n * (-2 / 3 + n * (5 / 16 + n * (41 / 180 + n * (-127 / 288 + n * (7891 / 37800))))));
  2398. this.utg[1] = np * (-1 / 48 + n * (-1 / 15 + n * (437 / 1440 + n * (-46 / 105 + n * (1118711 / 3870720)))));
  2399. this.gtu[1] = np * (13 / 48 + n * (-3 / 5 + n * (557 / 1440 + n * (281 / 630 + n * (-1983433 / 1935360)))));
  2400. np = np * n;
  2401. this.utg[2] = np * (-17 / 480 + n * (37 / 840 + n * (209 / 4480 + n * (-5569 / 90720 ))));
  2402. this.gtu[2] = np * (61 / 240 + n * (-103 / 140 + n * (15061 / 26880 + n * (167603 / 181440))));
  2403. np = np * n;
  2404. this.utg[3] = np * (-4397 / 161280 + n * (11 / 504 + n * (830251 / 7257600)));
  2405. this.gtu[3] = np * (49561 / 161280 + n * (-179 / 168 + n * (6601661 / 7257600)));
  2406. np = np * n;
  2407. this.utg[4] = np * (-4583 / 161280 + n * (108847 / 3991680));
  2408. this.gtu[4] = np * (34729 / 80640 + n * (-3418889 / 1995840));
  2409. np = np * n;
  2410. this.utg[5] = np * (-20648693 / 638668800);
  2411. this.gtu[5] = np * (212378941 / 319334400);
  2412. var Z = gatg(this.cbg, this.lat0);
  2413. this.Zb = -this.Qn * (Z + clens(this.gtu, 2 * Z));
  2414. }
  2415. function forward$3(p) {
  2416. var Ce = adjust_lon(p.x - this.long0);
  2417. var Cn = p.y;
  2418. Cn = gatg(this.cbg, Cn);
  2419. var sin_Cn = Math.sin(Cn);
  2420. var cos_Cn = Math.cos(Cn);
  2421. var sin_Ce = Math.sin(Ce);
  2422. var cos_Ce = Math.cos(Ce);
  2423. Cn = Math.atan2(sin_Cn, cos_Ce * cos_Cn);
  2424. Ce = Math.atan2(sin_Ce * cos_Cn, hypot(sin_Cn, cos_Cn * cos_Ce));
  2425. Ce = asinhy(Math.tan(Ce));
  2426. var tmp = clens_cmplx(this.gtu, 2 * Cn, 2 * Ce);
  2427. Cn = Cn + tmp[0];
  2428. Ce = Ce + tmp[1];
  2429. var x;
  2430. var y;
  2431. if (Math.abs(Ce) <= 2.623395162778) {
  2432. x = this.a * (this.Qn * Ce) + this.x0;
  2433. y = this.a * (this.Qn * Cn + this.Zb) + this.y0;
  2434. }
  2435. else {
  2436. x = Infinity;
  2437. y = Infinity;
  2438. }
  2439. p.x = x;
  2440. p.y = y;
  2441. return p;
  2442. }
  2443. function inverse$3(p) {
  2444. var Ce = (p.x - this.x0) * (1 / this.a);
  2445. var Cn = (p.y - this.y0) * (1 / this.a);
  2446. Cn = (Cn - this.Zb) / this.Qn;
  2447. Ce = Ce / this.Qn;
  2448. var lon;
  2449. var lat;
  2450. if (Math.abs(Ce) <= 2.623395162778) {
  2451. var tmp = clens_cmplx(this.utg, 2 * Cn, 2 * Ce);
  2452. Cn = Cn + tmp[0];
  2453. Ce = Ce + tmp[1];
  2454. Ce = Math.atan(sinh(Ce));
  2455. var sin_Cn = Math.sin(Cn);
  2456. var cos_Cn = Math.cos(Cn);
  2457. var sin_Ce = Math.sin(Ce);
  2458. var cos_Ce = Math.cos(Ce);
  2459. Cn = Math.atan2(sin_Cn * cos_Ce, hypot(sin_Ce, cos_Ce * cos_Cn));
  2460. Ce = Math.atan2(sin_Ce, cos_Ce * cos_Cn);
  2461. lon = adjust_lon(Ce + this.long0);
  2462. lat = gatg(this.cgb, Cn);
  2463. }
  2464. else {
  2465. lon = Infinity;
  2466. lat = Infinity;
  2467. }
  2468. p.x = lon;
  2469. p.y = lat;
  2470. return p;
  2471. }
  2472. var names$4 = ["Extended_Transverse_Mercator", "Extended Transverse Mercator", "etmerc"];
  2473. var etmerc = {
  2474. init: init$3,
  2475. forward: forward$3,
  2476. inverse: inverse$3,
  2477. names: names$4
  2478. };
  2479. var adjust_zone = function(zone, lon) {
  2480. if (zone === undefined) {
  2481. zone = Math.floor((adjust_lon(lon) + Math.PI) * 30 / Math.PI) + 1;
  2482. if (zone < 0) {
  2483. return 0;
  2484. } else if (zone > 60) {
  2485. return 60;
  2486. }
  2487. }
  2488. return zone;
  2489. };
  2490. var dependsOn = 'etmerc';
  2491. function init$4() {
  2492. var zone = adjust_zone(this.zone, this.long0);
  2493. if (zone === undefined) {
  2494. throw new Error('unknown utm zone');
  2495. }
  2496. this.lat0 = 0;
  2497. this.long0 = ((6 * Math.abs(zone)) - 183) * D2R;
  2498. this.x0 = 500000;
  2499. this.y0 = this.utmSouth ? 10000000 : 0;
  2500. this.k0 = 0.9996;
  2501. etmerc.init.apply(this);
  2502. this.forward = etmerc.forward;
  2503. this.inverse = etmerc.inverse;
  2504. }
  2505. var names$5 = ["Universal Transverse Mercator System", "utm"];
  2506. var utm = {
  2507. init: init$4,
  2508. names: names$5,
  2509. dependsOn: dependsOn
  2510. };
  2511. var srat = function(esinp, exp) {
  2512. return (Math.pow((1 - esinp) / (1 + esinp), exp));
  2513. };
  2514. var MAX_ITER$1 = 20;
  2515. function init$6() {
  2516. var sphi = Math.sin(this.lat0);
  2517. var cphi = Math.cos(this.lat0);
  2518. cphi *= cphi;
  2519. this.rc = Math.sqrt(1 - this.es) / (1 - this.es * sphi * sphi);
  2520. this.C = Math.sqrt(1 + this.es * cphi * cphi / (1 - this.es));
  2521. this.phic0 = Math.asin(sphi / this.C);
  2522. this.ratexp = 0.5 * this.C * this.e;
  2523. this.K = Math.tan(0.5 * this.phic0 + FORTPI) / (Math.pow(Math.tan(0.5 * this.lat0 + FORTPI), this.C) * srat(this.e * sphi, this.ratexp));
  2524. }
  2525. function forward$5(p) {
  2526. var lon = p.x;
  2527. var lat = p.y;
  2528. p.y = 2 * Math.atan(this.K * Math.pow(Math.tan(0.5 * lat + FORTPI), this.C) * srat(this.e * Math.sin(lat), this.ratexp)) - HALF_PI;
  2529. p.x = this.C * lon;
  2530. return p;
  2531. }
  2532. function inverse$5(p) {
  2533. var DEL_TOL = 1e-14;
  2534. var lon = p.x / this.C;
  2535. var lat = p.y;
  2536. var num = Math.pow(Math.tan(0.5 * lat + FORTPI) / this.K, 1 / this.C);
  2537. for (var i = MAX_ITER$1; i > 0; --i) {
  2538. lat = 2 * Math.atan(num * srat(this.e * Math.sin(p.y), - 0.5 * this.e)) - HALF_PI;
  2539. if (Math.abs(lat - p.y) < DEL_TOL) {
  2540. break;
  2541. }
  2542. p.y = lat;
  2543. }
  2544. /* convergence failed */
  2545. if (!i) {
  2546. return null;
  2547. }
  2548. p.x = lon;
  2549. p.y = lat;
  2550. return p;
  2551. }
  2552. var names$7 = ["gauss"];
  2553. var gauss = {
  2554. init: init$6,
  2555. forward: forward$5,
  2556. inverse: inverse$5,
  2557. names: names$7
  2558. };
  2559. function init$5() {
  2560. gauss.init.apply(this);
  2561. if (!this.rc) {
  2562. return;
  2563. }
  2564. this.sinc0 = Math.sin(this.phic0);
  2565. this.cosc0 = Math.cos(this.phic0);
  2566. this.R2 = 2 * this.rc;
  2567. if (!this.title) {
  2568. this.title = "Oblique Stereographic Alternative";
  2569. }
  2570. }
  2571. function forward$4(p) {
  2572. var sinc, cosc, cosl, k;
  2573. p.x = adjust_lon(p.x - this.long0);
  2574. gauss.forward.apply(this, [p]);
  2575. sinc = Math.sin(p.y);
  2576. cosc = Math.cos(p.y);
  2577. cosl = Math.cos(p.x);
  2578. k = this.k0 * this.R2 / (1 + this.sinc0 * sinc + this.cosc0 * cosc * cosl);
  2579. p.x = k * cosc * Math.sin(p.x);
  2580. p.y = k * (this.cosc0 * sinc - this.sinc0 * cosc * cosl);
  2581. p.x = this.a * p.x + this.x0;
  2582. p.y = this.a * p.y + this.y0;
  2583. return p;
  2584. }
  2585. function inverse$4(p) {
  2586. var sinc, cosc, lon, lat, rho;
  2587. p.x = (p.x - this.x0) / this.a;
  2588. p.y = (p.y - this.y0) / this.a;
  2589. p.x /= this.k0;
  2590. p.y /= this.k0;
  2591. if ((rho = Math.sqrt(p.x * p.x + p.y * p.y))) {
  2592. var c = 2 * Math.atan2(rho, this.R2);
  2593. sinc = Math.sin(c);
  2594. cosc = Math.cos(c);
  2595. lat = Math.asin(cosc * this.sinc0 + p.y * sinc * this.cosc0 / rho);
  2596. lon = Math.atan2(p.x * sinc, rho * this.cosc0 * cosc - p.y * this.sinc0 * sinc);
  2597. }
  2598. else {
  2599. lat = this.phic0;
  2600. lon = 0;
  2601. }
  2602. p.x = lon;
  2603. p.y = lat;
  2604. gauss.inverse.apply(this, [p]);
  2605. p.x = adjust_lon(p.x + this.long0);
  2606. return p;
  2607. }
  2608. var names$6 = ["Stereographic_North_Pole", "Oblique_Stereographic", "Polar_Stereographic", "sterea","Oblique Stereographic Alternative","Double_Stereographic"];
  2609. var sterea = {
  2610. init: init$5,
  2611. forward: forward$4,
  2612. inverse: inverse$4,
  2613. names: names$6
  2614. };
  2615. function ssfn_(phit, sinphi, eccen) {
  2616. sinphi *= eccen;
  2617. return (Math.tan(0.5 * (HALF_PI + phit)) * Math.pow((1 - sinphi) / (1 + sinphi), 0.5 * eccen));
  2618. }
  2619. function init$7() {
  2620. this.coslat0 = Math.cos(this.lat0);
  2621. this.sinlat0 = Math.sin(this.lat0);
  2622. if (this.sphere) {
  2623. if (this.k0 === 1 && !isNaN(this.lat_ts) && Math.abs(this.coslat0) <= EPSLN) {
  2624. this.k0 = 0.5 * (1 + sign(this.lat0) * Math.sin(this.lat_ts));
  2625. }
  2626. }
  2627. else {
  2628. if (Math.abs(this.coslat0) <= EPSLN) {
  2629. if (this.lat0 > 0) {
  2630. //North pole
  2631. //trace('stere:north pole');
  2632. this.con = 1;
  2633. }
  2634. else {
  2635. //South pole
  2636. //trace('stere:south pole');
  2637. this.con = -1;
  2638. }
  2639. }
  2640. this.cons = Math.sqrt(Math.pow(1 + this.e, 1 + this.e) * Math.pow(1 - this.e, 1 - this.e));
  2641. if (this.k0 === 1 && !isNaN(this.lat_ts) && Math.abs(this.coslat0) <= EPSLN) {
  2642. this.k0 = 0.5 * this.cons * msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts)) / tsfnz(this.e, this.con * this.lat_ts, this.con * Math.sin(this.lat_ts));
  2643. }
  2644. this.ms1 = msfnz(this.e, this.sinlat0, this.coslat0);
  2645. this.X0 = 2 * Math.atan(this.ssfn_(this.lat0, this.sinlat0, this.e)) - HALF_PI;
  2646. this.cosX0 = Math.cos(this.X0);
  2647. this.sinX0 = Math.sin(this.X0);
  2648. }
  2649. }
  2650. // Stereographic forward equations--mapping lat,long to x,y
  2651. function forward$6(p) {
  2652. var lon = p.x;
  2653. var lat = p.y;
  2654. var sinlat = Math.sin(lat);
  2655. var coslat = Math.cos(lat);
  2656. var A, X, sinX, cosX, ts, rh;
  2657. var dlon = adjust_lon(lon - this.long0);
  2658. if (Math.abs(Math.abs(lon - this.long0) - Math.PI) <= EPSLN && Math.abs(lat + this.lat0) <= EPSLN) {
  2659. //case of the origine point
  2660. //trace('stere:this is the origin point');
  2661. p.x = NaN;
  2662. p.y = NaN;
  2663. return p;
  2664. }
  2665. if (this.sphere) {
  2666. //trace('stere:sphere case');
  2667. A = 2 * this.k0 / (1 + this.sinlat0 * sinlat + this.coslat0 * coslat * Math.cos(dlon));
  2668. p.x = this.a * A * coslat * Math.sin(dlon) + this.x0;
  2669. p.y = this.a * A * (this.coslat0 * sinlat - this.sinlat0 * coslat * Math.cos(dlon)) + this.y0;
  2670. return p;
  2671. }
  2672. else {
  2673. X = 2 * Math.atan(this.ssfn_(lat, sinlat, this.e)) - HALF_PI;
  2674. cosX = Math.cos(X);
  2675. sinX = Math.sin(X);
  2676. if (Math.abs(this.coslat0) <= EPSLN) {
  2677. ts = tsfnz(this.e, lat * this.con, this.con * sinlat);
  2678. rh = 2 * this.a * this.k0 * ts / this.cons;
  2679. p.x = this.x0 + rh * Math.sin(lon - this.long0);
  2680. p.y = this.y0 - this.con * rh * Math.cos(lon - this.long0);
  2681. //trace(p.toString());
  2682. return p;
  2683. }
  2684. else if (Math.abs(this.sinlat0) < EPSLN) {
  2685. //Eq
  2686. //trace('stere:equateur');
  2687. A = 2 * this.a * this.k0 / (1 + cosX * Math.cos(dlon));
  2688. p.y = A * sinX;
  2689. }
  2690. else {
  2691. //other case
  2692. //trace('stere:normal case');
  2693. A = 2 * this.a * this.k0 * this.ms1 / (this.cosX0 * (1 + this.sinX0 * sinX + this.cosX0 * cosX * Math.cos(dlon)));
  2694. p.y = A * (this.cosX0 * sinX - this.sinX0 * cosX * Math.cos(dlon)) + this.y0;
  2695. }
  2696. p.x = A * cosX * Math.sin(dlon) + this.x0;
  2697. }
  2698. //trace(p.toString());
  2699. return p;
  2700. }
  2701. //* Stereographic inverse equations--mapping x,y to lat/long
  2702. function inverse$6(p) {
  2703. p.x -= this.x0;
  2704. p.y -= this.y0;
  2705. var lon, lat, ts, ce, Chi;
  2706. var rh = Math.sqrt(p.x * p.x + p.y * p.y);
  2707. if (this.sphere) {
  2708. var c = 2 * Math.atan(rh / (2 * this.a * this.k0));
  2709. lon = this.long0;
  2710. lat = this.lat0;
  2711. if (rh <= EPSLN) {
  2712. p.x = lon;
  2713. p.y = lat;
  2714. return p;
  2715. }
  2716. lat = Math.asin(Math.cos(c) * this.sinlat0 + p.y * Math.sin(c) * this.coslat0 / rh);
  2717. if (Math.abs(this.coslat0) < EPSLN) {
  2718. if (this.lat0 > 0) {
  2719. lon = adjust_lon(this.long0 + Math.atan2(p.x, - 1 * p.y));
  2720. }
  2721. else {
  2722. lon = adjust_lon(this.long0 + Math.atan2(p.x, p.y));
  2723. }
  2724. }
  2725. else {
  2726. lon = adjust_lon(this.long0 + Math.atan2(p.x * Math.sin(c), rh * this.coslat0 * Math.cos(c) - p.y * this.sinlat0 * Math.sin(c)));
  2727. }
  2728. p.x = lon;
  2729. p.y = lat;
  2730. return p;
  2731. }
  2732. else {
  2733. if (Math.abs(this.coslat0) <= EPSLN) {
  2734. if (rh <= EPSLN) {
  2735. lat = this.lat0;
  2736. lon = this.long0;
  2737. p.x = lon;
  2738. p.y = lat;
  2739. //trace(p.toString());
  2740. return p;
  2741. }
  2742. p.x *= this.con;
  2743. p.y *= this.con;
  2744. ts = rh * this.cons / (2 * this.a * this.k0);
  2745. lat = this.con * phi2z(this.e, ts);
  2746. lon = this.con * adjust_lon(this.con * this.long0 + Math.atan2(p.x, - 1 * p.y));
  2747. }
  2748. else {
  2749. ce = 2 * Math.atan(rh * this.cosX0 / (2 * this.a * this.k0 * this.ms1));
  2750. lon = this.long0;
  2751. if (rh <= EPSLN) {
  2752. Chi = this.X0;
  2753. }
  2754. else {
  2755. Chi = Math.asin(Math.cos(ce) * this.sinX0 + p.y * Math.sin(ce) * this.cosX0 / rh);
  2756. lon = adjust_lon(this.long0 + Math.atan2(p.x * Math.sin(ce), rh * this.cosX0 * Math.cos(ce) - p.y * this.sinX0 * Math.sin(ce)));
  2757. }
  2758. lat = -1 * phi2z(this.e, Math.tan(0.5 * (HALF_PI + Chi)));
  2759. }
  2760. }
  2761. p.x = lon;
  2762. p.y = lat;
  2763. //trace(p.toString());
  2764. return p;
  2765. }
  2766. var names$8 = ["stere", "Stereographic_South_Pole", "Polar Stereographic (variant B)"];
  2767. var stere = {
  2768. init: init$7,
  2769. forward: forward$6,
  2770. inverse: inverse$6,
  2771. names: names$8,
  2772. ssfn_: ssfn_
  2773. };
  2774. /*
  2775. references:
  2776. Formules et constantes pour le Calcul pour la
  2777. projection cylindrique conforme à axe oblique et pour la transformation entre
  2778. des systèmes de référence.
  2779. http://www.swisstopo.admin.ch/internet/swisstopo/fr/home/topics/survey/sys/refsys/switzerland.parsysrelated1.31216.downloadList.77004.DownloadFile.tmp/swissprojectionfr.pdf
  2780. */
  2781. function init$8() {
  2782. var phy0 = this.lat0;
  2783. this.lambda0 = this.long0;
  2784. var sinPhy0 = Math.sin(phy0);
  2785. var semiMajorAxis = this.a;
  2786. var invF = this.rf;
  2787. var flattening = 1 / invF;
  2788. var e2 = 2 * flattening - Math.pow(flattening, 2);
  2789. var e = this.e = Math.sqrt(e2);
  2790. this.R = this.k0 * semiMajorAxis * Math.sqrt(1 - e2) / (1 - e2 * Math.pow(sinPhy0, 2));
  2791. this.alpha = Math.sqrt(1 + e2 / (1 - e2) * Math.pow(Math.cos(phy0), 4));
  2792. this.b0 = Math.asin(sinPhy0 / this.alpha);
  2793. var k1 = Math.log(Math.tan(Math.PI / 4 + this.b0 / 2));
  2794. var k2 = Math.log(Math.tan(Math.PI / 4 + phy0 / 2));
  2795. var k3 = Math.log((1 + e * sinPhy0) / (1 - e * sinPhy0));
  2796. this.K = k1 - this.alpha * k2 + this.alpha * e / 2 * k3;
  2797. }
  2798. function forward$7(p) {
  2799. var Sa1 = Math.log(Math.tan(Math.PI / 4 - p.y / 2));
  2800. var Sa2 = this.e / 2 * Math.log((1 + this.e * Math.sin(p.y)) / (1 - this.e * Math.sin(p.y)));
  2801. var S = -this.alpha * (Sa1 + Sa2) + this.K;
  2802. // spheric latitude
  2803. var b = 2 * (Math.atan(Math.exp(S)) - Math.PI / 4);
  2804. // spheric longitude
  2805. var I = this.alpha * (p.x - this.lambda0);
  2806. // psoeudo equatorial rotation
  2807. var rotI = Math.atan(Math.sin(I) / (Math.sin(this.b0) * Math.tan(b) + Math.cos(this.b0) * Math.cos(I)));
  2808. var rotB = Math.asin(Math.cos(this.b0) * Math.sin(b) - Math.sin(this.b0) * Math.cos(b) * Math.cos(I));
  2809. p.y = this.R / 2 * Math.log((1 + Math.sin(rotB)) / (1 - Math.sin(rotB))) + this.y0;
  2810. p.x = this.R * rotI + this.x0;
  2811. return p;
  2812. }
  2813. function inverse$7(p) {
  2814. var Y = p.x - this.x0;
  2815. var X = p.y - this.y0;
  2816. var rotI = Y / this.R;
  2817. var rotB = 2 * (Math.atan(Math.exp(X / this.R)) - Math.PI / 4);
  2818. var b = Math.asin(Math.cos(this.b0) * Math.sin(rotB) + Math.sin(this.b0) * Math.cos(rotB) * Math.cos(rotI));
  2819. var I = Math.atan(Math.sin(rotI) / (Math.cos(this.b0) * Math.cos(rotI) - Math.sin(this.b0) * Math.tan(rotB)));
  2820. var lambda = this.lambda0 + I / this.alpha;
  2821. var S = 0;
  2822. var phy = b;
  2823. var prevPhy = -1000;
  2824. var iteration = 0;
  2825. while (Math.abs(phy - prevPhy) > 0.0000001) {
  2826. if (++iteration > 20) {
  2827. //...reportError("omercFwdInfinity");
  2828. return;
  2829. }
  2830. //S = Math.log(Math.tan(Math.PI / 4 + phy / 2));
  2831. S = 1 / this.alpha * (Math.log(Math.tan(Math.PI / 4 + b / 2)) - this.K) + this.e * Math.log(Math.tan(Math.PI / 4 + Math.asin(this.e * Math.sin(phy)) / 2));
  2832. prevPhy = phy;
  2833. phy = 2 * Math.atan(Math.exp(S)) - Math.PI / 2;
  2834. }
  2835. p.x = lambda;
  2836. p.y = phy;
  2837. return p;
  2838. }
  2839. var names$9 = ["somerc"];
  2840. var somerc = {
  2841. init: init$8,
  2842. forward: forward$7,
  2843. inverse: inverse$7,
  2844. names: names$9
  2845. };
  2846. /* Initialize the Oblique Mercator projection
  2847. ------------------------------------------*/
  2848. function init$9() {
  2849. this.no_off = this.no_off || false;
  2850. this.no_rot = this.no_rot || false;
  2851. if (isNaN(this.k0)) {
  2852. this.k0 = 1;
  2853. }
  2854. var sinlat = Math.sin(this.lat0);
  2855. var coslat = Math.cos(this.lat0);
  2856. var con = this.e * sinlat;
  2857. this.bl = Math.sqrt(1 + this.es / (1 - this.es) * Math.pow(coslat, 4));
  2858. this.al = this.a * this.bl * this.k0 * Math.sqrt(1 - this.es) / (1 - con * con);
  2859. var t0 = tsfnz(this.e, this.lat0, sinlat);
  2860. var dl = this.bl / coslat * Math.sqrt((1 - this.es) / (1 - con * con));
  2861. if (dl * dl < 1) {
  2862. dl = 1;
  2863. }
  2864. var fl;
  2865. var gl;
  2866. if (!isNaN(this.longc)) {
  2867. //Central point and azimuth method
  2868. if (this.lat0 >= 0) {
  2869. fl = dl + Math.sqrt(dl * dl - 1);
  2870. }
  2871. else {
  2872. fl = dl - Math.sqrt(dl * dl - 1);
  2873. }
  2874. this.el = fl * Math.pow(t0, this.bl);
  2875. gl = 0.5 * (fl - 1 / fl);
  2876. this.gamma0 = Math.asin(Math.sin(this.alpha) / dl);
  2877. this.long0 = this.longc - Math.asin(gl * Math.tan(this.gamma0)) / this.bl;
  2878. }
  2879. else {
  2880. //2 points method
  2881. var t1 = tsfnz(this.e, this.lat1, Math.sin(this.lat1));
  2882. var t2 = tsfnz(this.e, this.lat2, Math.sin(this.lat2));
  2883. if (this.lat0 >= 0) {
  2884. this.el = (dl + Math.sqrt(dl * dl - 1)) * Math.pow(t0, this.bl);
  2885. }
  2886. else {
  2887. this.el = (dl - Math.sqrt(dl * dl - 1)) * Math.pow(t0, this.bl);
  2888. }
  2889. var hl = Math.pow(t1, this.bl);
  2890. var ll = Math.pow(t2, this.bl);
  2891. fl = this.el / hl;
  2892. gl = 0.5 * (fl - 1 / fl);
  2893. var jl = (this.el * this.el - ll * hl) / (this.el * this.el + ll * hl);
  2894. var pl = (ll - hl) / (ll + hl);
  2895. var dlon12 = adjust_lon(this.long1 - this.long2);
  2896. this.long0 = 0.5 * (this.long1 + this.long2) - Math.atan(jl * Math.tan(0.5 * this.bl * (dlon12)) / pl) / this.bl;
  2897. this.long0 = adjust_lon(this.long0);
  2898. var dlon10 = adjust_lon(this.long1 - this.long0);
  2899. this.gamma0 = Math.atan(Math.sin(this.bl * (dlon10)) / gl);
  2900. this.alpha = Math.asin(dl * Math.sin(this.gamma0));
  2901. }
  2902. if (this.no_off) {
  2903. this.uc = 0;
  2904. }
  2905. else {
  2906. if (this.lat0 >= 0) {
  2907. this.uc = this.al / this.bl * Math.atan2(Math.sqrt(dl * dl - 1), Math.cos(this.alpha));
  2908. }
  2909. else {
  2910. this.uc = -1 * this.al / this.bl * Math.atan2(Math.sqrt(dl * dl - 1), Math.cos(this.alpha));
  2911. }
  2912. }
  2913. }
  2914. /* Oblique Mercator forward equations--mapping lat,long to x,y
  2915. ----------------------------------------------------------*/
  2916. function forward$8(p) {
  2917. var lon = p.x;
  2918. var lat = p.y;
  2919. var dlon = adjust_lon(lon - this.long0);
  2920. var us, vs;
  2921. var con;
  2922. if (Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN) {
  2923. if (lat > 0) {
  2924. con = -1;
  2925. }
  2926. else {
  2927. con = 1;
  2928. }
  2929. vs = this.al / this.bl * Math.log(Math.tan(FORTPI + con * this.gamma0 * 0.5));
  2930. us = -1 * con * HALF_PI * this.al / this.bl;
  2931. }
  2932. else {
  2933. var t = tsfnz(this.e, lat, Math.sin(lat));
  2934. var ql = this.el / Math.pow(t, this.bl);
  2935. var sl = 0.5 * (ql - 1 / ql);
  2936. var tl = 0.5 * (ql + 1 / ql);
  2937. var vl = Math.sin(this.bl * (dlon));
  2938. var ul = (sl * Math.sin(this.gamma0) - vl * Math.cos(this.gamma0)) / tl;
  2939. if (Math.abs(Math.abs(ul) - 1) <= EPSLN) {
  2940. vs = Number.POSITIVE_INFINITY;
  2941. }
  2942. else {
  2943. vs = 0.5 * this.al * Math.log((1 - ul) / (1 + ul)) / this.bl;
  2944. }
  2945. if (Math.abs(Math.cos(this.bl * (dlon))) <= EPSLN) {
  2946. us = this.al * this.bl * (dlon);
  2947. }
  2948. else {
  2949. us = this.al * Math.atan2(sl * Math.cos(this.gamma0) + vl * Math.sin(this.gamma0), Math.cos(this.bl * dlon)) / this.bl;
  2950. }
  2951. }
  2952. if (this.no_rot) {
  2953. p.x = this.x0 + us;
  2954. p.y = this.y0 + vs;
  2955. }
  2956. else {
  2957. us -= this.uc;
  2958. p.x = this.x0 + vs * Math.cos(this.alpha) + us * Math.sin(this.alpha);
  2959. p.y = this.y0 + us * Math.cos(this.alpha) - vs * Math.sin(this.alpha);
  2960. }
  2961. return p;
  2962. }
  2963. function inverse$8(p) {
  2964. var us, vs;
  2965. if (this.no_rot) {
  2966. vs = p.y - this.y0;
  2967. us = p.x - this.x0;
  2968. }
  2969. else {
  2970. vs = (p.x - this.x0) * Math.cos(this.alpha) - (p.y - this.y0) * Math.sin(this.alpha);
  2971. us = (p.y - this.y0) * Math.cos(this.alpha) + (p.x - this.x0) * Math.sin(this.alpha);
  2972. us += this.uc;
  2973. }
  2974. var qp = Math.exp(-1 * this.bl * vs / this.al);
  2975. var sp = 0.5 * (qp - 1 / qp);
  2976. var tp = 0.5 * (qp + 1 / qp);
  2977. var vp = Math.sin(this.bl * us / this.al);
  2978. var up = (vp * Math.cos(this.gamma0) + sp * Math.sin(this.gamma0)) / tp;
  2979. var ts = Math.pow(this.el / Math.sqrt((1 + up) / (1 - up)), 1 / this.bl);
  2980. if (Math.abs(up - 1) < EPSLN) {
  2981. p.x = this.long0;
  2982. p.y = HALF_PI;
  2983. }
  2984. else if (Math.abs(up + 1) < EPSLN) {
  2985. p.x = this.long0;
  2986. p.y = -1 * HALF_PI;
  2987. }
  2988. else {
  2989. p.y = phi2z(this.e, ts);
  2990. p.x = adjust_lon(this.long0 - Math.atan2(sp * Math.cos(this.gamma0) - vp * Math.sin(this.gamma0), Math.cos(this.bl * us / this.al)) / this.bl);
  2991. }
  2992. return p;
  2993. }
  2994. var names$10 = ["Hotine_Oblique_Mercator", "Hotine Oblique Mercator", "Hotine_Oblique_Mercator_Azimuth_Natural_Origin", "Hotine_Oblique_Mercator_Azimuth_Center", "omerc"];
  2995. var omerc = {
  2996. init: init$9,
  2997. forward: forward$8,
  2998. inverse: inverse$8,
  2999. names: names$10
  3000. };
  3001. function init$10() {
  3002. // array of: r_maj,r_min,lat1,lat2,c_lon,c_lat,false_east,false_north
  3003. //double c_lat; /* center latitude */
  3004. //double c_lon; /* center longitude */
  3005. //double lat1; /* first standard parallel */
  3006. //double lat2; /* second standard parallel */
  3007. //double r_maj; /* major axis */
  3008. //double r_min; /* minor axis */
  3009. //double false_east; /* x offset in meters */
  3010. //double false_north; /* y offset in meters */
  3011. if (!this.lat2) {
  3012. this.lat2 = this.lat1;
  3013. } //if lat2 is not defined
  3014. if (!this.k0) {
  3015. this.k0 = 1;
  3016. }
  3017. this.x0 = this.x0 || 0;
  3018. this.y0 = this.y0 || 0;
  3019. // Standard Parallels cannot be equal and on opposite sides of the equator
  3020. if (Math.abs(this.lat1 + this.lat2) < EPSLN) {
  3021. return;
  3022. }
  3023. var temp = this.b / this.a;
  3024. this.e = Math.sqrt(1 - temp * temp);
  3025. var sin1 = Math.sin(this.lat1);
  3026. var cos1 = Math.cos(this.lat1);
  3027. var ms1 = msfnz(this.e, sin1, cos1);
  3028. var ts1 = tsfnz(this.e, this.lat1, sin1);
  3029. var sin2 = Math.sin(this.lat2);
  3030. var cos2 = Math.cos(this.lat2);
  3031. var ms2 = msfnz(this.e, sin2, cos2);
  3032. var ts2 = tsfnz(this.e, this.lat2, sin2);
  3033. var ts0 = tsfnz(this.e, this.lat0, Math.sin(this.lat0));
  3034. if (Math.abs(this.lat1 - this.lat2) > EPSLN) {
  3035. this.ns = Math.log(ms1 / ms2) / Math.log(ts1 / ts2);
  3036. }
  3037. else {
  3038. this.ns = sin1;
  3039. }
  3040. if (isNaN(this.ns)) {
  3041. this.ns = sin1;
  3042. }
  3043. this.f0 = ms1 / (this.ns * Math.pow(ts1, this.ns));
  3044. this.rh = this.a * this.f0 * Math.pow(ts0, this.ns);
  3045. if (!this.title) {
  3046. this.title = "Lambert Conformal Conic";
  3047. }
  3048. }
  3049. // Lambert Conformal conic forward equations--mapping lat,long to x,y
  3050. // -----------------------------------------------------------------
  3051. function forward$9(p) {
  3052. var lon = p.x;
  3053. var lat = p.y;
  3054. // singular cases :
  3055. if (Math.abs(2 * Math.abs(lat) - Math.PI) <= EPSLN) {
  3056. lat = sign(lat) * (HALF_PI - 2 * EPSLN);
  3057. }
  3058. var con = Math.abs(Math.abs(lat) - HALF_PI);
  3059. var ts, rh1;
  3060. if (con > EPSLN) {
  3061. ts = tsfnz(this.e, lat, Math.sin(lat));
  3062. rh1 = this.a * this.f0 * Math.pow(ts, this.ns);
  3063. }
  3064. else {
  3065. con = lat * this.ns;
  3066. if (con <= 0) {
  3067. return null;
  3068. }
  3069. rh1 = 0;
  3070. }
  3071. var theta = this.ns * adjust_lon(lon - this.long0);
  3072. p.x = this.k0 * (rh1 * Math.sin(theta)) + this.x0;
  3073. p.y = this.k0 * (this.rh - rh1 * Math.cos(theta)) + this.y0;
  3074. return p;
  3075. }
  3076. // Lambert Conformal Conic inverse equations--mapping x,y to lat/long
  3077. // -----------------------------------------------------------------
  3078. function inverse$9(p) {
  3079. var rh1, con, ts;
  3080. var lat, lon;
  3081. var x = (p.x - this.x0) / this.k0;
  3082. var y = (this.rh - (p.y - this.y0) / this.k0);
  3083. if (this.ns > 0) {
  3084. rh1 = Math.sqrt(x * x + y * y);
  3085. con = 1;
  3086. }
  3087. else {
  3088. rh1 = -Math.sqrt(x * x + y * y);
  3089. con = -1;
  3090. }
  3091. var theta = 0;
  3092. if (rh1 !== 0) {
  3093. theta = Math.atan2((con * x), (con * y));
  3094. }
  3095. if ((rh1 !== 0) || (this.ns > 0)) {
  3096. con = 1 / this.ns;
  3097. ts = Math.pow((rh1 / (this.a * this.f0)), con);
  3098. lat = phi2z(this.e, ts);
  3099. if (lat === -9999) {
  3100. return null;
  3101. }
  3102. }
  3103. else {
  3104. lat = -HALF_PI;
  3105. }
  3106. lon = adjust_lon(theta / this.ns + this.long0);
  3107. p.x = lon;
  3108. p.y = lat;
  3109. return p;
  3110. }
  3111. var names$11 = ["Lambert Tangential Conformal Conic Projection", "Lambert_Conformal_Conic", "Lambert_Conformal_Conic_2SP", "lcc"];
  3112. var lcc = {
  3113. init: init$10,
  3114. forward: forward$9,
  3115. inverse: inverse$9,
  3116. names: names$11
  3117. };
  3118. function init$11() {
  3119. this.a = 6377397.155;
  3120. this.es = 0.006674372230614;
  3121. this.e = Math.sqrt(this.es);
  3122. if (!this.lat0) {
  3123. this.lat0 = 0.863937979737193;
  3124. }
  3125. if (!this.long0) {
  3126. this.long0 = 0.7417649320975901 - 0.308341501185665;
  3127. }
  3128. /* if scale not set default to 0.9999 */
  3129. if (!this.k0) {
  3130. this.k0 = 0.9999;
  3131. }
  3132. this.s45 = 0.785398163397448; /* 45 */
  3133. this.s90 = 2 * this.s45;
  3134. this.fi0 = this.lat0;
  3135. this.e2 = this.es;
  3136. this.e = Math.sqrt(this.e2);
  3137. this.alfa = Math.sqrt(1 + (this.e2 * Math.pow(Math.cos(this.fi0), 4)) / (1 - this.e2));
  3138. this.uq = 1.04216856380474;
  3139. this.u0 = Math.asin(Math.sin(this.fi0) / this.alfa);
  3140. this.g = Math.pow((1 + this.e * Math.sin(this.fi0)) / (1 - this.e * Math.sin(this.fi0)), this.alfa * this.e / 2);
  3141. this.k = Math.tan(this.u0 / 2 + this.s45) / Math.pow(Math.tan(this.fi0 / 2 + this.s45), this.alfa) * this.g;
  3142. this.k1 = this.k0;
  3143. this.n0 = this.a * Math.sqrt(1 - this.e2) / (1 - this.e2 * Math.pow(Math.sin(this.fi0), 2));
  3144. this.s0 = 1.37008346281555;
  3145. this.n = Math.sin(this.s0);
  3146. this.ro0 = this.k1 * this.n0 / Math.tan(this.s0);
  3147. this.ad = this.s90 - this.uq;
  3148. }
  3149. /* ellipsoid */
  3150. /* calculate xy from lat/lon */
  3151. /* Constants, identical to inverse transform function */
  3152. function forward$10(p) {
  3153. var gfi, u, deltav, s, d, eps, ro;
  3154. var lon = p.x;
  3155. var lat = p.y;
  3156. var delta_lon = adjust_lon(lon - this.long0);
  3157. /* Transformation */
  3158. gfi = Math.pow(((1 + this.e * Math.sin(lat)) / (1 - this.e * Math.sin(lat))), (this.alfa * this.e / 2));
  3159. u = 2 * (Math.atan(this.k * Math.pow(Math.tan(lat / 2 + this.s45), this.alfa) / gfi) - this.s45);
  3160. deltav = -delta_lon * this.alfa;
  3161. s = Math.asin(Math.cos(this.ad) * Math.sin(u) + Math.sin(this.ad) * Math.cos(u) * Math.cos(deltav));
  3162. d = Math.asin(Math.cos(u) * Math.sin(deltav) / Math.cos(s));
  3163. eps = this.n * d;
  3164. ro = this.ro0 * Math.pow(Math.tan(this.s0 / 2 + this.s45), this.n) / Math.pow(Math.tan(s / 2 + this.s45), this.n);
  3165. p.y = ro * Math.cos(eps) / 1;
  3166. p.x = ro * Math.sin(eps) / 1;
  3167. if (!this.czech) {
  3168. p.y *= -1;
  3169. p.x *= -1;
  3170. }
  3171. return (p);
  3172. }
  3173. /* calculate lat/lon from xy */
  3174. function inverse$10(p) {
  3175. var u, deltav, s, d, eps, ro, fi1;
  3176. var ok;
  3177. /* Transformation */
  3178. /* revert y, x*/
  3179. var tmp = p.x;
  3180. p.x = p.y;
  3181. p.y = tmp;
  3182. if (!this.czech) {
  3183. p.y *= -1;
  3184. p.x *= -1;
  3185. }
  3186. ro = Math.sqrt(p.x * p.x + p.y * p.y);
  3187. eps = Math.atan2(p.y, p.x);
  3188. d = eps / Math.sin(this.s0);
  3189. s = 2 * (Math.atan(Math.pow(this.ro0 / ro, 1 / this.n) * Math.tan(this.s0 / 2 + this.s45)) - this.s45);
  3190. u = Math.asin(Math.cos(this.ad) * Math.sin(s) - Math.sin(this.ad) * Math.cos(s) * Math.cos(d));
  3191. deltav = Math.asin(Math.cos(s) * Math.sin(d) / Math.cos(u));
  3192. p.x = this.long0 - deltav / this.alfa;
  3193. fi1 = u;
  3194. ok = 0;
  3195. var iter = 0;
  3196. do {
  3197. p.y = 2 * (Math.atan(Math.pow(this.k, - 1 / this.alfa) * Math.pow(Math.tan(u / 2 + this.s45), 1 / this.alfa) * Math.pow((1 + this.e * Math.sin(fi1)) / (1 - this.e * Math.sin(fi1)), this.e / 2)) - this.s45);
  3198. if (Math.abs(fi1 - p.y) < 0.0000000001) {
  3199. ok = 1;
  3200. }
  3201. fi1 = p.y;
  3202. iter += 1;
  3203. } while (ok === 0 && iter < 15);
  3204. if (iter >= 15) {
  3205. return null;
  3206. }
  3207. return (p);
  3208. }
  3209. var names$12 = ["Krovak", "krovak"];
  3210. var krovak = {
  3211. init: init$11,
  3212. forward: forward$10,
  3213. inverse: inverse$10,
  3214. names: names$12
  3215. };
  3216. var mlfn = function(e0, e1, e2, e3, phi) {
  3217. return (e0 * phi - e1 * Math.sin(2 * phi) + e2 * Math.sin(4 * phi) - e3 * Math.sin(6 * phi));
  3218. };
  3219. var e0fn = function(x) {
  3220. return (1 - 0.25 * x * (1 + x / 16 * (3 + 1.25 * x)));
  3221. };
  3222. var e1fn = function(x) {
  3223. return (0.375 * x * (1 + 0.25 * x * (1 + 0.46875 * x)));
  3224. };
  3225. var e2fn = function(x) {
  3226. return (0.05859375 * x * x * (1 + 0.75 * x));
  3227. };
  3228. var e3fn = function(x) {
  3229. return (x * x * x * (35 / 3072));
  3230. };
  3231. var gN = function(a, e, sinphi) {
  3232. var temp = e * sinphi;
  3233. return a / Math.sqrt(1 - temp * temp);
  3234. };
  3235. var adjust_lat = function(x) {
  3236. return (Math.abs(x) < HALF_PI) ? x : (x - (sign(x) * Math.PI));
  3237. };
  3238. var imlfn = function(ml, e0, e1, e2, e3) {
  3239. var phi;
  3240. var dphi;
  3241. phi = ml / e0;
  3242. for (var i = 0; i < 15; i++) {
  3243. dphi = (ml - (e0 * phi - e1 * Math.sin(2 * phi) + e2 * Math.sin(4 * phi) - e3 * Math.sin(6 * phi))) / (e0 - 2 * e1 * Math.cos(2 * phi) + 4 * e2 * Math.cos(4 * phi) - 6 * e3 * Math.cos(6 * phi));
  3244. phi += dphi;
  3245. if (Math.abs(dphi) <= 0.0000000001) {
  3246. return phi;
  3247. }
  3248. }
  3249. //..reportError("IMLFN-CONV:Latitude failed to converge after 15 iterations");
  3250. return NaN;
  3251. };
  3252. function init$12() {
  3253. if (!this.sphere) {
  3254. this.e0 = e0fn(this.es);
  3255. this.e1 = e1fn(this.es);
  3256. this.e2 = e2fn(this.es);
  3257. this.e3 = e3fn(this.es);
  3258. this.ml0 = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0);
  3259. }
  3260. }
  3261. /* Cassini forward equations--mapping lat,long to x,y
  3262. -----------------------------------------------------------------------*/
  3263. function forward$11(p) {
  3264. /* Forward equations
  3265. -----------------*/
  3266. var x, y;
  3267. var lam = p.x;
  3268. var phi = p.y;
  3269. lam = adjust_lon(lam - this.long0);
  3270. if (this.sphere) {
  3271. x = this.a * Math.asin(Math.cos(phi) * Math.sin(lam));
  3272. y = this.a * (Math.atan2(Math.tan(phi), Math.cos(lam)) - this.lat0);
  3273. }
  3274. else {
  3275. //ellipsoid
  3276. var sinphi = Math.sin(phi);
  3277. var cosphi = Math.cos(phi);
  3278. var nl = gN(this.a, this.e, sinphi);
  3279. var tl = Math.tan(phi) * Math.tan(phi);
  3280. var al = lam * Math.cos(phi);
  3281. var asq = al * al;
  3282. var cl = this.es * cosphi * cosphi / (1 - this.es);
  3283. var ml = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, phi);
  3284. x = nl * al * (1 - asq * tl * (1 / 6 - (8 - tl + 8 * cl) * asq / 120));
  3285. y = ml - this.ml0 + nl * sinphi / cosphi * asq * (0.5 + (5 - tl + 6 * cl) * asq / 24);
  3286. }
  3287. p.x = x + this.x0;
  3288. p.y = y + this.y0;
  3289. return p;
  3290. }
  3291. /* Inverse equations
  3292. -----------------*/
  3293. function inverse$11(p) {
  3294. p.x -= this.x0;
  3295. p.y -= this.y0;
  3296. var x = p.x / this.a;
  3297. var y = p.y / this.a;
  3298. var phi, lam;
  3299. if (this.sphere) {
  3300. var dd = y + this.lat0;
  3301. phi = Math.asin(Math.sin(dd) * Math.cos(x));
  3302. lam = Math.atan2(Math.tan(x), Math.cos(dd));
  3303. }
  3304. else {
  3305. /* ellipsoid */
  3306. var ml1 = this.ml0 / this.a + y;
  3307. var phi1 = imlfn(ml1, this.e0, this.e1, this.e2, this.e3);
  3308. if (Math.abs(Math.abs(phi1) - HALF_PI) <= EPSLN) {
  3309. p.x = this.long0;
  3310. p.y = HALF_PI;
  3311. if (y < 0) {
  3312. p.y *= -1;
  3313. }
  3314. return p;
  3315. }
  3316. var nl1 = gN(this.a, this.e, Math.sin(phi1));
  3317. var rl1 = nl1 * nl1 * nl1 / this.a / this.a * (1 - this.es);
  3318. var tl1 = Math.pow(Math.tan(phi1), 2);
  3319. var dl = x * this.a / nl1;
  3320. var dsq = dl * dl;
  3321. phi = phi1 - nl1 * Math.tan(phi1) / rl1 * dl * dl * (0.5 - (1 + 3 * tl1) * dl * dl / 24);
  3322. lam = dl * (1 - dsq * (tl1 / 3 + (1 + 3 * tl1) * tl1 * dsq / 15)) / Math.cos(phi1);
  3323. }
  3324. p.x = adjust_lon(lam + this.long0);
  3325. p.y = adjust_lat(phi);
  3326. return p;
  3327. }
  3328. var names$13 = ["Cassini", "Cassini_Soldner", "cass"];
  3329. var cass = {
  3330. init: init$12,
  3331. forward: forward$11,
  3332. inverse: inverse$11,
  3333. names: names$13
  3334. };
  3335. var qsfnz = function(eccent, sinphi) {
  3336. var con;
  3337. if (eccent > 1.0e-7) {
  3338. con = eccent * sinphi;
  3339. return ((1 - eccent * eccent) * (sinphi / (1 - con * con) - (0.5 / eccent) * Math.log((1 - con) / (1 + con))));
  3340. }
  3341. else {
  3342. return (2 * sinphi);
  3343. }
  3344. };
  3345. /*
  3346. reference
  3347. "New Equal-Area Map Projections for Noncircular Regions", John P. Snyder,
  3348. The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355.
  3349. */
  3350. var S_POLE = 1;
  3351. var N_POLE = 2;
  3352. var EQUIT = 3;
  3353. var OBLIQ = 4;
  3354. /* Initialize the Lambert Azimuthal Equal Area projection
  3355. ------------------------------------------------------*/
  3356. function init$13() {
  3357. var t = Math.abs(this.lat0);
  3358. if (Math.abs(t - HALF_PI) < EPSLN) {
  3359. this.mode = this.lat0 < 0 ? this.S_POLE : this.N_POLE;
  3360. }
  3361. else if (Math.abs(t) < EPSLN) {
  3362. this.mode = this.EQUIT;
  3363. }
  3364. else {
  3365. this.mode = this.OBLIQ;
  3366. }
  3367. if (this.es > 0) {
  3368. var sinphi;
  3369. this.qp = qsfnz(this.e, 1);
  3370. this.mmf = 0.5 / (1 - this.es);
  3371. this.apa = authset(this.es);
  3372. switch (this.mode) {
  3373. case this.N_POLE:
  3374. this.dd = 1;
  3375. break;
  3376. case this.S_POLE:
  3377. this.dd = 1;
  3378. break;
  3379. case this.EQUIT:
  3380. this.rq = Math.sqrt(0.5 * this.qp);
  3381. this.dd = 1 / this.rq;
  3382. this.xmf = 1;
  3383. this.ymf = 0.5 * this.qp;
  3384. break;
  3385. case this.OBLIQ:
  3386. this.rq = Math.sqrt(0.5 * this.qp);
  3387. sinphi = Math.sin(this.lat0);
  3388. this.sinb1 = qsfnz(this.e, sinphi) / this.qp;
  3389. this.cosb1 = Math.sqrt(1 - this.sinb1 * this.sinb1);
  3390. this.dd = Math.cos(this.lat0) / (Math.sqrt(1 - this.es * sinphi * sinphi) * this.rq * this.cosb1);
  3391. this.ymf = (this.xmf = this.rq) / this.dd;
  3392. this.xmf *= this.dd;
  3393. break;
  3394. }
  3395. }
  3396. else {
  3397. if (this.mode === this.OBLIQ) {
  3398. this.sinph0 = Math.sin(this.lat0);
  3399. this.cosph0 = Math.cos(this.lat0);
  3400. }
  3401. }
  3402. }
  3403. /* Lambert Azimuthal Equal Area forward equations--mapping lat,long to x,y
  3404. -----------------------------------------------------------------------*/
  3405. function forward$12(p) {
  3406. /* Forward equations
  3407. -----------------*/
  3408. var x, y, coslam, sinlam, sinphi, q, sinb, cosb, b, cosphi;
  3409. var lam = p.x;
  3410. var phi = p.y;
  3411. lam = adjust_lon(lam - this.long0);
  3412. if (this.sphere) {
  3413. sinphi = Math.sin(phi);
  3414. cosphi = Math.cos(phi);
  3415. coslam = Math.cos(lam);
  3416. if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
  3417. y = (this.mode === this.EQUIT) ? 1 + cosphi * coslam : 1 + this.sinph0 * sinphi + this.cosph0 * cosphi * coslam;
  3418. if (y <= EPSLN) {
  3419. return null;
  3420. }
  3421. y = Math.sqrt(2 / y);
  3422. x = y * cosphi * Math.sin(lam);
  3423. y *= (this.mode === this.EQUIT) ? sinphi : this.cosph0 * sinphi - this.sinph0 * cosphi * coslam;
  3424. }
  3425. else if (this.mode === this.N_POLE || this.mode === this.S_POLE) {
  3426. if (this.mode === this.N_POLE) {
  3427. coslam = -coslam;
  3428. }
  3429. if (Math.abs(phi + this.lat0) < EPSLN) {
  3430. return null;
  3431. }
  3432. y = FORTPI - phi * 0.5;
  3433. y = 2 * ((this.mode === this.S_POLE) ? Math.cos(y) : Math.sin(y));
  3434. x = y * Math.sin(lam);
  3435. y *= coslam;
  3436. }
  3437. }
  3438. else {
  3439. sinb = 0;
  3440. cosb = 0;
  3441. b = 0;
  3442. coslam = Math.cos(lam);
  3443. sinlam = Math.sin(lam);
  3444. sinphi = Math.sin(phi);
  3445. q = qsfnz(this.e, sinphi);
  3446. if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
  3447. sinb = q / this.qp;
  3448. cosb = Math.sqrt(1 - sinb * sinb);
  3449. }
  3450. switch (this.mode) {
  3451. case this.OBLIQ:
  3452. b = 1 + this.sinb1 * sinb + this.cosb1 * cosb * coslam;
  3453. break;
  3454. case this.EQUIT:
  3455. b = 1 + cosb * coslam;
  3456. break;
  3457. case this.N_POLE:
  3458. b = HALF_PI + phi;
  3459. q = this.qp - q;
  3460. break;
  3461. case this.S_POLE:
  3462. b = phi - HALF_PI;
  3463. q = this.qp + q;
  3464. break;
  3465. }
  3466. if (Math.abs(b) < EPSLN) {
  3467. return null;
  3468. }
  3469. switch (this.mode) {
  3470. case this.OBLIQ:
  3471. case this.EQUIT:
  3472. b = Math.sqrt(2 / b);
  3473. if (this.mode === this.OBLIQ) {
  3474. y = this.ymf * b * (this.cosb1 * sinb - this.sinb1 * cosb * coslam);
  3475. }
  3476. else {
  3477. y = (b = Math.sqrt(2 / (1 + cosb * coslam))) * sinb * this.ymf;
  3478. }
  3479. x = this.xmf * b * cosb * sinlam;
  3480. break;
  3481. case this.N_POLE:
  3482. case this.S_POLE:
  3483. if (q >= 0) {
  3484. x = (b = Math.sqrt(q)) * sinlam;
  3485. y = coslam * ((this.mode === this.S_POLE) ? b : -b);
  3486. }
  3487. else {
  3488. x = y = 0;
  3489. }
  3490. break;
  3491. }
  3492. }
  3493. p.x = this.a * x + this.x0;
  3494. p.y = this.a * y + this.y0;
  3495. return p;
  3496. }
  3497. /* Inverse equations
  3498. -----------------*/
  3499. function inverse$12(p) {
  3500. p.x -= this.x0;
  3501. p.y -= this.y0;
  3502. var x = p.x / this.a;
  3503. var y = p.y / this.a;
  3504. var lam, phi, cCe, sCe, q, rho, ab;
  3505. if (this.sphere) {
  3506. var cosz = 0,
  3507. rh, sinz = 0;
  3508. rh = Math.sqrt(x * x + y * y);
  3509. phi = rh * 0.5;
  3510. if (phi > 1) {
  3511. return null;
  3512. }
  3513. phi = 2 * Math.asin(phi);
  3514. if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
  3515. sinz = Math.sin(phi);
  3516. cosz = Math.cos(phi);
  3517. }
  3518. switch (this.mode) {
  3519. case this.EQUIT:
  3520. phi = (Math.abs(rh) <= EPSLN) ? 0 : Math.asin(y * sinz / rh);
  3521. x *= sinz;
  3522. y = cosz * rh;
  3523. break;
  3524. case this.OBLIQ:
  3525. phi = (Math.abs(rh) <= EPSLN) ? this.lat0 : Math.asin(cosz * this.sinph0 + y * sinz * this.cosph0 / rh);
  3526. x *= sinz * this.cosph0;
  3527. y = (cosz - Math.sin(phi) * this.sinph0) * rh;
  3528. break;
  3529. case this.N_POLE:
  3530. y = -y;
  3531. phi = HALF_PI - phi;
  3532. break;
  3533. case this.S_POLE:
  3534. phi -= HALF_PI;
  3535. break;
  3536. }
  3537. lam = (y === 0 && (this.mode === this.EQUIT || this.mode === this.OBLIQ)) ? 0 : Math.atan2(x, y);
  3538. }
  3539. else {
  3540. ab = 0;
  3541. if (this.mode === this.OBLIQ || this.mode === this.EQUIT) {
  3542. x /= this.dd;
  3543. y *= this.dd;
  3544. rho = Math.sqrt(x * x + y * y);
  3545. if (rho < EPSLN) {
  3546. p.x = this.long0;
  3547. p.y = this.lat0;
  3548. return p;
  3549. }
  3550. sCe = 2 * Math.asin(0.5 * rho / this.rq);
  3551. cCe = Math.cos(sCe);
  3552. x *= (sCe = Math.sin(sCe));
  3553. if (this.mode === this.OBLIQ) {
  3554. ab = cCe * this.sinb1 + y * sCe * this.cosb1 / rho;
  3555. q = this.qp * ab;
  3556. y = rho * this.cosb1 * cCe - y * this.sinb1 * sCe;
  3557. }
  3558. else {
  3559. ab = y * sCe / rho;
  3560. q = this.qp * ab;
  3561. y = rho * cCe;
  3562. }
  3563. }
  3564. else if (this.mode === this.N_POLE || this.mode === this.S_POLE) {
  3565. if (this.mode === this.N_POLE) {
  3566. y = -y;
  3567. }
  3568. q = (x * x + y * y);
  3569. if (!q) {
  3570. p.x = this.long0;
  3571. p.y = this.lat0;
  3572. return p;
  3573. }
  3574. ab = 1 - q / this.qp;
  3575. if (this.mode === this.S_POLE) {
  3576. ab = -ab;
  3577. }
  3578. }
  3579. lam = Math.atan2(x, y);
  3580. phi = authlat(Math.asin(ab), this.apa);
  3581. }
  3582. p.x = adjust_lon(this.long0 + lam);
  3583. p.y = phi;
  3584. return p;
  3585. }
  3586. /* determine latitude from authalic latitude */
  3587. var P00 = 0.33333333333333333333;
  3588. var P01 = 0.17222222222222222222;
  3589. var P02 = 0.10257936507936507936;
  3590. var P10 = 0.06388888888888888888;
  3591. var P11 = 0.06640211640211640211;
  3592. var P20 = 0.01641501294219154443;
  3593. function authset(es) {
  3594. var t;
  3595. var APA = [];
  3596. APA[0] = es * P00;
  3597. t = es * es;
  3598. APA[0] += t * P01;
  3599. APA[1] = t * P10;
  3600. t *= es;
  3601. APA[0] += t * P02;
  3602. APA[1] += t * P11;
  3603. APA[2] = t * P20;
  3604. return APA;
  3605. }
  3606. function authlat(beta, APA) {
  3607. var t = beta + beta;
  3608. return (beta + APA[0] * Math.sin(t) + APA[1] * Math.sin(t + t) + APA[2] * Math.sin(t + t + t));
  3609. }
  3610. var names$14 = ["Lambert Azimuthal Equal Area", "Lambert_Azimuthal_Equal_Area", "laea"];
  3611. var laea = {
  3612. init: init$13,
  3613. forward: forward$12,
  3614. inverse: inverse$12,
  3615. names: names$14,
  3616. S_POLE: S_POLE,
  3617. N_POLE: N_POLE,
  3618. EQUIT: EQUIT,
  3619. OBLIQ: OBLIQ
  3620. };
  3621. var asinz = function(x) {
  3622. if (Math.abs(x) > 1) {
  3623. x = (x > 1) ? 1 : -1;
  3624. }
  3625. return Math.asin(x);
  3626. };
  3627. function init$14() {
  3628. if (Math.abs(this.lat1 + this.lat2) < EPSLN) {
  3629. return;
  3630. }
  3631. this.temp = this.b / this.a;
  3632. this.es = 1 - Math.pow(this.temp, 2);
  3633. this.e3 = Math.sqrt(this.es);
  3634. this.sin_po = Math.sin(this.lat1);
  3635. this.cos_po = Math.cos(this.lat1);
  3636. this.t1 = this.sin_po;
  3637. this.con = this.sin_po;
  3638. this.ms1 = msfnz(this.e3, this.sin_po, this.cos_po);
  3639. this.qs1 = qsfnz(this.e3, this.sin_po, this.cos_po);
  3640. this.sin_po = Math.sin(this.lat2);
  3641. this.cos_po = Math.cos(this.lat2);
  3642. this.t2 = this.sin_po;
  3643. this.ms2 = msfnz(this.e3, this.sin_po, this.cos_po);
  3644. this.qs2 = qsfnz(this.e3, this.sin_po, this.cos_po);
  3645. this.sin_po = Math.sin(this.lat0);
  3646. this.cos_po = Math.cos(this.lat0);
  3647. this.t3 = this.sin_po;
  3648. this.qs0 = qsfnz(this.e3, this.sin_po, this.cos_po);
  3649. if (Math.abs(this.lat1 - this.lat2) > EPSLN) {
  3650. this.ns0 = (this.ms1 * this.ms1 - this.ms2 * this.ms2) / (this.qs2 - this.qs1);
  3651. }
  3652. else {
  3653. this.ns0 = this.con;
  3654. }
  3655. this.c = this.ms1 * this.ms1 + this.ns0 * this.qs1;
  3656. this.rh = this.a * Math.sqrt(this.c - this.ns0 * this.qs0) / this.ns0;
  3657. }
  3658. /* Albers Conical Equal Area forward equations--mapping lat,long to x,y
  3659. -------------------------------------------------------------------*/
  3660. function forward$13(p) {
  3661. var lon = p.x;
  3662. var lat = p.y;
  3663. this.sin_phi = Math.sin(lat);
  3664. this.cos_phi = Math.cos(lat);
  3665. var qs = qsfnz(this.e3, this.sin_phi, this.cos_phi);
  3666. var rh1 = this.a * Math.sqrt(this.c - this.ns0 * qs) / this.ns0;
  3667. var theta = this.ns0 * adjust_lon(lon - this.long0);
  3668. var x = rh1 * Math.sin(theta) + this.x0;
  3669. var y = this.rh - rh1 * Math.cos(theta) + this.y0;
  3670. p.x = x;
  3671. p.y = y;
  3672. return p;
  3673. }
  3674. function inverse$13(p) {
  3675. var rh1, qs, con, theta, lon, lat;
  3676. p.x -= this.x0;
  3677. p.y = this.rh - p.y + this.y0;
  3678. if (this.ns0 >= 0) {
  3679. rh1 = Math.sqrt(p.x * p.x + p.y * p.y);
  3680. con = 1;
  3681. }
  3682. else {
  3683. rh1 = -Math.sqrt(p.x * p.x + p.y * p.y);
  3684. con = -1;
  3685. }
  3686. theta = 0;
  3687. if (rh1 !== 0) {
  3688. theta = Math.atan2(con * p.x, con * p.y);
  3689. }
  3690. con = rh1 * this.ns0 / this.a;
  3691. if (this.sphere) {
  3692. lat = Math.asin((this.c - con * con) / (2 * this.ns0));
  3693. }
  3694. else {
  3695. qs = (this.c - con * con) / this.ns0;
  3696. lat = this.phi1z(this.e3, qs);
  3697. }
  3698. lon = adjust_lon(theta / this.ns0 + this.long0);
  3699. p.x = lon;
  3700. p.y = lat;
  3701. return p;
  3702. }
  3703. /* Function to compute phi1, the latitude for the inverse of the
  3704. Albers Conical Equal-Area projection.
  3705. -------------------------------------------*/
  3706. function phi1z(eccent, qs) {
  3707. var sinphi, cosphi, con, com, dphi;
  3708. var phi = asinz(0.5 * qs);
  3709. if (eccent < EPSLN) {
  3710. return phi;
  3711. }
  3712. var eccnts = eccent * eccent;
  3713. for (var i = 1; i <= 25; i++) {
  3714. sinphi = Math.sin(phi);
  3715. cosphi = Math.cos(phi);
  3716. con = eccent * sinphi;
  3717. com = 1 - con * con;
  3718. dphi = 0.5 * com * com / cosphi * (qs / (1 - eccnts) - sinphi / com + 0.5 / eccent * Math.log((1 - con) / (1 + con)));
  3719. phi = phi + dphi;
  3720. if (Math.abs(dphi) <= 1e-7) {
  3721. return phi;
  3722. }
  3723. }
  3724. return null;
  3725. }
  3726. var names$15 = ["Albers_Conic_Equal_Area", "Albers", "aea"];
  3727. var aea = {
  3728. init: init$14,
  3729. forward: forward$13,
  3730. inverse: inverse$13,
  3731. names: names$15,
  3732. phi1z: phi1z
  3733. };
  3734. /*
  3735. reference:
  3736. Wolfram Mathworld "Gnomonic Projection"
  3737. http://mathworld.wolfram.com/GnomonicProjection.html
  3738. Accessed: 12th November 2009
  3739. */
  3740. function init$15() {
  3741. /* Place parameters in static storage for common use
  3742. -------------------------------------------------*/
  3743. this.sin_p14 = Math.sin(this.lat0);
  3744. this.cos_p14 = Math.cos(this.lat0);
  3745. // Approximation for projecting points to the horizon (infinity)
  3746. this.infinity_dist = 1000 * this.a;
  3747. this.rc = 1;
  3748. }
  3749. /* Gnomonic forward equations--mapping lat,long to x,y
  3750. ---------------------------------------------------*/
  3751. function forward$14(p) {
  3752. var sinphi, cosphi; /* sin and cos value */
  3753. var dlon; /* delta longitude value */
  3754. var coslon; /* cos of longitude */
  3755. var ksp; /* scale factor */
  3756. var g;
  3757. var x, y;
  3758. var lon = p.x;
  3759. var lat = p.y;
  3760. /* Forward equations
  3761. -----------------*/
  3762. dlon = adjust_lon(lon - this.long0);
  3763. sinphi = Math.sin(lat);
  3764. cosphi = Math.cos(lat);
  3765. coslon = Math.cos(dlon);
  3766. g = this.sin_p14 * sinphi + this.cos_p14 * cosphi * coslon;
  3767. ksp = 1;
  3768. if ((g > 0) || (Math.abs(g) <= EPSLN)) {
  3769. x = this.x0 + this.a * ksp * cosphi * Math.sin(dlon) / g;
  3770. y = this.y0 + this.a * ksp * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon) / g;
  3771. }
  3772. else {
  3773. // Point is in the opposing hemisphere and is unprojectable
  3774. // We still need to return a reasonable point, so we project
  3775. // to infinity, on a bearing
  3776. // equivalent to the northern hemisphere equivalent
  3777. // This is a reasonable approximation for short shapes and lines that
  3778. // straddle the horizon.
  3779. x = this.x0 + this.infinity_dist * cosphi * Math.sin(dlon);
  3780. y = this.y0 + this.infinity_dist * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon);
  3781. }
  3782. p.x = x;
  3783. p.y = y;
  3784. return p;
  3785. }
  3786. function inverse$14(p) {
  3787. var rh; /* Rho */
  3788. var sinc, cosc;
  3789. var c;
  3790. var lon, lat;
  3791. /* Inverse equations
  3792. -----------------*/
  3793. p.x = (p.x - this.x0) / this.a;
  3794. p.y = (p.y - this.y0) / this.a;
  3795. p.x /= this.k0;
  3796. p.y /= this.k0;
  3797. if ((rh = Math.sqrt(p.x * p.x + p.y * p.y))) {
  3798. c = Math.atan2(rh, this.rc);
  3799. sinc = Math.sin(c);
  3800. cosc = Math.cos(c);
  3801. lat = asinz(cosc * this.sin_p14 + (p.y * sinc * this.cos_p14) / rh);
  3802. lon = Math.atan2(p.x * sinc, rh * this.cos_p14 * cosc - p.y * this.sin_p14 * sinc);
  3803. lon = adjust_lon(this.long0 + lon);
  3804. }
  3805. else {
  3806. lat = this.phic0;
  3807. lon = 0;
  3808. }
  3809. p.x = lon;
  3810. p.y = lat;
  3811. return p;
  3812. }
  3813. var names$16 = ["gnom"];
  3814. var gnom = {
  3815. init: init$15,
  3816. forward: forward$14,
  3817. inverse: inverse$14,
  3818. names: names$16
  3819. };
  3820. var iqsfnz = function(eccent, q) {
  3821. var temp = 1 - (1 - eccent * eccent) / (2 * eccent) * Math.log((1 - eccent) / (1 + eccent));
  3822. if (Math.abs(Math.abs(q) - temp) < 1.0E-6) {
  3823. if (q < 0) {
  3824. return (-1 * HALF_PI);
  3825. }
  3826. else {
  3827. return HALF_PI;
  3828. }
  3829. }
  3830. //var phi = 0.5* q/(1-eccent*eccent);
  3831. var phi = Math.asin(0.5 * q);
  3832. var dphi;
  3833. var sin_phi;
  3834. var cos_phi;
  3835. var con;
  3836. for (var i = 0; i < 30; i++) {
  3837. sin_phi = Math.sin(phi);
  3838. cos_phi = Math.cos(phi);
  3839. con = eccent * sin_phi;
  3840. dphi = Math.pow(1 - con * con, 2) / (2 * cos_phi) * (q / (1 - eccent * eccent) - sin_phi / (1 - con * con) + 0.5 / eccent * Math.log((1 - con) / (1 + con)));
  3841. phi += dphi;
  3842. if (Math.abs(dphi) <= 0.0000000001) {
  3843. return phi;
  3844. }
  3845. }
  3846. //console.log("IQSFN-CONV:Latitude failed to converge after 30 iterations");
  3847. return NaN;
  3848. };
  3849. /*
  3850. reference:
  3851. "Cartographic Projection Procedures for the UNIX Environment-
  3852. A User's Manual" by Gerald I. Evenden,
  3853. USGS Open File Report 90-284and Release 4 Interim Reports (2003)
  3854. */
  3855. function init$16() {
  3856. //no-op
  3857. if (!this.sphere) {
  3858. this.k0 = msfnz(this.e, Math.sin(this.lat_ts), Math.cos(this.lat_ts));
  3859. }
  3860. }
  3861. /* Cylindrical Equal Area forward equations--mapping lat,long to x,y
  3862. ------------------------------------------------------------*/
  3863. function forward$15(p) {
  3864. var lon = p.x;
  3865. var lat = p.y;
  3866. var x, y;
  3867. /* Forward equations
  3868. -----------------*/
  3869. var dlon = adjust_lon(lon - this.long0);
  3870. if (this.sphere) {
  3871. x = this.x0 + this.a * dlon * Math.cos(this.lat_ts);
  3872. y = this.y0 + this.a * Math.sin(lat) / Math.cos(this.lat_ts);
  3873. }
  3874. else {
  3875. var qs = qsfnz(this.e, Math.sin(lat));
  3876. x = this.x0 + this.a * this.k0 * dlon;
  3877. y = this.y0 + this.a * qs * 0.5 / this.k0;
  3878. }
  3879. p.x = x;
  3880. p.y = y;
  3881. return p;
  3882. }
  3883. /* Cylindrical Equal Area inverse equations--mapping x,y to lat/long
  3884. ------------------------------------------------------------*/
  3885. function inverse$15(p) {
  3886. p.x -= this.x0;
  3887. p.y -= this.y0;
  3888. var lon, lat;
  3889. if (this.sphere) {
  3890. lon = adjust_lon(this.long0 + (p.x / this.a) / Math.cos(this.lat_ts));
  3891. lat = Math.asin((p.y / this.a) * Math.cos(this.lat_ts));
  3892. }
  3893. else {
  3894. lat = iqsfnz(this.e, 2 * p.y * this.k0 / this.a);
  3895. lon = adjust_lon(this.long0 + p.x / (this.a * this.k0));
  3896. }
  3897. p.x = lon;
  3898. p.y = lat;
  3899. return p;
  3900. }
  3901. var names$17 = ["cea"];
  3902. var cea = {
  3903. init: init$16,
  3904. forward: forward$15,
  3905. inverse: inverse$15,
  3906. names: names$17
  3907. };
  3908. function init$17() {
  3909. this.x0 = this.x0 || 0;
  3910. this.y0 = this.y0 || 0;
  3911. this.lat0 = this.lat0 || 0;
  3912. this.long0 = this.long0 || 0;
  3913. this.lat_ts = this.lat_ts || 0;
  3914. this.title = this.title || "Equidistant Cylindrical (Plate Carre)";
  3915. this.rc = Math.cos(this.lat_ts);
  3916. }
  3917. // forward equations--mapping lat,long to x,y
  3918. // -----------------------------------------------------------------
  3919. function forward$16(p) {
  3920. var lon = p.x;
  3921. var lat = p.y;
  3922. var dlon = adjust_lon(lon - this.long0);
  3923. var dlat = adjust_lat(lat - this.lat0);
  3924. p.x = this.x0 + (this.a * dlon * this.rc);
  3925. p.y = this.y0 + (this.a * dlat);
  3926. return p;
  3927. }
  3928. // inverse equations--mapping x,y to lat/long
  3929. // -----------------------------------------------------------------
  3930. function inverse$16(p) {
  3931. var x = p.x;
  3932. var y = p.y;
  3933. p.x = adjust_lon(this.long0 + ((x - this.x0) / (this.a * this.rc)));
  3934. p.y = adjust_lat(this.lat0 + ((y - this.y0) / (this.a)));
  3935. return p;
  3936. }
  3937. var names$18 = ["Equirectangular", "Equidistant_Cylindrical", "eqc"];
  3938. var eqc = {
  3939. init: init$17,
  3940. forward: forward$16,
  3941. inverse: inverse$16,
  3942. names: names$18
  3943. };
  3944. var MAX_ITER$2 = 20;
  3945. function init$18() {
  3946. /* Place parameters in static storage for common use
  3947. -------------------------------------------------*/
  3948. this.temp = this.b / this.a;
  3949. this.es = 1 - Math.pow(this.temp, 2); // devait etre dans tmerc.js mais n y est pas donc je commente sinon retour de valeurs nulles
  3950. this.e = Math.sqrt(this.es);
  3951. this.e0 = e0fn(this.es);
  3952. this.e1 = e1fn(this.es);
  3953. this.e2 = e2fn(this.es);
  3954. this.e3 = e3fn(this.es);
  3955. this.ml0 = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0); //si que des zeros le calcul ne se fait pas
  3956. }
  3957. /* Polyconic forward equations--mapping lat,long to x,y
  3958. ---------------------------------------------------*/
  3959. function forward$17(p) {
  3960. var lon = p.x;
  3961. var lat = p.y;
  3962. var x, y, el;
  3963. var dlon = adjust_lon(lon - this.long0);
  3964. el = dlon * Math.sin(lat);
  3965. if (this.sphere) {
  3966. if (Math.abs(lat) <= EPSLN) {
  3967. x = this.a * dlon;
  3968. y = -1 * this.a * this.lat0;
  3969. }
  3970. else {
  3971. x = this.a * Math.sin(el) / Math.tan(lat);
  3972. y = this.a * (adjust_lat(lat - this.lat0) + (1 - Math.cos(el)) / Math.tan(lat));
  3973. }
  3974. }
  3975. else {
  3976. if (Math.abs(lat) <= EPSLN) {
  3977. x = this.a * dlon;
  3978. y = -1 * this.ml0;
  3979. }
  3980. else {
  3981. var nl = gN(this.a, this.e, Math.sin(lat)) / Math.tan(lat);
  3982. x = nl * Math.sin(el);
  3983. y = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, lat) - this.ml0 + nl * (1 - Math.cos(el));
  3984. }
  3985. }
  3986. p.x = x + this.x0;
  3987. p.y = y + this.y0;
  3988. return p;
  3989. }
  3990. /* Inverse equations
  3991. -----------------*/
  3992. function inverse$17(p) {
  3993. var lon, lat, x, y, i;
  3994. var al, bl;
  3995. var phi, dphi;
  3996. x = p.x - this.x0;
  3997. y = p.y - this.y0;
  3998. if (this.sphere) {
  3999. if (Math.abs(y + this.a * this.lat0) <= EPSLN) {
  4000. lon = adjust_lon(x / this.a + this.long0);
  4001. lat = 0;
  4002. }
  4003. else {
  4004. al = this.lat0 + y / this.a;
  4005. bl = x * x / this.a / this.a + al * al;
  4006. phi = al;
  4007. var tanphi;
  4008. for (i = MAX_ITER$2; i; --i) {
  4009. tanphi = Math.tan(phi);
  4010. dphi = -1 * (al * (phi * tanphi + 1) - phi - 0.5 * (phi * phi + bl) * tanphi) / ((phi - al) / tanphi - 1);
  4011. phi += dphi;
  4012. if (Math.abs(dphi) <= EPSLN) {
  4013. lat = phi;
  4014. break;
  4015. }
  4016. }
  4017. lon = adjust_lon(this.long0 + (Math.asin(x * Math.tan(phi) / this.a)) / Math.sin(lat));
  4018. }
  4019. }
  4020. else {
  4021. if (Math.abs(y + this.ml0) <= EPSLN) {
  4022. lat = 0;
  4023. lon = adjust_lon(this.long0 + x / this.a);
  4024. }
  4025. else {
  4026. al = (this.ml0 + y) / this.a;
  4027. bl = x * x / this.a / this.a + al * al;
  4028. phi = al;
  4029. var cl, mln, mlnp, ma;
  4030. var con;
  4031. for (i = MAX_ITER$2; i; --i) {
  4032. con = this.e * Math.sin(phi);
  4033. cl = Math.sqrt(1 - con * con) * Math.tan(phi);
  4034. mln = this.a * mlfn(this.e0, this.e1, this.e2, this.e3, phi);
  4035. mlnp = this.e0 - 2 * this.e1 * Math.cos(2 * phi) + 4 * this.e2 * Math.cos(4 * phi) - 6 * this.e3 * Math.cos(6 * phi);
  4036. ma = mln / this.a;
  4037. dphi = (al * (cl * ma + 1) - ma - 0.5 * cl * (ma * ma + bl)) / (this.es * Math.sin(2 * phi) * (ma * ma + bl - 2 * al * ma) / (4 * cl) + (al - ma) * (cl * mlnp - 2 / Math.sin(2 * phi)) - mlnp);
  4038. phi -= dphi;
  4039. if (Math.abs(dphi) <= EPSLN) {
  4040. lat = phi;
  4041. break;
  4042. }
  4043. }
  4044. //lat=phi4z(this.e,this.e0,this.e1,this.e2,this.e3,al,bl,0,0);
  4045. cl = Math.sqrt(1 - this.es * Math.pow(Math.sin(lat), 2)) * Math.tan(lat);
  4046. lon = adjust_lon(this.long0 + Math.asin(x * cl / this.a) / Math.sin(lat));
  4047. }
  4048. }
  4049. p.x = lon;
  4050. p.y = lat;
  4051. return p;
  4052. }
  4053. var names$19 = ["Polyconic", "poly"];
  4054. var poly = {
  4055. init: init$18,
  4056. forward: forward$17,
  4057. inverse: inverse$17,
  4058. names: names$19
  4059. };
  4060. /*
  4061. reference
  4062. Department of Land and Survey Technical Circular 1973/32
  4063. http://www.linz.govt.nz/docs/miscellaneous/nz-map-definition.pdf
  4064. OSG Technical Report 4.1
  4065. http://www.linz.govt.nz/docs/miscellaneous/nzmg.pdf
  4066. */
  4067. /**
  4068. * iterations: Number of iterations to refine inverse transform.
  4069. * 0 -> km accuracy
  4070. * 1 -> m accuracy -- suitable for most mapping applications
  4071. * 2 -> mm accuracy
  4072. */
  4073. function init$19() {
  4074. this.A = [];
  4075. this.A[1] = 0.6399175073;
  4076. this.A[2] = -0.1358797613;
  4077. this.A[3] = 0.063294409;
  4078. this.A[4] = -0.02526853;
  4079. this.A[5] = 0.0117879;
  4080. this.A[6] = -0.0055161;
  4081. this.A[7] = 0.0026906;
  4082. this.A[8] = -0.001333;
  4083. this.A[9] = 0.00067;
  4084. this.A[10] = -0.00034;
  4085. this.B_re = [];
  4086. this.B_im = [];
  4087. this.B_re[1] = 0.7557853228;
  4088. this.B_im[1] = 0;
  4089. this.B_re[2] = 0.249204646;
  4090. this.B_im[2] = 0.003371507;
  4091. this.B_re[3] = -0.001541739;
  4092. this.B_im[3] = 0.041058560;
  4093. this.B_re[4] = -0.10162907;
  4094. this.B_im[4] = 0.01727609;
  4095. this.B_re[5] = -0.26623489;
  4096. this.B_im[5] = -0.36249218;
  4097. this.B_re[6] = -0.6870983;
  4098. this.B_im[6] = -1.1651967;
  4099. this.C_re = [];
  4100. this.C_im = [];
  4101. this.C_re[1] = 1.3231270439;
  4102. this.C_im[1] = 0;
  4103. this.C_re[2] = -0.577245789;
  4104. this.C_im[2] = -0.007809598;
  4105. this.C_re[3] = 0.508307513;
  4106. this.C_im[3] = -0.112208952;
  4107. this.C_re[4] = -0.15094762;
  4108. this.C_im[4] = 0.18200602;
  4109. this.C_re[5] = 1.01418179;
  4110. this.C_im[5] = 1.64497696;
  4111. this.C_re[6] = 1.9660549;
  4112. this.C_im[6] = 2.5127645;
  4113. this.D = [];
  4114. this.D[1] = 1.5627014243;
  4115. this.D[2] = 0.5185406398;
  4116. this.D[3] = -0.03333098;
  4117. this.D[4] = -0.1052906;
  4118. this.D[5] = -0.0368594;
  4119. this.D[6] = 0.007317;
  4120. this.D[7] = 0.01220;
  4121. this.D[8] = 0.00394;
  4122. this.D[9] = -0.0013;
  4123. }
  4124. /**
  4125. New Zealand Map Grid Forward - long/lat to x/y
  4126. long/lat in radians
  4127. */
  4128. function forward$18(p) {
  4129. var n;
  4130. var lon = p.x;
  4131. var lat = p.y;
  4132. var delta_lat = lat - this.lat0;
  4133. var delta_lon = lon - this.long0;
  4134. // 1. Calculate d_phi and d_psi ... // and d_lambda
  4135. // For this algorithm, delta_latitude is in seconds of arc x 10-5, so we need to scale to those units. Longitude is radians.
  4136. var d_phi = delta_lat / SEC_TO_RAD * 1E-5;
  4137. var d_lambda = delta_lon;
  4138. var d_phi_n = 1; // d_phi^0
  4139. var d_psi = 0;
  4140. for (n = 1; n <= 10; n++) {
  4141. d_phi_n = d_phi_n * d_phi;
  4142. d_psi = d_psi + this.A[n] * d_phi_n;
  4143. }
  4144. // 2. Calculate theta
  4145. var th_re = d_psi;
  4146. var th_im = d_lambda;
  4147. // 3. Calculate z
  4148. var th_n_re = 1;
  4149. var th_n_im = 0; // theta^0
  4150. var th_n_re1;
  4151. var th_n_im1;
  4152. var z_re = 0;
  4153. var z_im = 0;
  4154. for (n = 1; n <= 6; n++) {
  4155. th_n_re1 = th_n_re * th_re - th_n_im * th_im;
  4156. th_n_im1 = th_n_im * th_re + th_n_re * th_im;
  4157. th_n_re = th_n_re1;
  4158. th_n_im = th_n_im1;
  4159. z_re = z_re + this.B_re[n] * th_n_re - this.B_im[n] * th_n_im;
  4160. z_im = z_im + this.B_im[n] * th_n_re + this.B_re[n] * th_n_im;
  4161. }
  4162. // 4. Calculate easting and northing
  4163. p.x = (z_im * this.a) + this.x0;
  4164. p.y = (z_re * this.a) + this.y0;
  4165. return p;
  4166. }
  4167. /**
  4168. New Zealand Map Grid Inverse - x/y to long/lat
  4169. */
  4170. function inverse$18(p) {
  4171. var n;
  4172. var x = p.x;
  4173. var y = p.y;
  4174. var delta_x = x - this.x0;
  4175. var delta_y = y - this.y0;
  4176. // 1. Calculate z
  4177. var z_re = delta_y / this.a;
  4178. var z_im = delta_x / this.a;
  4179. // 2a. Calculate theta - first approximation gives km accuracy
  4180. var z_n_re = 1;
  4181. var z_n_im = 0; // z^0
  4182. var z_n_re1;
  4183. var z_n_im1;
  4184. var th_re = 0;
  4185. var th_im = 0;
  4186. for (n = 1; n <= 6; n++) {
  4187. z_n_re1 = z_n_re * z_re - z_n_im * z_im;
  4188. z_n_im1 = z_n_im * z_re + z_n_re * z_im;
  4189. z_n_re = z_n_re1;
  4190. z_n_im = z_n_im1;
  4191. th_re = th_re + this.C_re[n] * z_n_re - this.C_im[n] * z_n_im;
  4192. th_im = th_im + this.C_im[n] * z_n_re + this.C_re[n] * z_n_im;
  4193. }
  4194. // 2b. Iterate to refine the accuracy of the calculation
  4195. // 0 iterations gives km accuracy
  4196. // 1 iteration gives m accuracy -- good enough for most mapping applications
  4197. // 2 iterations bives mm accuracy
  4198. for (var i = 0; i < this.iterations; i++) {
  4199. var th_n_re = th_re;
  4200. var th_n_im = th_im;
  4201. var th_n_re1;
  4202. var th_n_im1;
  4203. var num_re = z_re;
  4204. var num_im = z_im;
  4205. for (n = 2; n <= 6; n++) {
  4206. th_n_re1 = th_n_re * th_re - th_n_im * th_im;
  4207. th_n_im1 = th_n_im * th_re + th_n_re * th_im;
  4208. th_n_re = th_n_re1;
  4209. th_n_im = th_n_im1;
  4210. num_re = num_re + (n - 1) * (this.B_re[n] * th_n_re - this.B_im[n] * th_n_im);
  4211. num_im = num_im + (n - 1) * (this.B_im[n] * th_n_re + this.B_re[n] * th_n_im);
  4212. }
  4213. th_n_re = 1;
  4214. th_n_im = 0;
  4215. var den_re = this.B_re[1];
  4216. var den_im = this.B_im[1];
  4217. for (n = 2; n <= 6; n++) {
  4218. th_n_re1 = th_n_re * th_re - th_n_im * th_im;
  4219. th_n_im1 = th_n_im * th_re + th_n_re * th_im;
  4220. th_n_re = th_n_re1;
  4221. th_n_im = th_n_im1;
  4222. den_re = den_re + n * (this.B_re[n] * th_n_re - this.B_im[n] * th_n_im);
  4223. den_im = den_im + n * (this.B_im[n] * th_n_re + this.B_re[n] * th_n_im);
  4224. }
  4225. // Complex division
  4226. var den2 = den_re * den_re + den_im * den_im;
  4227. th_re = (num_re * den_re + num_im * den_im) / den2;
  4228. th_im = (num_im * den_re - num_re * den_im) / den2;
  4229. }
  4230. // 3. Calculate d_phi ... // and d_lambda
  4231. var d_psi = th_re;
  4232. var d_lambda = th_im;
  4233. var d_psi_n = 1; // d_psi^0
  4234. var d_phi = 0;
  4235. for (n = 1; n <= 9; n++) {
  4236. d_psi_n = d_psi_n * d_psi;
  4237. d_phi = d_phi + this.D[n] * d_psi_n;
  4238. }
  4239. // 4. Calculate latitude and longitude
  4240. // d_phi is calcuated in second of arc * 10^-5, so we need to scale back to radians. d_lambda is in radians.
  4241. var lat = this.lat0 + (d_phi * SEC_TO_RAD * 1E5);
  4242. var lon = this.long0 + d_lambda;
  4243. p.x = lon;
  4244. p.y = lat;
  4245. return p;
  4246. }
  4247. var names$20 = ["New_Zealand_Map_Grid", "nzmg"];
  4248. var nzmg = {
  4249. init: init$19,
  4250. forward: forward$18,
  4251. inverse: inverse$18,
  4252. names: names$20
  4253. };
  4254. /*
  4255. reference
  4256. "New Equal-Area Map Projections for Noncircular Regions", John P. Snyder,
  4257. The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355.
  4258. */
  4259. /* Initialize the Miller Cylindrical projection
  4260. -------------------------------------------*/
  4261. function init$20() {
  4262. //no-op
  4263. }
  4264. /* Miller Cylindrical forward equations--mapping lat,long to x,y
  4265. ------------------------------------------------------------*/
  4266. function forward$19(p) {
  4267. var lon = p.x;
  4268. var lat = p.y;
  4269. /* Forward equations
  4270. -----------------*/
  4271. var dlon = adjust_lon(lon - this.long0);
  4272. var x = this.x0 + this.a * dlon;
  4273. var y = this.y0 + this.a * Math.log(Math.tan((Math.PI / 4) + (lat / 2.5))) * 1.25;
  4274. p.x = x;
  4275. p.y = y;
  4276. return p;
  4277. }
  4278. /* Miller Cylindrical inverse equations--mapping x,y to lat/long
  4279. ------------------------------------------------------------*/
  4280. function inverse$19(p) {
  4281. p.x -= this.x0;
  4282. p.y -= this.y0;
  4283. var lon = adjust_lon(this.long0 + p.x / this.a);
  4284. var lat = 2.5 * (Math.atan(Math.exp(0.8 * p.y / this.a)) - Math.PI / 4);
  4285. p.x = lon;
  4286. p.y = lat;
  4287. return p;
  4288. }
  4289. var names$21 = ["Miller_Cylindrical", "mill"];
  4290. var mill = {
  4291. init: init$20,
  4292. forward: forward$19,
  4293. inverse: inverse$19,
  4294. names: names$21
  4295. };
  4296. var MAX_ITER$3 = 20;
  4297. function init$21() {
  4298. /* Place parameters in static storage for common use
  4299. -------------------------------------------------*/
  4300. if (!this.sphere) {
  4301. this.en = pj_enfn(this.es);
  4302. }
  4303. else {
  4304. this.n = 1;
  4305. this.m = 0;
  4306. this.es = 0;
  4307. this.C_y = Math.sqrt((this.m + 1) / this.n);
  4308. this.C_x = this.C_y / (this.m + 1);
  4309. }
  4310. }
  4311. /* Sinusoidal forward equations--mapping lat,long to x,y
  4312. -----------------------------------------------------*/
  4313. function forward$20(p) {
  4314. var x, y;
  4315. var lon = p.x;
  4316. var lat = p.y;
  4317. /* Forward equations
  4318. -----------------*/
  4319. lon = adjust_lon(lon - this.long0);
  4320. if (this.sphere) {
  4321. if (!this.m) {
  4322. lat = this.n !== 1 ? Math.asin(this.n * Math.sin(lat)) : lat;
  4323. }
  4324. else {
  4325. var k = this.n * Math.sin(lat);
  4326. for (var i = MAX_ITER$3; i; --i) {
  4327. var V = (this.m * lat + Math.sin(lat) - k) / (this.m + Math.cos(lat));
  4328. lat -= V;
  4329. if (Math.abs(V) < EPSLN) {
  4330. break;
  4331. }
  4332. }
  4333. }
  4334. x = this.a * this.C_x * lon * (this.m + Math.cos(lat));
  4335. y = this.a * this.C_y * lat;
  4336. }
  4337. else {
  4338. var s = Math.sin(lat);
  4339. var c = Math.cos(lat);
  4340. y = this.a * pj_mlfn(lat, s, c, this.en);
  4341. x = this.a * lon * c / Math.sqrt(1 - this.es * s * s);
  4342. }
  4343. p.x = x;
  4344. p.y = y;
  4345. return p;
  4346. }
  4347. function inverse$20(p) {
  4348. var lat, temp, lon, s;
  4349. p.x -= this.x0;
  4350. lon = p.x / this.a;
  4351. p.y -= this.y0;
  4352. lat = p.y / this.a;
  4353. if (this.sphere) {
  4354. lat /= this.C_y;
  4355. lon = lon / (this.C_x * (this.m + Math.cos(lat)));
  4356. if (this.m) {
  4357. lat = asinz((this.m * lat + Math.sin(lat)) / this.n);
  4358. }
  4359. else if (this.n !== 1) {
  4360. lat = asinz(Math.sin(lat) / this.n);
  4361. }
  4362. lon = adjust_lon(lon + this.long0);
  4363. lat = adjust_lat(lat);
  4364. }
  4365. else {
  4366. lat = pj_inv_mlfn(p.y / this.a, this.es, this.en);
  4367. s = Math.abs(lat);
  4368. if (s < HALF_PI) {
  4369. s = Math.sin(lat);
  4370. temp = this.long0 + p.x * Math.sqrt(1 - this.es * s * s) / (this.a * Math.cos(lat));
  4371. //temp = this.long0 + p.x / (this.a * Math.cos(lat));
  4372. lon = adjust_lon(temp);
  4373. }
  4374. else if ((s - EPSLN) < HALF_PI) {
  4375. lon = this.long0;
  4376. }
  4377. }
  4378. p.x = lon;
  4379. p.y = lat;
  4380. return p;
  4381. }
  4382. var names$22 = ["Sinusoidal", "sinu"];
  4383. var sinu = {
  4384. init: init$21,
  4385. forward: forward$20,
  4386. inverse: inverse$20,
  4387. names: names$22
  4388. };
  4389. function init$22() {}
  4390. /* Mollweide forward equations--mapping lat,long to x,y
  4391. ----------------------------------------------------*/
  4392. function forward$21(p) {
  4393. /* Forward equations
  4394. -----------------*/
  4395. var lon = p.x;
  4396. var lat = p.y;
  4397. var delta_lon = adjust_lon(lon - this.long0);
  4398. var theta = lat;
  4399. var con = Math.PI * Math.sin(lat);
  4400. /* Iterate using the Newton-Raphson method to find theta
  4401. -----------------------------------------------------*/
  4402. while (true) {
  4403. var delta_theta = -(theta + Math.sin(theta) - con) / (1 + Math.cos(theta));
  4404. theta += delta_theta;
  4405. if (Math.abs(delta_theta) < EPSLN) {
  4406. break;
  4407. }
  4408. }
  4409. theta /= 2;
  4410. /* If the latitude is 90 deg, force the x coordinate to be "0 + false easting"
  4411. this is done here because of precision problems with "cos(theta)"
  4412. --------------------------------------------------------------------------*/
  4413. if (Math.PI / 2 - Math.abs(lat) < EPSLN) {
  4414. delta_lon = 0;
  4415. }
  4416. var x = 0.900316316158 * this.a * delta_lon * Math.cos(theta) + this.x0;
  4417. var y = 1.4142135623731 * this.a * Math.sin(theta) + this.y0;
  4418. p.x = x;
  4419. p.y = y;
  4420. return p;
  4421. }
  4422. function inverse$21(p) {
  4423. var theta;
  4424. var arg;
  4425. /* Inverse equations
  4426. -----------------*/
  4427. p.x -= this.x0;
  4428. p.y -= this.y0;
  4429. arg = p.y / (1.4142135623731 * this.a);
  4430. /* Because of division by zero problems, 'arg' can not be 1. Therefore
  4431. a number very close to one is used instead.
  4432. -------------------------------------------------------------------*/
  4433. if (Math.abs(arg) > 0.999999999999) {
  4434. arg = 0.999999999999;
  4435. }
  4436. theta = Math.asin(arg);
  4437. var lon = adjust_lon(this.long0 + (p.x / (0.900316316158 * this.a * Math.cos(theta))));
  4438. if (lon < (-Math.PI)) {
  4439. lon = -Math.PI;
  4440. }
  4441. if (lon > Math.PI) {
  4442. lon = Math.PI;
  4443. }
  4444. arg = (2 * theta + Math.sin(2 * theta)) / Math.PI;
  4445. if (Math.abs(arg) > 1) {
  4446. arg = 1;
  4447. }
  4448. var lat = Math.asin(arg);
  4449. p.x = lon;
  4450. p.y = lat;
  4451. return p;
  4452. }
  4453. var names$23 = ["Mollweide", "moll"];
  4454. var moll = {
  4455. init: init$22,
  4456. forward: forward$21,
  4457. inverse: inverse$21,
  4458. names: names$23
  4459. };
  4460. function init$23() {
  4461. /* Place parameters in static storage for common use
  4462. -------------------------------------------------*/
  4463. // Standard Parallels cannot be equal and on opposite sides of the equator
  4464. if (Math.abs(this.lat1 + this.lat2) < EPSLN) {
  4465. return;
  4466. }
  4467. this.lat2 = this.lat2 || this.lat1;
  4468. this.temp = this.b / this.a;
  4469. this.es = 1 - Math.pow(this.temp, 2);
  4470. this.e = Math.sqrt(this.es);
  4471. this.e0 = e0fn(this.es);
  4472. this.e1 = e1fn(this.es);
  4473. this.e2 = e2fn(this.es);
  4474. this.e3 = e3fn(this.es);
  4475. this.sinphi = Math.sin(this.lat1);
  4476. this.cosphi = Math.cos(this.lat1);
  4477. this.ms1 = msfnz(this.e, this.sinphi, this.cosphi);
  4478. this.ml1 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat1);
  4479. if (Math.abs(this.lat1 - this.lat2) < EPSLN) {
  4480. this.ns = this.sinphi;
  4481. }
  4482. else {
  4483. this.sinphi = Math.sin(this.lat2);
  4484. this.cosphi = Math.cos(this.lat2);
  4485. this.ms2 = msfnz(this.e, this.sinphi, this.cosphi);
  4486. this.ml2 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat2);
  4487. this.ns = (this.ms1 - this.ms2) / (this.ml2 - this.ml1);
  4488. }
  4489. this.g = this.ml1 + this.ms1 / this.ns;
  4490. this.ml0 = mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0);
  4491. this.rh = this.a * (this.g - this.ml0);
  4492. }
  4493. /* Equidistant Conic forward equations--mapping lat,long to x,y
  4494. -----------------------------------------------------------*/
  4495. function forward$22(p) {
  4496. var lon = p.x;
  4497. var lat = p.y;
  4498. var rh1;
  4499. /* Forward equations
  4500. -----------------*/
  4501. if (this.sphere) {
  4502. rh1 = this.a * (this.g - lat);
  4503. }
  4504. else {
  4505. var ml = mlfn(this.e0, this.e1, this.e2, this.e3, lat);
  4506. rh1 = this.a * (this.g - ml);
  4507. }
  4508. var theta = this.ns * adjust_lon(lon - this.long0);
  4509. var x = this.x0 + rh1 * Math.sin(theta);
  4510. var y = this.y0 + this.rh - rh1 * Math.cos(theta);
  4511. p.x = x;
  4512. p.y = y;
  4513. return p;
  4514. }
  4515. /* Inverse equations
  4516. -----------------*/
  4517. function inverse$22(p) {
  4518. p.x -= this.x0;
  4519. p.y = this.rh - p.y + this.y0;
  4520. var con, rh1, lat, lon;
  4521. if (this.ns >= 0) {
  4522. rh1 = Math.sqrt(p.x * p.x + p.y * p.y);
  4523. con = 1;
  4524. }
  4525. else {
  4526. rh1 = -Math.sqrt(p.x * p.x + p.y * p.y);
  4527. con = -1;
  4528. }
  4529. var theta = 0;
  4530. if (rh1 !== 0) {
  4531. theta = Math.atan2(con * p.x, con * p.y);
  4532. }
  4533. if (this.sphere) {
  4534. lon = adjust_lon(this.long0 + theta / this.ns);
  4535. lat = adjust_lat(this.g - rh1 / this.a);
  4536. p.x = lon;
  4537. p.y = lat;
  4538. return p;
  4539. }
  4540. else {
  4541. var ml = this.g - rh1 / this.a;
  4542. lat = imlfn(ml, this.e0, this.e1, this.e2, this.e3);
  4543. lon = adjust_lon(this.long0 + theta / this.ns);
  4544. p.x = lon;
  4545. p.y = lat;
  4546. return p;
  4547. }
  4548. }
  4549. var names$24 = ["Equidistant_Conic", "eqdc"];
  4550. var eqdc = {
  4551. init: init$23,
  4552. forward: forward$22,
  4553. inverse: inverse$22,
  4554. names: names$24
  4555. };
  4556. /* Initialize the Van Der Grinten projection
  4557. ----------------------------------------*/
  4558. function init$24() {
  4559. //this.R = 6370997; //Radius of earth
  4560. this.R = this.a;
  4561. }
  4562. function forward$23(p) {
  4563. var lon = p.x;
  4564. var lat = p.y;
  4565. /* Forward equations
  4566. -----------------*/
  4567. var dlon = adjust_lon(lon - this.long0);
  4568. var x, y;
  4569. if (Math.abs(lat) <= EPSLN) {
  4570. x = this.x0 + this.R * dlon;
  4571. y = this.y0;
  4572. }
  4573. var theta = asinz(2 * Math.abs(lat / Math.PI));
  4574. if ((Math.abs(dlon) <= EPSLN) || (Math.abs(Math.abs(lat) - HALF_PI) <= EPSLN)) {
  4575. x = this.x0;
  4576. if (lat >= 0) {
  4577. y = this.y0 + Math.PI * this.R * Math.tan(0.5 * theta);
  4578. }
  4579. else {
  4580. y = this.y0 + Math.PI * this.R * -Math.tan(0.5 * theta);
  4581. }
  4582. // return(OK);
  4583. }
  4584. var al = 0.5 * Math.abs((Math.PI / dlon) - (dlon / Math.PI));
  4585. var asq = al * al;
  4586. var sinth = Math.sin(theta);
  4587. var costh = Math.cos(theta);
  4588. var g = costh / (sinth + costh - 1);
  4589. var gsq = g * g;
  4590. var m = g * (2 / sinth - 1);
  4591. var msq = m * m;
  4592. var con = Math.PI * this.R * (al * (g - msq) + Math.sqrt(asq * (g - msq) * (g - msq) - (msq + asq) * (gsq - msq))) / (msq + asq);
  4593. if (dlon < 0) {
  4594. con = -con;
  4595. }
  4596. x = this.x0 + con;
  4597. //con = Math.abs(con / (Math.PI * this.R));
  4598. var q = asq + g;
  4599. con = Math.PI * this.R * (m * q - al * Math.sqrt((msq + asq) * (asq + 1) - q * q)) / (msq + asq);
  4600. if (lat >= 0) {
  4601. //y = this.y0 + Math.PI * this.R * Math.sqrt(1 - con * con - 2 * al * con);
  4602. y = this.y0 + con;
  4603. }
  4604. else {
  4605. //y = this.y0 - Math.PI * this.R * Math.sqrt(1 - con * con - 2 * al * con);
  4606. y = this.y0 - con;
  4607. }
  4608. p.x = x;
  4609. p.y = y;
  4610. return p;
  4611. }
  4612. /* Van Der Grinten inverse equations--mapping x,y to lat/long
  4613. ---------------------------------------------------------*/
  4614. function inverse$23(p) {
  4615. var lon, lat;
  4616. var xx, yy, xys, c1, c2, c3;
  4617. var a1;
  4618. var m1;
  4619. var con;
  4620. var th1;
  4621. var d;
  4622. /* inverse equations
  4623. -----------------*/
  4624. p.x -= this.x0;
  4625. p.y -= this.y0;
  4626. con = Math.PI * this.R;
  4627. xx = p.x / con;
  4628. yy = p.y / con;
  4629. xys = xx * xx + yy * yy;
  4630. c1 = -Math.abs(yy) * (1 + xys);
  4631. c2 = c1 - 2 * yy * yy + xx * xx;
  4632. c3 = -2 * c1 + 1 + 2 * yy * yy + xys * xys;
  4633. d = yy * yy / c3 + (2 * c2 * c2 * c2 / c3 / c3 / c3 - 9 * c1 * c2 / c3 / c3) / 27;
  4634. a1 = (c1 - c2 * c2 / 3 / c3) / c3;
  4635. m1 = 2 * Math.sqrt(-a1 / 3);
  4636. con = ((3 * d) / a1) / m1;
  4637. if (Math.abs(con) > 1) {
  4638. if (con >= 0) {
  4639. con = 1;
  4640. }
  4641. else {
  4642. con = -1;
  4643. }
  4644. }
  4645. th1 = Math.acos(con) / 3;
  4646. if (p.y >= 0) {
  4647. lat = (-m1 * Math.cos(th1 + Math.PI / 3) - c2 / 3 / c3) * Math.PI;
  4648. }
  4649. else {
  4650. lat = -(-m1 * Math.cos(th1 + Math.PI / 3) - c2 / 3 / c3) * Math.PI;
  4651. }
  4652. if (Math.abs(xx) < EPSLN) {
  4653. lon = this.long0;
  4654. }
  4655. else {
  4656. lon = adjust_lon(this.long0 + Math.PI * (xys - 1 + Math.sqrt(1 + 2 * (xx * xx - yy * yy) + xys * xys)) / 2 / xx);
  4657. }
  4658. p.x = lon;
  4659. p.y = lat;
  4660. return p;
  4661. }
  4662. var names$25 = ["Van_der_Grinten_I", "VanDerGrinten", "vandg"];
  4663. var vandg = {
  4664. init: init$24,
  4665. forward: forward$23,
  4666. inverse: inverse$23,
  4667. names: names$25
  4668. };
  4669. function init$25() {
  4670. this.sin_p12 = Math.sin(this.lat0);
  4671. this.cos_p12 = Math.cos(this.lat0);
  4672. }
  4673. function forward$24(p) {
  4674. var lon = p.x;
  4675. var lat = p.y;
  4676. var sinphi = Math.sin(p.y);
  4677. var cosphi = Math.cos(p.y);
  4678. var dlon = adjust_lon(lon - this.long0);
  4679. var e0, e1, e2, e3, Mlp, Ml, tanphi, Nl1, Nl, psi, Az, G, H, GH, Hs, c, kp, cos_c, s, s2, s3, s4, s5;
  4680. if (this.sphere) {
  4681. if (Math.abs(this.sin_p12 - 1) <= EPSLN) {
  4682. //North Pole case
  4683. p.x = this.x0 + this.a * (HALF_PI - lat) * Math.sin(dlon);
  4684. p.y = this.y0 - this.a * (HALF_PI - lat) * Math.cos(dlon);
  4685. return p;
  4686. }
  4687. else if (Math.abs(this.sin_p12 + 1) <= EPSLN) {
  4688. //South Pole case
  4689. p.x = this.x0 + this.a * (HALF_PI + lat) * Math.sin(dlon);
  4690. p.y = this.y0 + this.a * (HALF_PI + lat) * Math.cos(dlon);
  4691. return p;
  4692. }
  4693. else {
  4694. //default case
  4695. cos_c = this.sin_p12 * sinphi + this.cos_p12 * cosphi * Math.cos(dlon);
  4696. c = Math.acos(cos_c);
  4697. kp = c ? c / Math.sin(c) : 1;
  4698. p.x = this.x0 + this.a * kp * cosphi * Math.sin(dlon);
  4699. p.y = this.y0 + this.a * kp * (this.cos_p12 * sinphi - this.sin_p12 * cosphi * Math.cos(dlon));
  4700. return p;
  4701. }
  4702. }
  4703. else {
  4704. e0 = e0fn(this.es);
  4705. e1 = e1fn(this.es);
  4706. e2 = e2fn(this.es);
  4707. e3 = e3fn(this.es);
  4708. if (Math.abs(this.sin_p12 - 1) <= EPSLN) {
  4709. //North Pole case
  4710. Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
  4711. Ml = this.a * mlfn(e0, e1, e2, e3, lat);
  4712. p.x = this.x0 + (Mlp - Ml) * Math.sin(dlon);
  4713. p.y = this.y0 - (Mlp - Ml) * Math.cos(dlon);
  4714. return p;
  4715. }
  4716. else if (Math.abs(this.sin_p12 + 1) <= EPSLN) {
  4717. //South Pole case
  4718. Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
  4719. Ml = this.a * mlfn(e0, e1, e2, e3, lat);
  4720. p.x = this.x0 + (Mlp + Ml) * Math.sin(dlon);
  4721. p.y = this.y0 + (Mlp + Ml) * Math.cos(dlon);
  4722. return p;
  4723. }
  4724. else {
  4725. //Default case
  4726. tanphi = sinphi / cosphi;
  4727. Nl1 = gN(this.a, this.e, this.sin_p12);
  4728. Nl = gN(this.a, this.e, sinphi);
  4729. psi = Math.atan((1 - this.es) * tanphi + this.es * Nl1 * this.sin_p12 / (Nl * cosphi));
  4730. Az = Math.atan2(Math.sin(dlon), this.cos_p12 * Math.tan(psi) - this.sin_p12 * Math.cos(dlon));
  4731. if (Az === 0) {
  4732. s = Math.asin(this.cos_p12 * Math.sin(psi) - this.sin_p12 * Math.cos(psi));
  4733. }
  4734. else if (Math.abs(Math.abs(Az) - Math.PI) <= EPSLN) {
  4735. s = -Math.asin(this.cos_p12 * Math.sin(psi) - this.sin_p12 * Math.cos(psi));
  4736. }
  4737. else {
  4738. s = Math.asin(Math.sin(dlon) * Math.cos(psi) / Math.sin(Az));
  4739. }
  4740. G = this.e * this.sin_p12 / Math.sqrt(1 - this.es);
  4741. H = this.e * this.cos_p12 * Math.cos(Az) / Math.sqrt(1 - this.es);
  4742. GH = G * H;
  4743. Hs = H * H;
  4744. s2 = s * s;
  4745. s3 = s2 * s;
  4746. s4 = s3 * s;
  4747. s5 = s4 * s;
  4748. c = Nl1 * s * (1 - s2 * Hs * (1 - Hs) / 6 + s3 / 8 * GH * (1 - 2 * Hs) + s4 / 120 * (Hs * (4 - 7 * Hs) - 3 * G * G * (1 - 7 * Hs)) - s5 / 48 * GH);
  4749. p.x = this.x0 + c * Math.sin(Az);
  4750. p.y = this.y0 + c * Math.cos(Az);
  4751. return p;
  4752. }
  4753. }
  4754. }
  4755. function inverse$24(p) {
  4756. p.x -= this.x0;
  4757. p.y -= this.y0;
  4758. var rh, z, sinz, cosz, lon, lat, con, e0, e1, e2, e3, Mlp, M, N1, psi, Az, cosAz, tmp, A, B, D, Ee, F, sinpsi;
  4759. if (this.sphere) {
  4760. rh = Math.sqrt(p.x * p.x + p.y * p.y);
  4761. if (rh > (2 * HALF_PI * this.a)) {
  4762. return;
  4763. }
  4764. z = rh / this.a;
  4765. sinz = Math.sin(z);
  4766. cosz = Math.cos(z);
  4767. lon = this.long0;
  4768. if (Math.abs(rh) <= EPSLN) {
  4769. lat = this.lat0;
  4770. }
  4771. else {
  4772. lat = asinz(cosz * this.sin_p12 + (p.y * sinz * this.cos_p12) / rh);
  4773. con = Math.abs(this.lat0) - HALF_PI;
  4774. if (Math.abs(con) <= EPSLN) {
  4775. if (this.lat0 >= 0) {
  4776. lon = adjust_lon(this.long0 + Math.atan2(p.x, - p.y));
  4777. }
  4778. else {
  4779. lon = adjust_lon(this.long0 - Math.atan2(-p.x, p.y));
  4780. }
  4781. }
  4782. else {
  4783. /*con = cosz - this.sin_p12 * Math.sin(lat);
  4784. if ((Math.abs(con) < EPSLN) && (Math.abs(p.x) < EPSLN)) {
  4785. //no-op, just keep the lon value as is
  4786. } else {
  4787. var temp = Math.atan2((p.x * sinz * this.cos_p12), (con * rh));
  4788. lon = adjust_lon(this.long0 + Math.atan2((p.x * sinz * this.cos_p12), (con * rh)));
  4789. }*/
  4790. lon = adjust_lon(this.long0 + Math.atan2(p.x * sinz, rh * this.cos_p12 * cosz - p.y * this.sin_p12 * sinz));
  4791. }
  4792. }
  4793. p.x = lon;
  4794. p.y = lat;
  4795. return p;
  4796. }
  4797. else {
  4798. e0 = e0fn(this.es);
  4799. e1 = e1fn(this.es);
  4800. e2 = e2fn(this.es);
  4801. e3 = e3fn(this.es);
  4802. if (Math.abs(this.sin_p12 - 1) <= EPSLN) {
  4803. //North pole case
  4804. Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
  4805. rh = Math.sqrt(p.x * p.x + p.y * p.y);
  4806. M = Mlp - rh;
  4807. lat = imlfn(M / this.a, e0, e1, e2, e3);
  4808. lon = adjust_lon(this.long0 + Math.atan2(p.x, - 1 * p.y));
  4809. p.x = lon;
  4810. p.y = lat;
  4811. return p;
  4812. }
  4813. else if (Math.abs(this.sin_p12 + 1) <= EPSLN) {
  4814. //South pole case
  4815. Mlp = this.a * mlfn(e0, e1, e2, e3, HALF_PI);
  4816. rh = Math.sqrt(p.x * p.x + p.y * p.y);
  4817. M = rh - Mlp;
  4818. lat = imlfn(M / this.a, e0, e1, e2, e3);
  4819. lon = adjust_lon(this.long0 + Math.atan2(p.x, p.y));
  4820. p.x = lon;
  4821. p.y = lat;
  4822. return p;
  4823. }
  4824. else {
  4825. //default case
  4826. rh = Math.sqrt(p.x * p.x + p.y * p.y);
  4827. Az = Math.atan2(p.x, p.y);
  4828. N1 = gN(this.a, this.e, this.sin_p12);
  4829. cosAz = Math.cos(Az);
  4830. tmp = this.e * this.cos_p12 * cosAz;
  4831. A = -tmp * tmp / (1 - this.es);
  4832. B = 3 * this.es * (1 - A) * this.sin_p12 * this.cos_p12 * cosAz / (1 - this.es);
  4833. D = rh / N1;
  4834. Ee = D - A * (1 + A) * Math.pow(D, 3) / 6 - B * (1 + 3 * A) * Math.pow(D, 4) / 24;
  4835. F = 1 - A * Ee * Ee / 2 - D * Ee * Ee * Ee / 6;
  4836. psi = Math.asin(this.sin_p12 * Math.cos(Ee) + this.cos_p12 * Math.sin(Ee) * cosAz);
  4837. lon = adjust_lon(this.long0 + Math.asin(Math.sin(Az) * Math.sin(Ee) / Math.cos(psi)));
  4838. sinpsi = Math.sin(psi);
  4839. lat = Math.atan2((sinpsi - this.es * F * this.sin_p12) * Math.tan(psi), sinpsi * (1 - this.es));
  4840. p.x = lon;
  4841. p.y = lat;
  4842. return p;
  4843. }
  4844. }
  4845. }
  4846. var names$26 = ["Azimuthal_Equidistant", "aeqd"];
  4847. var aeqd = {
  4848. init: init$25,
  4849. forward: forward$24,
  4850. inverse: inverse$24,
  4851. names: names$26
  4852. };
  4853. function init$26() {
  4854. //double temp; /* temporary variable */
  4855. /* Place parameters in static storage for common use
  4856. -------------------------------------------------*/
  4857. this.sin_p14 = Math.sin(this.lat0);
  4858. this.cos_p14 = Math.cos(this.lat0);
  4859. }
  4860. /* Orthographic forward equations--mapping lat,long to x,y
  4861. ---------------------------------------------------*/
  4862. function forward$25(p) {
  4863. var sinphi, cosphi; /* sin and cos value */
  4864. var dlon; /* delta longitude value */
  4865. var coslon; /* cos of longitude */
  4866. var ksp; /* scale factor */
  4867. var g, x, y;
  4868. var lon = p.x;
  4869. var lat = p.y;
  4870. /* Forward equations
  4871. -----------------*/
  4872. dlon = adjust_lon(lon - this.long0);
  4873. sinphi = Math.sin(lat);
  4874. cosphi = Math.cos(lat);
  4875. coslon = Math.cos(dlon);
  4876. g = this.sin_p14 * sinphi + this.cos_p14 * cosphi * coslon;
  4877. ksp = 1;
  4878. if ((g > 0) || (Math.abs(g) <= EPSLN)) {
  4879. x = this.a * ksp * cosphi * Math.sin(dlon);
  4880. y = this.y0 + this.a * ksp * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon);
  4881. }
  4882. p.x = x;
  4883. p.y = y;
  4884. return p;
  4885. }
  4886. function inverse$25(p) {
  4887. var rh; /* height above ellipsoid */
  4888. var z; /* angle */
  4889. var sinz, cosz; /* sin of z and cos of z */
  4890. var con;
  4891. var lon, lat;
  4892. /* Inverse equations
  4893. -----------------*/
  4894. p.x -= this.x0;
  4895. p.y -= this.y0;
  4896. rh = Math.sqrt(p.x * p.x + p.y * p.y);
  4897. z = asinz(rh / this.a);
  4898. sinz = Math.sin(z);
  4899. cosz = Math.cos(z);
  4900. lon = this.long0;
  4901. if (Math.abs(rh) <= EPSLN) {
  4902. lat = this.lat0;
  4903. p.x = lon;
  4904. p.y = lat;
  4905. return p;
  4906. }
  4907. lat = asinz(cosz * this.sin_p14 + (p.y * sinz * this.cos_p14) / rh);
  4908. con = Math.abs(this.lat0) - HALF_PI;
  4909. if (Math.abs(con) <= EPSLN) {
  4910. if (this.lat0 >= 0) {
  4911. lon = adjust_lon(this.long0 + Math.atan2(p.x, - p.y));
  4912. }
  4913. else {
  4914. lon = adjust_lon(this.long0 - Math.atan2(-p.x, p.y));
  4915. }
  4916. p.x = lon;
  4917. p.y = lat;
  4918. return p;
  4919. }
  4920. lon = adjust_lon(this.long0 + Math.atan2((p.x * sinz), rh * this.cos_p14 * cosz - p.y * this.sin_p14 * sinz));
  4921. p.x = lon;
  4922. p.y = lat;
  4923. return p;
  4924. }
  4925. var names$27 = ["ortho"];
  4926. var ortho = {
  4927. init: init$26,
  4928. forward: forward$25,
  4929. inverse: inverse$25,
  4930. names: names$27
  4931. };
  4932. // QSC projection rewritten from the original PROJ4
  4933. // https://github.com/OSGeo/proj.4/blob/master/src/PJ_qsc.c
  4934. /* constants */
  4935. var FACE_ENUM = {
  4936. FRONT: 1,
  4937. RIGHT: 2,
  4938. BACK: 3,
  4939. LEFT: 4,
  4940. TOP: 5,
  4941. BOTTOM: 6
  4942. };
  4943. var AREA_ENUM = {
  4944. AREA_0: 1,
  4945. AREA_1: 2,
  4946. AREA_2: 3,
  4947. AREA_3: 4
  4948. };
  4949. function init$27() {
  4950. this.x0 = this.x0 || 0;
  4951. this.y0 = this.y0 || 0;
  4952. this.lat0 = this.lat0 || 0;
  4953. this.long0 = this.long0 || 0;
  4954. this.lat_ts = this.lat_ts || 0;
  4955. this.title = this.title || "Quadrilateralized Spherical Cube";
  4956. /* Determine the cube face from the center of projection. */
  4957. if (this.lat0 >= HALF_PI - FORTPI / 2.0) {
  4958. this.face = FACE_ENUM.TOP;
  4959. } else if (this.lat0 <= -(HALF_PI - FORTPI / 2.0)) {
  4960. this.face = FACE_ENUM.BOTTOM;
  4961. } else if (Math.abs(this.long0) <= FORTPI) {
  4962. this.face = FACE_ENUM.FRONT;
  4963. } else if (Math.abs(this.long0) <= HALF_PI + FORTPI) {
  4964. this.face = this.long0 > 0.0 ? FACE_ENUM.RIGHT : FACE_ENUM.LEFT;
  4965. } else {
  4966. this.face = FACE_ENUM.BACK;
  4967. }
  4968. /* Fill in useful values for the ellipsoid <-> sphere shift
  4969. * described in [LK12]. */
  4970. if (this.es !== 0) {
  4971. this.one_minus_f = 1 - (this.a - this.b) / this.a;
  4972. this.one_minus_f_squared = this.one_minus_f * this.one_minus_f;
  4973. }
  4974. }
  4975. // QSC forward equations--mapping lat,long to x,y
  4976. // -----------------------------------------------------------------
  4977. function forward$26(p) {
  4978. var xy = {x: 0, y: 0};
  4979. var lat, lon;
  4980. var theta, phi;
  4981. var t, mu;
  4982. /* nu; */
  4983. var area = {value: 0};
  4984. // move lon according to projection's lon
  4985. p.x -= this.long0;
  4986. /* Convert the geodetic latitude to a geocentric latitude.
  4987. * This corresponds to the shift from the ellipsoid to the sphere
  4988. * described in [LK12]. */
  4989. if (this.es !== 0) {//if (P->es != 0) {
  4990. lat = Math.atan(this.one_minus_f_squared * Math.tan(p.y));
  4991. } else {
  4992. lat = p.y;
  4993. }
  4994. /* Convert the input lat, lon into theta, phi as used by QSC.
  4995. * This depends on the cube face and the area on it.
  4996. * For the top and bottom face, we can compute theta and phi
  4997. * directly from phi, lam. For the other faces, we must use
  4998. * unit sphere cartesian coordinates as an intermediate step. */
  4999. lon = p.x; //lon = lp.lam;
  5000. if (this.face === FACE_ENUM.TOP) {
  5001. phi = HALF_PI - lat;
  5002. if (lon >= FORTPI && lon <= HALF_PI + FORTPI) {
  5003. area.value = AREA_ENUM.AREA_0;
  5004. theta = lon - HALF_PI;
  5005. } else if (lon > HALF_PI + FORTPI || lon <= -(HALF_PI + FORTPI)) {
  5006. area.value = AREA_ENUM.AREA_1;
  5007. theta = (lon > 0.0 ? lon - SPI : lon + SPI);
  5008. } else if (lon > -(HALF_PI + FORTPI) && lon <= -FORTPI) {
  5009. area.value = AREA_ENUM.AREA_2;
  5010. theta = lon + HALF_PI;
  5011. } else {
  5012. area.value = AREA_ENUM.AREA_3;
  5013. theta = lon;
  5014. }
  5015. } else if (this.face === FACE_ENUM.BOTTOM) {
  5016. phi = HALF_PI + lat;
  5017. if (lon >= FORTPI && lon <= HALF_PI + FORTPI) {
  5018. area.value = AREA_ENUM.AREA_0;
  5019. theta = -lon + HALF_PI;
  5020. } else if (lon < FORTPI && lon >= -FORTPI) {
  5021. area.value = AREA_ENUM.AREA_1;
  5022. theta = -lon;
  5023. } else if (lon < -FORTPI && lon >= -(HALF_PI + FORTPI)) {
  5024. area.value = AREA_ENUM.AREA_2;
  5025. theta = -lon - HALF_PI;
  5026. } else {
  5027. area.value = AREA_ENUM.AREA_3;
  5028. theta = (lon > 0.0 ? -lon + SPI : -lon - SPI);
  5029. }
  5030. } else {
  5031. var q, r, s;
  5032. var sinlat, coslat;
  5033. var sinlon, coslon;
  5034. if (this.face === FACE_ENUM.RIGHT) {
  5035. lon = qsc_shift_lon_origin(lon, +HALF_PI);
  5036. } else if (this.face === FACE_ENUM.BACK) {
  5037. lon = qsc_shift_lon_origin(lon, +SPI);
  5038. } else if (this.face === FACE_ENUM.LEFT) {
  5039. lon = qsc_shift_lon_origin(lon, -HALF_PI);
  5040. }
  5041. sinlat = Math.sin(lat);
  5042. coslat = Math.cos(lat);
  5043. sinlon = Math.sin(lon);
  5044. coslon = Math.cos(lon);
  5045. q = coslat * coslon;
  5046. r = coslat * sinlon;
  5047. s = sinlat;
  5048. if (this.face === FACE_ENUM.FRONT) {
  5049. phi = Math.acos(q);
  5050. theta = qsc_fwd_equat_face_theta(phi, s, r, area);
  5051. } else if (this.face === FACE_ENUM.RIGHT) {
  5052. phi = Math.acos(r);
  5053. theta = qsc_fwd_equat_face_theta(phi, s, -q, area);
  5054. } else if (this.face === FACE_ENUM.BACK) {
  5055. phi = Math.acos(-q);
  5056. theta = qsc_fwd_equat_face_theta(phi, s, -r, area);
  5057. } else if (this.face === FACE_ENUM.LEFT) {
  5058. phi = Math.acos(-r);
  5059. theta = qsc_fwd_equat_face_theta(phi, s, q, area);
  5060. } else {
  5061. /* Impossible */
  5062. phi = theta = 0;
  5063. area.value = AREA_ENUM.AREA_0;
  5064. }
  5065. }
  5066. /* Compute mu and nu for the area of definition.
  5067. * For mu, see Eq. (3-21) in [OL76], but note the typos:
  5068. * compare with Eq. (3-14). For nu, see Eq. (3-38). */
  5069. mu = Math.atan((12 / SPI) * (theta + Math.acos(Math.sin(theta) * Math.cos(FORTPI)) - HALF_PI));
  5070. t = Math.sqrt((1 - Math.cos(phi)) / (Math.cos(mu) * Math.cos(mu)) / (1 - Math.cos(Math.atan(1 / Math.cos(theta)))));
  5071. /* Apply the result to the real area. */
  5072. if (area.value === AREA_ENUM.AREA_1) {
  5073. mu += HALF_PI;
  5074. } else if (area.value === AREA_ENUM.AREA_2) {
  5075. mu += SPI;
  5076. } else if (area.value === AREA_ENUM.AREA_3) {
  5077. mu += 1.5 * SPI;
  5078. }
  5079. /* Now compute x, y from mu and nu */
  5080. xy.x = t * Math.cos(mu);
  5081. xy.y = t * Math.sin(mu);
  5082. xy.x = xy.x * this.a + this.x0;
  5083. xy.y = xy.y * this.a + this.y0;
  5084. p.x = xy.x;
  5085. p.y = xy.y;
  5086. return p;
  5087. }
  5088. // QSC inverse equations--mapping x,y to lat/long
  5089. // -----------------------------------------------------------------
  5090. function inverse$26(p) {
  5091. var lp = {lam: 0, phi: 0};
  5092. var mu, nu, cosmu, tannu;
  5093. var tantheta, theta, cosphi, phi;
  5094. var t;
  5095. var area = {value: 0};
  5096. /* de-offset */
  5097. p.x = (p.x - this.x0) / this.a;
  5098. p.y = (p.y - this.y0) / this.a;
  5099. /* Convert the input x, y to the mu and nu angles as used by QSC.
  5100. * This depends on the area of the cube face. */
  5101. nu = Math.atan(Math.sqrt(p.x * p.x + p.y * p.y));
  5102. mu = Math.atan2(p.y, p.x);
  5103. if (p.x >= 0.0 && p.x >= Math.abs(p.y)) {
  5104. area.value = AREA_ENUM.AREA_0;
  5105. } else if (p.y >= 0.0 && p.y >= Math.abs(p.x)) {
  5106. area.value = AREA_ENUM.AREA_1;
  5107. mu -= HALF_PI;
  5108. } else if (p.x < 0.0 && -p.x >= Math.abs(p.y)) {
  5109. area.value = AREA_ENUM.AREA_2;
  5110. mu = (mu < 0.0 ? mu + SPI : mu - SPI);
  5111. } else {
  5112. area.value = AREA_ENUM.AREA_3;
  5113. mu += HALF_PI;
  5114. }
  5115. /* Compute phi and theta for the area of definition.
  5116. * The inverse projection is not described in the original paper, but some
  5117. * good hints can be found here (as of 2011-12-14):
  5118. * http://fits.gsfc.nasa.gov/fitsbits/saf.93/saf.9302
  5119. * (search for "Message-Id: <9302181759.AA25477 at fits.cv.nrao.edu>") */
  5120. t = (SPI / 12) * Math.tan(mu);
  5121. tantheta = Math.sin(t) / (Math.cos(t) - (1 / Math.sqrt(2)));
  5122. theta = Math.atan(tantheta);
  5123. cosmu = Math.cos(mu);
  5124. tannu = Math.tan(nu);
  5125. cosphi = 1 - cosmu * cosmu * tannu * tannu * (1 - Math.cos(Math.atan(1 / Math.cos(theta))));
  5126. if (cosphi < -1) {
  5127. cosphi = -1;
  5128. } else if (cosphi > +1) {
  5129. cosphi = +1;
  5130. }
  5131. /* Apply the result to the real area on the cube face.
  5132. * For the top and bottom face, we can compute phi and lam directly.
  5133. * For the other faces, we must use unit sphere cartesian coordinates
  5134. * as an intermediate step. */
  5135. if (this.face === FACE_ENUM.TOP) {
  5136. phi = Math.acos(cosphi);
  5137. lp.phi = HALF_PI - phi;
  5138. if (area.value === AREA_ENUM.AREA_0) {
  5139. lp.lam = theta + HALF_PI;
  5140. } else if (area.value === AREA_ENUM.AREA_1) {
  5141. lp.lam = (theta < 0.0 ? theta + SPI : theta - SPI);
  5142. } else if (area.value === AREA_ENUM.AREA_2) {
  5143. lp.lam = theta - HALF_PI;
  5144. } else /* area.value == AREA_ENUM.AREA_3 */ {
  5145. lp.lam = theta;
  5146. }
  5147. } else if (this.face === FACE_ENUM.BOTTOM) {
  5148. phi = Math.acos(cosphi);
  5149. lp.phi = phi - HALF_PI;
  5150. if (area.value === AREA_ENUM.AREA_0) {
  5151. lp.lam = -theta + HALF_PI;
  5152. } else if (area.value === AREA_ENUM.AREA_1) {
  5153. lp.lam = -theta;
  5154. } else if (area.value === AREA_ENUM.AREA_2) {
  5155. lp.lam = -theta - HALF_PI;
  5156. } else /* area.value == AREA_ENUM.AREA_3 */ {
  5157. lp.lam = (theta < 0.0 ? -theta - SPI : -theta + SPI);
  5158. }
  5159. } else {
  5160. /* Compute phi and lam via cartesian unit sphere coordinates. */
  5161. var q, r, s;
  5162. q = cosphi;
  5163. t = q * q;
  5164. if (t >= 1) {
  5165. s = 0;
  5166. } else {
  5167. s = Math.sqrt(1 - t) * Math.sin(theta);
  5168. }
  5169. t += s * s;
  5170. if (t >= 1) {
  5171. r = 0;
  5172. } else {
  5173. r = Math.sqrt(1 - t);
  5174. }
  5175. /* Rotate q,r,s into the correct area. */
  5176. if (area.value === AREA_ENUM.AREA_1) {
  5177. t = r;
  5178. r = -s;
  5179. s = t;
  5180. } else if (area.value === AREA_ENUM.AREA_2) {
  5181. r = -r;
  5182. s = -s;
  5183. } else if (area.value === AREA_ENUM.AREA_3) {
  5184. t = r;
  5185. r = s;
  5186. s = -t;
  5187. }
  5188. /* Rotate q,r,s into the correct cube face. */
  5189. if (this.face === FACE_ENUM.RIGHT) {
  5190. t = q;
  5191. q = -r;
  5192. r = t;
  5193. } else if (this.face === FACE_ENUM.BACK) {
  5194. q = -q;
  5195. r = -r;
  5196. } else if (this.face === FACE_ENUM.LEFT) {
  5197. t = q;
  5198. q = r;
  5199. r = -t;
  5200. }
  5201. /* Now compute phi and lam from the unit sphere coordinates. */
  5202. lp.phi = Math.acos(-s) - HALF_PI;
  5203. lp.lam = Math.atan2(r, q);
  5204. if (this.face === FACE_ENUM.RIGHT) {
  5205. lp.lam = qsc_shift_lon_origin(lp.lam, -HALF_PI);
  5206. } else if (this.face === FACE_ENUM.BACK) {
  5207. lp.lam = qsc_shift_lon_origin(lp.lam, -SPI);
  5208. } else if (this.face === FACE_ENUM.LEFT) {
  5209. lp.lam = qsc_shift_lon_origin(lp.lam, +HALF_PI);
  5210. }
  5211. }
  5212. /* Apply the shift from the sphere to the ellipsoid as described
  5213. * in [LK12]. */
  5214. if (this.es !== 0) {
  5215. var invert_sign;
  5216. var tanphi, xa;
  5217. invert_sign = (lp.phi < 0 ? 1 : 0);
  5218. tanphi = Math.tan(lp.phi);
  5219. xa = this.b / Math.sqrt(tanphi * tanphi + this.one_minus_f_squared);
  5220. lp.phi = Math.atan(Math.sqrt(this.a * this.a - xa * xa) / (this.one_minus_f * xa));
  5221. if (invert_sign) {
  5222. lp.phi = -lp.phi;
  5223. }
  5224. }
  5225. lp.lam += this.long0;
  5226. p.x = lp.lam;
  5227. p.y = lp.phi;
  5228. return p;
  5229. }
  5230. /* Helper function for forward projection: compute the theta angle
  5231. * and determine the area number. */
  5232. function qsc_fwd_equat_face_theta(phi, y, x, area) {
  5233. var theta;
  5234. if (phi < EPSLN) {
  5235. area.value = AREA_ENUM.AREA_0;
  5236. theta = 0.0;
  5237. } else {
  5238. theta = Math.atan2(y, x);
  5239. if (Math.abs(theta) <= FORTPI) {
  5240. area.value = AREA_ENUM.AREA_0;
  5241. } else if (theta > FORTPI && theta <= HALF_PI + FORTPI) {
  5242. area.value = AREA_ENUM.AREA_1;
  5243. theta -= HALF_PI;
  5244. } else if (theta > HALF_PI + FORTPI || theta <= -(HALF_PI + FORTPI)) {
  5245. area.value = AREA_ENUM.AREA_2;
  5246. theta = (theta >= 0.0 ? theta - SPI : theta + SPI);
  5247. } else {
  5248. area.value = AREA_ENUM.AREA_3;
  5249. theta += HALF_PI;
  5250. }
  5251. }
  5252. return theta;
  5253. }
  5254. /* Helper function: shift the longitude. */
  5255. function qsc_shift_lon_origin(lon, offset) {
  5256. var slon = lon + offset;
  5257. if (slon < -SPI) {
  5258. slon += TWO_PI;
  5259. } else if (slon > +SPI) {
  5260. slon -= TWO_PI;
  5261. }
  5262. return slon;
  5263. }
  5264. var names$28 = ["Quadrilateralized Spherical Cube", "Quadrilateralized_Spherical_Cube", "qsc"];
  5265. var qsc = {
  5266. init: init$27,
  5267. forward: forward$26,
  5268. inverse: inverse$26,
  5269. names: names$28
  5270. };
  5271. // Robinson projection
  5272. // Based on https://github.com/OSGeo/proj.4/blob/master/src/PJ_robin.c
  5273. // Polynomial coeficients from http://article.gmane.org/gmane.comp.gis.proj-4.devel/6039
  5274. var COEFS_X = [
  5275. [1.0000, 2.2199e-17, -7.15515e-05, 3.1103e-06],
  5276. [0.9986, -0.000482243, -2.4897e-05, -1.3309e-06],
  5277. [0.9954, -0.00083103, -4.48605e-05, -9.86701e-07],
  5278. [0.9900, -0.00135364, -5.9661e-05, 3.6777e-06],
  5279. [0.9822, -0.00167442, -4.49547e-06, -5.72411e-06],
  5280. [0.9730, -0.00214868, -9.03571e-05, 1.8736e-08],
  5281. [0.9600, -0.00305085, -9.00761e-05, 1.64917e-06],
  5282. [0.9427, -0.00382792, -6.53386e-05, -2.6154e-06],
  5283. [0.9216, -0.00467746, -0.00010457, 4.81243e-06],
  5284. [0.8962, -0.00536223, -3.23831e-05, -5.43432e-06],
  5285. [0.8679, -0.00609363, -0.000113898, 3.32484e-06],
  5286. [0.8350, -0.00698325, -6.40253e-05, 9.34959e-07],
  5287. [0.7986, -0.00755338, -5.00009e-05, 9.35324e-07],
  5288. [0.7597, -0.00798324, -3.5971e-05, -2.27626e-06],
  5289. [0.7186, -0.00851367, -7.01149e-05, -8.6303e-06],
  5290. [0.6732, -0.00986209, -0.000199569, 1.91974e-05],
  5291. [0.6213, -0.010418, 8.83923e-05, 6.24051e-06],
  5292. [0.5722, -0.00906601, 0.000182, 6.24051e-06],
  5293. [0.5322, -0.00677797, 0.000275608, 6.24051e-06]
  5294. ];
  5295. var COEFS_Y = [
  5296. [-5.20417e-18, 0.0124, 1.21431e-18, -8.45284e-11],
  5297. [0.0620, 0.0124, -1.26793e-09, 4.22642e-10],
  5298. [0.1240, 0.0124, 5.07171e-09, -1.60604e-09],
  5299. [0.1860, 0.0123999, -1.90189e-08, 6.00152e-09],
  5300. [0.2480, 0.0124002, 7.10039e-08, -2.24e-08],
  5301. [0.3100, 0.0123992, -2.64997e-07, 8.35986e-08],
  5302. [0.3720, 0.0124029, 9.88983e-07, -3.11994e-07],
  5303. [0.4340, 0.0123893, -3.69093e-06, -4.35621e-07],
  5304. [0.4958, 0.0123198, -1.02252e-05, -3.45523e-07],
  5305. [0.5571, 0.0121916, -1.54081e-05, -5.82288e-07],
  5306. [0.6176, 0.0119938, -2.41424e-05, -5.25327e-07],
  5307. [0.6769, 0.011713, -3.20223e-05, -5.16405e-07],
  5308. [0.7346, 0.0113541, -3.97684e-05, -6.09052e-07],
  5309. [0.7903, 0.0109107, -4.89042e-05, -1.04739e-06],
  5310. [0.8435, 0.0103431, -6.4615e-05, -1.40374e-09],
  5311. [0.8936, 0.00969686, -6.4636e-05, -8.547e-06],
  5312. [0.9394, 0.00840947, -0.000192841, -4.2106e-06],
  5313. [0.9761, 0.00616527, -0.000256, -4.2106e-06],
  5314. [1.0000, 0.00328947, -0.000319159, -4.2106e-06]
  5315. ];
  5316. var FXC = 0.8487;
  5317. var FYC = 1.3523;
  5318. var C1 = R2D/5; // rad to 5-degree interval
  5319. var RC1 = 1/C1;
  5320. var NODES = 18;
  5321. var poly3_val = function(coefs, x) {
  5322. return coefs[0] + x * (coefs[1] + x * (coefs[2] + x * coefs[3]));
  5323. };
  5324. var poly3_der = function(coefs, x) {
  5325. return coefs[1] + x * (2 * coefs[2] + x * 3 * coefs[3]);
  5326. };
  5327. function newton_rapshon(f_df, start, max_err, iters) {
  5328. var x = start;
  5329. for (; iters; --iters) {
  5330. var upd = f_df(x);
  5331. x -= upd;
  5332. if (Math.abs(upd) < max_err) {
  5333. break;
  5334. }
  5335. }
  5336. return x;
  5337. }
  5338. function init$28() {
  5339. this.x0 = this.x0 || 0;
  5340. this.y0 = this.y0 || 0;
  5341. this.long0 = this.long0 || 0;
  5342. this.es = 0;
  5343. this.title = this.title || "Robinson";
  5344. }
  5345. function forward$27(ll) {
  5346. var lon = adjust_lon(ll.x - this.long0);
  5347. var dphi = Math.abs(ll.y);
  5348. var i = Math.floor(dphi * C1);
  5349. if (i < 0) {
  5350. i = 0;
  5351. } else if (i >= NODES) {
  5352. i = NODES - 1;
  5353. }
  5354. dphi = R2D * (dphi - RC1 * i);
  5355. var xy = {
  5356. x: poly3_val(COEFS_X[i], dphi) * lon,
  5357. y: poly3_val(COEFS_Y[i], dphi)
  5358. };
  5359. if (ll.y < 0) {
  5360. xy.y = -xy.y;
  5361. }
  5362. xy.x = xy.x * this.a * FXC + this.x0;
  5363. xy.y = xy.y * this.a * FYC + this.y0;
  5364. return xy;
  5365. }
  5366. function inverse$27(xy) {
  5367. var ll = {
  5368. x: (xy.x - this.x0) / (this.a * FXC),
  5369. y: Math.abs(xy.y - this.y0) / (this.a * FYC)
  5370. };
  5371. if (ll.y >= 1) { // pathologic case
  5372. ll.x /= COEFS_X[NODES][0];
  5373. ll.y = xy.y < 0 ? -HALF_PI : HALF_PI;
  5374. } else {
  5375. // find table interval
  5376. var i = Math.floor(ll.y * NODES);
  5377. if (i < 0) {
  5378. i = 0;
  5379. } else if (i >= NODES) {
  5380. i = NODES - 1;
  5381. }
  5382. for (;;) {
  5383. if (COEFS_Y[i][0] > ll.y) {
  5384. --i;
  5385. } else if (COEFS_Y[i+1][0] <= ll.y) {
  5386. ++i;
  5387. } else {
  5388. break;
  5389. }
  5390. }
  5391. // linear interpolation in 5 degree interval
  5392. var coefs = COEFS_Y[i];
  5393. var t = 5 * (ll.y - coefs[0]) / (COEFS_Y[i+1][0] - coefs[0]);
  5394. // find t so that poly3_val(coefs, t) = ll.y
  5395. t = newton_rapshon(function(x) {
  5396. return (poly3_val(coefs, x) - ll.y) / poly3_der(coefs, x);
  5397. }, t, EPSLN, 100);
  5398. ll.x /= poly3_val(COEFS_X[i], t);
  5399. ll.y = (5 * i + t) * D2R;
  5400. if (xy.y < 0) {
  5401. ll.y = -ll.y;
  5402. }
  5403. }
  5404. ll.x = adjust_lon(ll.x + this.long0);
  5405. return ll;
  5406. }
  5407. var names$29 = ["Robinson", "robin"];
  5408. var robin = {
  5409. init: init$28,
  5410. forward: forward$27,
  5411. inverse: inverse$27,
  5412. names: names$29
  5413. };
  5414. function init$29() {
  5415. this.name = 'geocent';
  5416. }
  5417. function forward$28(p) {
  5418. var point = geodeticToGeocentric(p, this.es, this.a);
  5419. return point;
  5420. }
  5421. function inverse$28(p) {
  5422. var point = geocentricToGeodetic(p, this.es, this.a, this.b);
  5423. return point;
  5424. }
  5425. var names$30 = ["Geocentric", 'geocentric', "geocent", "Geocent"];
  5426. var geocent = {
  5427. init: init$29,
  5428. forward: forward$28,
  5429. inverse: inverse$28,
  5430. names: names$30
  5431. };
  5432. var includedProjections = function(proj4){
  5433. proj4.Proj.projections.add(tmerc);
  5434. proj4.Proj.projections.add(etmerc);
  5435. proj4.Proj.projections.add(utm);
  5436. proj4.Proj.projections.add(sterea);
  5437. proj4.Proj.projections.add(stere);
  5438. proj4.Proj.projections.add(somerc);
  5439. proj4.Proj.projections.add(omerc);
  5440. proj4.Proj.projections.add(lcc);
  5441. proj4.Proj.projections.add(krovak);
  5442. proj4.Proj.projections.add(cass);
  5443. proj4.Proj.projections.add(laea);
  5444. proj4.Proj.projections.add(aea);
  5445. proj4.Proj.projections.add(gnom);
  5446. proj4.Proj.projections.add(cea);
  5447. proj4.Proj.projections.add(eqc);
  5448. proj4.Proj.projections.add(poly);
  5449. proj4.Proj.projections.add(nzmg);
  5450. proj4.Proj.projections.add(mill);
  5451. proj4.Proj.projections.add(sinu);
  5452. proj4.Proj.projections.add(moll);
  5453. proj4.Proj.projections.add(eqdc);
  5454. proj4.Proj.projections.add(vandg);
  5455. proj4.Proj.projections.add(aeqd);
  5456. proj4.Proj.projections.add(ortho);
  5457. proj4.Proj.projections.add(qsc);
  5458. proj4.Proj.projections.add(robin);
  5459. proj4.Proj.projections.add(geocent);
  5460. };
  5461. proj4$1.defaultDatum = 'WGS84'; //default datum
  5462. proj4$1.Proj = Projection;
  5463. proj4$1.WGS84 = new proj4$1.Proj('WGS84');
  5464. proj4$1.Point = Point;
  5465. proj4$1.toPoint = toPoint;
  5466. proj4$1.defs = defs;
  5467. proj4$1.transform = transform;
  5468. proj4$1.mgrs = mgrs;
  5469. proj4$1.version = '2.6.2';
  5470. includedProjections(proj4$1);
  5471. return proj4$1;
  5472. })));