geosphere/0000755000176200001440000000000014335012510012225 5ustar liggesusersgeosphere/NAMESPACE0000644000176200001440000000014314161531052013446 0ustar liggesusersuseDynLib(geosphere, .registration = TRUE) import(Rcpp) import(sp) exportPattern("^[^\\.\\_]") geosphere/ChangeLog0000644000176200001440000000605013472155746014024 0ustar liggesusers-- to do inconsistency reported by Ryan Case: bearing is expressed as -180 to 180 whereas bearingRhum is from 0 to 360 -- Current version dist* functions threw an error when using a two row matrix for p1, and missing p2. Fixed by setting "drop=FALSE". Bug report and fix by Miles Wood. -- 2 November 2018, version 1.5.7 distHaversine bugged in some cases for antipodes: https://stackoverflow.com/questions/45889616/why-does-disthaversine-return-nan-for-some-pairs-of-coordinates# dist2gc always returned a positive value (the manual said it should be negative if it was at the left of the circle); in contrast with what the manual stated. Getting the sign is now an option. Reported by Charles Mohan, Hughan Ross and David Cooley dist2gc used the bearing for an ellipsoid, not for a spheroid. Reported by Greg Whittier -- 15 June 2016, version 1.5-5 Fixed error in gcMaxLat (reported by William Smith) Bug fix in antipodal (reported by Gareth Davies) Bug fix in gcIntermediate when crossing the date line -- 7 July 2015, version 1.4-3 Included C-version of GeographicLib by C.F.F. Karney. areaPolygon and perimeter are now using that to compute these on a (WGS84) ellipsoid. New function distGeo (distance on an ellipsoid) also uses this. -- 17 January 2014, version 1.3-8 Fixed bug in destPointRhumb. Reported by Bart Kranstauber Fixed bug in bearingRhumb when using multiple points (incorrect results were returned). Reported by Bart Kranstauber Added 'ID' output to dist2Line distVincentyEllipsoid returned a distance of 0 between NA and NA; now it returns NA as intended (reported by Sebastian Luque) Fixed minor bug in distMeeus (using 'isTRUE' where 'which' is appropriate) (reported by Tyler Smith) -- 4 March 2012, version 1.2-27 Bug fix in antipodal; reported by Bart Kranstauber Fixed bug in distMeeus. It returned NaN when the distance between two points was 0. Reportedby Daniel Reidpath New function geomean to compute the mean of a set of coordinates (optionally with weights) -- 28 August 2011, version 1.2-25 Correction to gcIntermediate. Points were not exactly equidistant. Error spotted by Jason Davies. -- 18 May 2011, version 1.2-21 Normalizing longitude to -180..180 in midPoint. Suggested by Aaron Hardin -- 13 Jan 2011, version 1.2-18 New argument sepNA in gcIntermediate, suggested by Lee Butterman -- 1 Jan 2011, version 1.2-17 Merged functions distm and distm2 into distm Function with new distance algorithm "distMeeus" -- 4 Nov 2010 Additional options to gcIntermediate and greatCircle to return SpatialLines (that are cut in two when crossing the date line) -- 8 Sept 2010 bug fix in .pointsToMatrix (reported by Joe) -- 26 August 2010 New functions: dist2Line computes the (spherical) distance between points and polylines (and polygons borders). makeLine (like makePoly), adds intermediate great circle points to line segments, for better plotting onGreatCircle tests if points are on a specified great circle -- 25 August 2010 distVincentyEllipsoid now handles NA values. Bug fix suggested by George Wang. geosphere/data/0000755000176200001440000000000014334225312013143 5ustar liggesusersgeosphere/data/wrld.RData0000644000176200001440000047236013472155746015063 0ustar liggesusers7zXZi"6!X3])TW"nRʟXV%>"UZ J3+s;ە<&|DNaNMJ%qg$&Y3.:Kk8LaZБVv0n ѡ(KL u2 Ȫ{"l*-Kxh8$fmsi Ϭqu5ܦ;|- HVmU ˒';ZO[r X<D"Ir7] ZF_S(oID4Qڈjz-WXy` 9O6XAnw_i4z] v2Lt_aڣ~'6x %ٚ&k\_gjxg%%aNyI87I4۴eaojIqkPe B&W?HLg{ka?%&|[=oBd}p \jd!EfS4qڀv--OU]9Ҿd8`ԉ mAOXi%Z@Bˑ] .W3ϲŴ`\a=ByB 1ҿ,f*C<@N's-H)̕Ȗ\$nxjl1c$$vs[]#\9-OcG_H!8=5.N?`02z)6(n)7*4fz 'l#r<(I80]X[fPq)/s;}Wdd (DL ~_s\V$T{5'*X(857UacHܳ+s4o5F9=0Ox3ƆEj>f ! Z:q8~qJ Nm|{^+k$epSpd; afE6i+u4 {h &Ás ؾ̿<޻vǤP[HK50cKOjوjH"@Wfqs4`xLMpb~9e*y$ȍ@mv0(U󩁥/16% Dv"VřeY#ro>ܣܟҗ9 zq#j@Lh ܙqtʐ][KH )U)%J'3Y-BZ'mUknrJq0\$hZKkbQK5Q S!Wg%^r8wQ{ͮh]FM-Eutᙾ4p9VaP |v@_#^ ݭ5u2/GXXOOz$ۇH(ki@\ö =Q O`<Ì[RӭHiS*,mN0az5-.ivaKPXqA9ЏWަ|pT_MBc8[28u+\\%??++a1ղTaq?8I:\+r+5h{n HV7)l\c tr IeuDA%NboK]NThk(bb /O&nh[ aD㻇q֭"s Xn'߁!є }J V,֮-) ^B@]@W׈*IX!+wdAջz(mXˡ Ge)FYcNTD3`B1x&ni{qp Owltm̂r Я#qpvr¯u+B5ϗٙ(7wƤh~˹["8B[ֆkAnK^l#i8ĝN)&3kB= Xmy3-+c|,$@bj PD~^.?)~(fѵ$!tA-^^$LqcX;B" /, ?tͣ3İy8xNzOΈB+C&ZدB|EMuTV~->uuGˤt5HҚ|$j GMy,ӶOI;{(cl=n|(̪AsJW#fOcp IToZx'H ;RlPЋv[l?V8bOq@~B X8ŏ {CcFKiz⓱^ge8ā R.u%iL-q5 n mM5>{ 4:Q/ƛzbP psDLMy$2$JAQSݱl&W&q *蹥)7xen1+bPۛ탱X;CnDGvRN)tB/Hkc:bYT9xKPɫ[Xgw󒁱vPY9S m)v5" )t牟PFV :AuI0r&)C|`5i! 5Zix>6|ݐ:ݻUn{~oSkҽ)}#0’ #^e_˄4DӺhpúdp{F"`%Y5;؇TX/F#j?X& L5РHx]ޓ./R{`tK " JB._?&_E$o`Ocw V&ӭ~` RLtTx>@\_ŮYt+byNaZ+ebb{ (+O{og$ih0C #ژSOt=a -n'v7nfV_S4;nRYԃ1gjӋ gU!%81kYg*Zi] 0'٠C0U߼ CN6טQڦc RA1H= O5S4)[;(kybX҇˲+z.˒z,=ًԵcpCbjv;=!_@E+n g.pbXj8ǜeTKj.7&HP6;]+˯ZBJ~śe#Q%JQNHO?N%fRvccٵ;bXD,/k\~HoZa=yZ+d\N[fm q㸃MdkR6u{3p[3eR"W9ăi5ygvy^<RI]1^tcVP|}tw4? #`xMvR)lSWy.< P-YJ.1fgBq)e. J+-j̩XkU<`bAJ|o&JI>Bj speᦡ9`gU ݳXKez5٢lYhݱS^kt)>*0V "IXt$ΈW$W-&e'ȇ鳟^=3"<*t0Be2u<\:D*Ry A}BQ*1)â?0owon^l&1vhĤ ?6@x#9lQ;ǁIBJ#Цv*6Kd4{>4s֨*: s*^#Enb-!mm(gB^N^4ꭳ|[ 1MޫBiʐ01s@u +phv Xv¡Bo]v&M ޱNw؋0Â2?4m ԞK=4,@U>ƚ!r ۢ_T~z+ֆ4l"`b.J_-Q7AF2GǕL}lj/HN4oX_i(62"%q]:H#ż⛑fnvDO&5ђsvA3MUtQ^Ww; )B??c%t o޽8}/)1 e%\ID(Qa.?E"We5A)F},E'hXZcM*muKЧSZJn7a ,8TQTDⳎuVѼJ$f0wzme`Uc\mN YzD\:Fڙ$Vr_ѽ[_7D5 `ΔFrD.c7}2F\kI <fU{>%e+rfӰd ~ԋhe,UO*dtt'\vjQE=jӸtj`b+4XYn'/HztU| R2@Q';iX`??q `r.xJ;ıbxDo,!d ⺔/QY߉`h%$&{}T5<19IBZ$ *ۣȖ2I bf l!)މܭƗzZ|=ZOlm!CK u^&$9& k=]aB}9΢jI?cHH bo^Q /oǧjW8|'nC`1%F(!zE^/|k xl"^A?T'+mP1 aDLF?%DV*9x +P޶VƮ e\7*/ȜeՕ7}ڹ7srWQ0 +6 ZY{+IvJ}ٿ[;V7΃}Xzm]PfT?ݭZmJ e) 0\nHBb.e9G zd4;f6񚐓آu!pyNtKLQo5E\ĕ!M|GG fIKK 8P0ԏ[RJ6 ,N|RJ`ӝ;g=0Y, ڎ\W(qm}T%`e  "Gƨ>}:5t]?91Irj4}& E᫣#0)n0'4z&ЧE{Pvfl#jb`&əJx9laL.}&:*<϶S#np\~;IF޿f0쭐ǁc'͞yww9KӲAmpl)K4ʿݺ(h.}.~@ 6(M7һd.EiX pI[ 5 fطގgF/m23i)̰kG7Ne,6E[CPx󬿔V 9b=.U#%`G)y&W:EaXG.<E"FM^ydܡ\~q9)I(CVI5|GϤa?g!TO̼`#2Sə.LwSS< @d;wd]0ѯjkeSKe0q!ܒ pfG,+5-I]5Ď}W*~UE2\1u/&AAȴchϫZlk!y>g4=#Õ 6)Q'}?|O*TM"=C>|t[%GE EJ3HǼR~d@}&0q_K@AAORxdϓ$M9- H(S(Ij2֚ юO>~ ;r2_Z_і=1^QÓҙ}&J x>/V^>qٻeAb5 !J$ ?CSl<0}\w/bM7 0j}UEšA"oKqFna8Uen.ffT y,L|o%O;# pݷyEBYerX08ӹ ʽA4 LFYBnk 2T c퍜LoU 1|&"qLtCR#ڈ ^: XNa e4S^#RghC OwK\=޺lI;g|)6|o gS|2`i|EZ*(|gZ].3rF";"*v3_90hA!@Y3}ޕG{tu÷ANQ=^cB>O2Z& +\ݬx?~tZI%OLdpA)'T3?sT! ~Ww1A؍F<}#ՕR" }AzWr7us*^i!|^tuY9t:&U|2 3X姻ˀ@y'kK*V;uw6qvj39/W:=96Ρ}&#漢PlU9JxLG2ǫ.E|@FCJdп8tvPbi(]~2*&7Ѵlvds]_Dr`!UnI0͔x)ycR_Ygmóϼn hqȄZT|8e_ lY}6=V9P[FŚ)qϜ$;ia '&ٽ:qd\zw؆$)ꅾ&hz.淰A(g'8U\"VG1ie,O* 3< R hC LAvMn)0*fF ܨl]SQ BOq@" s[l;b͉8QdHW$0jàNɬ%:7N t(j5xaS1^W]g4f嵅-fvz%lAK)Lrw- /}ðڐ se ZV\ͺS81Xyxov#0LTa?Lz!xq벱]Rtud3^`t;{_ʈ-1[!;JAR]c7[. վjM=iv01I ]8&ȕFRs΁Q>WX6P%"2jV+I; (Ƈ͵wS$DXsS2-th8E1LzFϩ/-_%.KRv*!?%IJ1D(͒߻ƛhh^+Q(+>yav| 0Z% *cr,;CHW%-Ll m =%6;!pkh2xe0 O&Ƌm;%z*@Pod)upN7p0?4 |GFe#$2GAgEOHw1w:R :ܔ22[iWxWpS*dwJOH9A7W䧿,,SU|9qF8G>0W׎s@H9, @q6 Sdve []_ugб?À[8aH&/Iֶ 0Hj$go!42'ݨ%wt3=`\22=P~16+X9.'%&,UG63jDZK9r9V^e^*BABʲC h\ ;N1m博k.;C) Qw3ZZi+؉l5ƈ=9FDP; c'V'&Tr=%llO#nth`{4-iUD*umuh{WeUzzHy5Rh,gsE={B_85TW'm@6ma,q҉ګ9ݩ|Ă#2ipǎV_ǫ;o=::YQaWZ,J\F 4})Wb[2r9Ĝ0LW]_L' |\ĭoy㝟aq%=h1dG'瑔y4h M78hc}Ru'329T%'ȹz{QP]vo/K1Oŗ.坂crP^{ތ&q\|[X=N=¨~ܒSKYbAx~mk 1S5CNn+a|D=8|&< ptx  C?tk4L#[3>dbLL /0Z& x8Q9MQgilm,e Zvce^\n,HeC/[yلUDa d{_>BdGw! 9U+PE['2 Yae}b)aWtC8<SꁅvLx}S>gg BZ;j׌R2 k(c M3/Xyc_̀NJoΊZ9JVf=(h\[$W诟;|YqFƐ߰q 3k e``l<2Z{X lSp }HӍOt]w^|VҘp_K&k UZ4 v^׿YeGsr9=i ah 2M<;){*ݶXڅ2s/?nEJGw?"fbyX͞ h[km32ۺ 9ߺX,R&eow6WO +iDW?3)u?韫l"}y<8CGRkTu' Ԍ+f+n]Q*F29{h]x]\(0iYbr+Du@>,KՊQjm-gsf2ıni};qe@_Μ**7c[X,1H9Z;1āe{j?iaBqQml)Aτs[8\)jytIKPbۈ}|zFȡÌ/` 3XrA8Obswau` Z[zAEW+mBQp=_{w $ 9V/ -.ax޳2|QѴ £:K|Ų؍..fqx875 x}l { sGPLD궹;L[izpD]*"v5Ö@hBɬ zoi9w/LhP0$e|,W4EI~]rY;=c[IWDNi0&M^iVJRU\a!j:#9H4zSR,15^Ba7I) X邢Rb7S/907]Pk2L3=.cD3]ۏA %rdM)[$:Uf:VD:(M&4k_M/.0e׼|6lPioZg_mA?n#SԵ>/a] +f[+ {L3*t(z絞e~;ie_peޢ44.Z3'0-bk!1YqT^P=Gh"z7+C( 5[Jhl-[Ԭ6@;,6,\k#1r%tyiLqwvXi,ߊ˪, |G($εc#?µ҄sT, xF!V:pŞu0"УDez>|x|V[Y@ynxm(;9%yGv#Sjp$HLD YOhfao3 3z؉Lm׎̊b%<"xdr}¡ea C7q&Pж+E5;=%=.#LSYAVdNϵwXܚw} i} |JFVK Xe?ê:qPW)#T;&H\ŗ!Y[}rzbP_+ 6vR2~U~ꧏ@u`M5;{_%!GK,4~cAh2.' l.B\u 2nS{/G%3 T4>bұۛk=t(8 I^ϕ?q>Jޤ y.bϫdL63,0oC0 M)tBaIA" dzGf ܠRѾ\/DfL]ګKNЫc] ~l/: _ifᖩxu#]=˩R1YS,kk.?%dUxeO5Ŋֹ.~_3rc vN&:K7y Bo;F rsXN⫶m}Εiiu-<S^"ʒѶpt J+|[蝅\T=6ɩ=Mh~EI2ؗmnAZx -# 5Ҿ&.rZAaG'}e\/{|4l(؊&R+P{5}PAC5ad:5-=&nu{QApʚ "'[lo@֭C" pt4 /:VAg~åC>wFPskn @h1ɝXjz(('/&UmgCN<mn{:<K-hGC+\Tg!2*#_2I-Uj` _T]tL0m V:ӣv9/70.t{_DQ&15^d aoy| WX6U"H{*0MmSa*Cf2/zF s, P0 'W938/2ñG8j#ƻ5uYKu$F[sܞoVLqqg9|,`:UO2f}ӭ(~jդY$խ軭!V ʃa}|3RAE7{ fNZ+g7Pʙ=8~=pV{9gzú>l>H)/RI-jl=%'!OcUpW@,&ڗ*8@g\A{@ LX=Mn篆nHɅ x+JQGwJ8X)ߍTXÃX^$gNjiD:xYlOV@3Je\,;hgbhl& !ڮ1d͋}apJpp'BxTh#"6%%ԑb1S xjZ/IE AЈ?Z1V-Vl&ILB Z2T۸.SEy8 B+le "CEݨxs4$[&knf".LD݌89 ]ֶ4~6lB4/e2ȦZ+ Yyy;QyQ.Vu9+}k8B+=XW:.)>Vi*uJ_'a4h.|H?ZPYщ$?|N7uΟôR^~&F5.gI=7/ĭK7^o/7sC #l:6!qZ\0Бߔm-zi+m2R Y6}|#bH^A튟H[,O\;cnvqL?:Ŝ5sPOc> H*4#1!1Z~٭pݿ70'B .8Q]֮d19WH-۠HkRjy~>$Z/ ´ 쩽_`rVd;)Ynz8(ڲr]r:QܹTx 7[z KXJ`'Q\L~roȔpwSېhQQ/:Es ϸ[ bVwy0Шs2wWǍ`>"Ŗ2JբS+,=g Y=]ݤU yq}6tZBh*ȧaBqxui%_[4$m,މ*^poDIY=R?QZH)CX~{uGKY NsnٿuuJ_Xun"2,WNb`u: lW0Vß̹Ga:KON sMb~^KgQ  |WAGeoY@ߊGIS|"F_usHrLwheKjUϵM3tPF$gOs#9SR<9fN;U 9o0c{ҍf(2 ~YD#wA B>9d a=P0u]wq>>2r*_^MSV֪ Wg~x=9YQ";+N.z٭TհȡW 5!.TnA)rzNJ4 ֶeFCS,Wk >uhp֎c\xE\ 2 }l%HHu 74Ha|T'P-jnm}FBW ??ւ3T  |Р1|)&ا1vd&mp0 (Gt68IEO 0V@,)$w)@*o뷙epKuG JmesA6= ;ڹq8X&,m"CRG8wĭZ9ٝYJ S)3:FV2|Q|ό^]P k񮩩oT`VYfSJΙI;@٩>T<.(6laNneF6yS&ce'kzS%$ߏ7V4@MO{ {MԈWޥGDK}.nk4EϵЕ940b~)V^K(Y$(5_宍,ֿKOk7αC؁%,lPTTv?d+^ruU4^/BdU&O@_H׹}n3&,]VO5/@ks|n&<ijEʬֻ) 4:G |&sk< {ͧw {K]xR[?B<7HNOFy6C[tа=U@2 Dд81B"MjXuʍ"Q{od7T曦Ni6ñPkAek 5nӹMa: :<݋f;׽Undj%>: Pr!49dBw`[#Mv( H4p,$aXӤY?Kf44y$-RE0 q6{w5:* _oHH$dBWkf)R2 b曯_Wk1Q?h=pO۪3CU|#׃ܐ]*m(_9|} J>J:lN6-P)!$pe S}[ }UMĎIۄΐ>Dtqƙ{:rVO8 ܚ0G }Ӯp;=mLkK~WΚ}TZ Upu(~qZpM(zB&CZWyrq,s4(kHxWvZ" M{+c쀢'i_M@Z٬ZcV vHv% =c b>t<~6gϩ# &ܶF+, k̵;:F˱Q{H5WPHJr.e)s׷Ɋ4rʛ S__%S<`[1wkvj^ !sAY@QJk"uyxlKURܬ ˔1S6t0㿤\n1M7Fլ!^(HW?+ϴK"k߽vuo߲4(g["iܤ4< (_@]vDN~7%AG#O<ڤE^`7u~c"O^߇oXdAYrF-c̈́)29N1N.,uu{7聐2c~ rIBopN@5f ո~ӻ3Fi/#dj4̈́hYp3]/7&շ -1usavS+4A$zu96*'[Mb.KeiAOb>oFTab%fpYe r(:Ԇw&c6ܽTtoP0|8 &؀/HLœ,'F!-QOESqUOBW[0i޳ Xȴ 2ZW=6g_&ruDrb +l<+c+9d䧉Zf)Kaa\wT@1lUߙ)0K;ʜWmJyG~BwǂyG:W۾*B|k}~Q==a`*<[;&/Y>d)F֖L8@b7ͦ\ሐCXd-:HXbl+ klVGƘI9PRfE=U/t\e;И p z=$WJRB`rTRg?nj_lXW5dCiFO,(yY3o̥1<6^se_d1Ü$2?SKY6)իMNK ptq"n2>uUSُM+O8wX u 7޻/_o7#ۯ"vA.A7yF%74+E6-/f0OH" YbjSσ[ `_*{o-|k8g V񬐿,^U0Z ;ڥ1%"wMۛ'< tM.1P;}wHI=uER`a7r&3$KYQ0ʱlf@cN͒9Fft_Fu,ΣE-p(4ŒBn P,iT+9@@u;b4*;ݝyH]}0abnR2/=x~?P60jԛݡzGh!7'|R?7ʣbɫŔ2hx6R5m@QpY:lY(aX@DT6bAtR+E}sX=ʙ)S,@Q|PLw!\YnIJ ŜT[jE֡1N7党 D#٫jRَy ͱ! XW=& lل{a MǰӁr )}<Cu;׹,^ǥV;YR"5C)LށX@ؗ<%0MgOrkQ ={<}LHvG'NuqLk`r8@C/ ͗E2!SDL6wm#QYVZ͏3@/͙ixufV Ic{AQ&!kxhBc5!e餁??违VMP>^~L\SzobRy4o`4!Kl8ѻ\YhM\P<Ђ snUW@B8sUv@6hn|1,V栊\p졕PiX|; Г_ǼG8@GRUL`y^}}&bdP(҆Qwuhi"UH5=Aj,&9.=ni hldR@ڎ3T F2RhR]SJn])Sf^bU^D*p.''cdܐOdt y/ȵ%7 l݁@9jzwW[5\M{ 5Hzk^6rfc@`<AשƜ$137S)=h_EgX>(GsꬃޭI4wީ.u2XIb׌ #nZd !;x7諫/i$X+J$;t-T0eO^.<4*cZ^oKH\ kjb.NIeY ćG[u _Ɇ_ E&W9, Y#U`Il%yt)R QC!`>'$0wm ;i|qM![-ETTm#V;#rRޅu4=njX6h،ؖ+1KJlU޹mz˄!L.CׅS|G+y,>RlxS"I beN𖣇?"\zfzv"GĺKފrr`8l;CS=`:x0&!Px #R~5Cr.~6hʁ@O(VUh>&K}d%gJtTmӜ=OSL喺87vWBV4&ɥu;/c:ΐ)J gꢳٳ%I#"$+*u&>nq%3eG'ÑI^zArvr> 2 &CIJ DH2 |.M?, %Rr l Lx>ki:Qd@A?Đvˠu)3qwMl {KB;G=VaWt<rDJlnu_8I .X2r%X t3]S3PW*4mbv{M'kMVدc &&򫕖Q󕚜0F]sHƒc<8뤞rp<Ɛ By0"QCPrKm*-ٽ[=rvR~a7L04\$#'qu BLKd'Ϥ5jSzc`pgψʓqy Ve"pd~H2yUY^[N*0.'J/= aXk~)!!{0tDg0LNg0\% n.EJH0b}`86[(bTa?Z2 cuڦ7G8%:-0ח8A?"eisˏ`WqwA*]?y#D9-U,7 +O%O;@ne h?l.٠Z66@@7e(۳flj9֗%@bb?2KDR2{&(GU k7*īpv^kG 6ݱe'-kgG+@7u/a`v΋q>ۛj`׬{]4Wd|2Jz GfRi`mDZuA Sa[$-͠,fbcf D~ke60n\X[Y]ΔD a܃_~77~ߤvI'syCP ^d3Y\  @;F4\hTW5kA{1 , U!C9/gYLa"J|t_Nt8ǂY!-9FZX*,~]b+)udk9vf. R1h)ׄ:LjL3Z$HyxU6+J_}N#lQ&ʟ@Mcvo4:JTGŤ:L|vlL^bz҄|فo 3 /O/dXAxl# rlԞtHPzߥPu9e{=MљN'?c^G)\JU_ͻ;-f`>i] 2&vtCb,LZ:naQhNjTy*ꗎ-3HF'R `A^g_cXcŦ%!2ih`ȏ N.[G#xOgy)cGZ06p}:bp)Sm&:xCE=~l54Щ%247EA)+cՕsȣưY:1ӽJqm/ϱ.|5RΪx,r;Cϟr3kCĔ1T/^D饀ۈ0TY(k?T~xf>Pӌ ax1Z.x@Npi2[9zx`u'>H EIeHGCtg)|rKt兀pKzP`wliF{ъG[*-l!<7+^L)N!A;i})Z F-n5ŋ^5xYVBDǿ2IF,x \UW2D֍v/|YYkRtjkR #Huв:LN XK7wvU2a30)eVgsC7L^yR,7?nI&^X u_Dvr/aY.9,Y`kv+wH%5@[k)rbǷl2)$l.@p ZA3Ya(}J &\Z۩:̯/8WHZٺp9;كɸqzEWS%_*Oe-m KYa[Kk >'/˧ɍvW8ِppRVY)aj/n'm~z5rHDA{yњa07-?3q#ߪxNÌb#ӉƦ'T^B GhpaaL0;yaeCN>Tn;~gMVm+4MQ =u4{\䮊̩@ꐗerk /(c5 ì/8Ynx7-'3!1tm0pHz-X@QzBBBsbڀݣ"0DZ&"aㄹnHeMpV"bWsEcQMjW :9Ul46+^Moh7"(gzbr:sbd9]mv4VDm#h.[<+ƹo2-[|#¨YOIGgG=JQv]yǀ`. :E8A"A6C' O>{g/&~Xg erwcə!;*OW^#̘B8M,jR}K2<2q^.^~P}S؞)Ke]!z~7ꋣ5M0ӭ5OUKZlĄjL L|َz{](+6P@>OtR6r9}"I8[beTShesSֳѭ"R9(Y`fB߻*T5M:wu"h GOAAg(*Mi⿃՘xnP/;11NǦy\ r = /`4 ( gYRT IbEy~vx柟LQwQi=Aw=FSgȗKۣK@IU tiXǭWaH r“W-CfL>SU:ҌUfVO?Ֆ儀rPp^P} eޗN\ +$jiC%̤{мnG8:\q.7sR%qW!bfʍx\J ,]b}J bNԓeR* 3s9۲Uv, c7ZSdYKAGά2]'SNfd\CYNb$k@!~ UڌߠtӗX'wT_S"\2S,ћB5T#rZdݽi|\ɨ:V;m v=0إ"rCBR6s %¾CT,bG\fS]O>"]ߗֺ¹Q:Fl3Ll]^AyR*#Q(;|9o^co &4d#}j4-7VU3݀ t'l`B3Pz ~Ңx`8yk F^'rnD1߶^\{aՋ`z~ ^a=IWik8sV*r>` *feSDAڰIZm8HN(wFR`B:ŐsU;aǾY-s)#7Ŀ據. tz}#eeU.+ZTq8bbt/-F9N꫌? KCo]u{M2 I$jZkҹZD:JEDeESp;ɱY7&vKQ˦U]6D>kޝs'5yF'bԝ3R GS摱NWxح~aV m.$ Ty^Mfzaq5A'+ RF7ڱUkbLW8ı :RBvUwJI&Zs"Z4|+|R;M*`wlIX U|4T#M-Q[7|<sd8IVU9v6 ̃"5P2&_wjI`S`o#2I&4¼N8[?^֡Ew|pp ZĐW*i-ࣿB~nt"W7\9\BF'D""}qJ+ՄgՅxNO +dl*JR=3Шp)hR,qT5WS.n@_A$ LG'ǽt%!IGZ,q=,̂S WK,÷t 8?vФ-I.詆ɟﲥ fTv&:ȥC *hz :tjnXQ `uL=D<7UNB( \an|‹)(ԏnHkJ?m 'UXt$ Kuh6|limꄲʒ#n/{ŚTiɠ cZ*&i#V>hzD[PN T66ӥ/7@[J4h6"ηIS%5zyY* PI,,q5Ϛ\Ȉ_{s|a>L66핐<?1H+*ᆫH!leӐS3m&לnˎZ$uXۚrO?yÏDY4w.R)3+Zk=+/JeBb_F!~ֽ7^tbju q.I[K3"PܒWiK[G??),!H)hjz8եmw`Aw`3W8` NDmMGvbLTFoBIu2p؇ݞ/8/;Ԕ%5=7Y2nıJR&+h@)/,9}JUñ678G~ *u(⬆9hw] CHjcwoUOi_x6{"Bb>c6|FېU b(NòT@@gm!@62 8ĄtV,+8uh,|4s`gzS% ]U\ \7##T _>{ lz v]P'tÒdqEI@OA!Hg ̌]靅-Gz*40Nk A 5l߾*PH/\-:8 _P&pͽ`vkDHmi]v!Y@=A9\D9R:Q6V"&g'eyN+N (MIak [#1W2k'%{yOaoG9hGFHĉ\Լ!pZ@(Wel2("`&ʧ,"pNv*ELO_װ]%@` \OloBad޽Q`n0vC9/ '+~Om _"wm4o52ԷmǺqUᴸ6g=GɀjLul4[chk8/zRm@q-MtG6LxQnҗ]s⤧)\}Q9?$,Z.0J_rS9˄K=.cxA{N$"B%`Ast'P(佗 .r1·"RfUlWƙ0,kľ61nHbI?".+!Sl8gk΋H'7e\VJI?"9c0ؾu,fcLKCY*LKgBe%86USN)M74&aKWuV) rjEqF:.GE~817g.GwGԴv0w7'қP>".tN"W*$a:kK6uynU8< ~8tF@NQC~2E/0> i5Lލ{XR{lPN ,r}$WW?׏$FaB_wagьcZ{aS 11\~J?ߖ^=L0A;hPN9v?°x7}F @aDž F>1..h7N,îIE~TѭLndo!1}2!;E'.iZ5Ub3VvA@taAKPMyIj!2?af8S`JHkRbٟfnBy^@^փڰXgU6O +17uĜfŰ_鑺(w]("|BM# Wbf4u|<w# $l R& yPa]"-'̽(7}t'W҂05F676Ixm+\긱Hvԁ= l;xBJ74ZgA%nRJ wBHVB[FƂ¿NoȀC(Oկұ2CapKA曼uÐ8q$33,W _GDVb'+x̔I$+Z۔-t(`Yxʂ->% mhfmAEY4;k&1M1Pn"̒ PX!Rg9o"?;K^נJui#frѯ{';</;?}kDh[^DjZw滊%Y4I: 7W dY@)Iyk@P1*qVIq mbV@Z,<*$t#UV|K&IJ]i r sYWhSS&nק$;jM$N7'hP:VBDz G0c qQt +iDK 9=]kr/}2 btrs>"Kޒ2Lr<,'۶Ճ^;a|:@0P@ |VY^&( I}9ؙxE'nO uE?fu7I5jOtBZ774`^]9s [1lfvb:y_k訂*JMN!~%x78C51 59 0 g/BAIzHՍu":RHHʶ ղq`. ~~.RQb/$Z,1_ ,:`nY'7B\X?׬LR{XNw=!{=&[r bnc<P ֗.)1ꯡ3Pj;[JA99m(NaQu 1*M1KȐ5QP΋[DX4<=6pNRGͭzT37$.' ++,`bм1d%%k yd-ȭoT*FǫW%?6C=Wq؋>Qe'+:ݳyӆ!}fSj*q]2/;RiY>/+\q< _MU? $6mQDǐgDݻkTx3$\쏯VW8?Ȇ~˘"O Ae i*>@Ğ 3~c8BC^]d#>RJ|69qVd}(nX<pk0c=M ;;Wjm]G{V@n覊+ $e mŎhc|3 3̊?2r݈) :6U:AA/+~R]h%r.HVd{!mC:*}2#4y xt*] >.bͧJޙLJtuϼ89,*ny\S$iWt=D܄½/7;󏒪(Xml.˖v_K{fo`{d)YHAjvM>E~hJN>MþƽF ?pIb1Ha2u))9Ho߭iN g}5zw`tP~q~i }'- RJoڞu'HsfbgWWbuk&lY~YC7 k/U5]Gʔ~^7`(OʅgO`UYu(i6͙Ӹ.^I[&(^H h>?O,wVJA.oàpqj)aJWޒU弙C UpreփA: "wixK=ݔd+\$GW>[rv.|ᨐw"GR@G]=ou&`kA{f]gv,T#Qtvm7?eշ1t"bpuBV0QRucpe|bήrbի/7Xb[41 vQ̌TAOd#.1FY%R5~E=dKY Wu^eEdP1x׼ڒ밓V?<^ "f9:0w>LuZ+aZ;c6*zտ8.j?JLߖS[Ϲ4ksR H`,l&dSAu;ݷd1kuIa(-:2S}i)׭tM|P\n)\#ct&bp%Ju ܌ybvl'x@>ޅUHP盄w^2*EOg R}"KsZfT‡&DaU=xEp$qjF,*ReeO9wZTW' s d2HuG6(e֊"088VI[:<[3zM\٘}ˉ[_h[Ui2j27,C=^(%::E'e} nȼ!H. Njrt[GwR>3/[\ad؜OIEmR1e}W15$q9E.J>++|V2r-PBxQQ@,(eP9G[6~̊ nXd8GW]_WhP)A1=TH()TQ_ZoJ48lCe( RVx ?Yr:18[ZMG'\&pOmj 2s_dbydFs}Xc 3L#1O-vGYM\l a&{OUc +GlP!_*ߢX F:naʙ!.?"5[*EJjGyϹT0e`9&/Bc]`秘<:|9?(ϕ݌/uz58lp pdN.qF'S)< uia{-ف\x,ς}k/@&Їuהd;E+ܼDo ԞT8! 1\=w(F:O @Ӧ;ZIaUk/\sP7!LOmY^qӤ v&=' \M8^Œ/_:ȬܒyG;c:1lz[tpcRc[ƁLp(bea4l]UJ5~_XȣQUԾ 0iLrKԎjQh8-(:1S]ܽpw2_JVM]O/ΩaM>GM_ś 8.C܋$:Mݥ|;nr*EfG+^B~ذag Pձ<>T,[F˩xNշ`fs7T\*2<fhn=ڟxL֚H~ҡdx_@mȉnU[NӾ*Sc4zy' .v߃EV~?Qĥ JȞOL#[s%,1aqDD$w#_Hh:B(68滰YƸdW*>^dn=}ߒ<?ּ5tsGa5P*#A|ffZH -_[EXP`_JV_ L6,TL.0Ct<)YBV/x2^ؽj'cvXr\,﬉TQEG;Y ̣#8F 2Ɉήbu BM9/I Tp+x〧}E˕rx4IB@Sb(w6(璇Q'uF#s=D(iډك*,~\GVDٻ67"wIʳ~)s{ z!:7zT~ۋN5/n'mĵJ$= .w*ho* 1>k_bGkX[t6*ة ]܈$ 2 $Kf[frFtFVɀ?Cpwh$)%1x@Em ]]mƍM6kUlz]V9{B9Cn&c5e0|OK@bdVd^OmIߓl -ET ŀ)"6t-{^.KCF-Q>ͻpVf(XWtvJ ]צ:ɑn0VﬧI{AN0gA\ۆ|c{0|*)' ޏi^N@7=㵪7XØCZ+[Cah)2J_f[ cmr-plYIm iΗe=a= ^xs2dm3FkE|]o vڛp6Шv0X߾ocㅪ Vg+cyt`ҷ} UhNb+%TگgGǙ܁C1ysI#G |dc=CAo}hn'P8Uѕ9zL u@&l2<zʮuN\ƞ)MNtvbEA0]$IIg1#ygSMAU9I ڴՆ6ۼr<杗om`e9?G4$|pR l%}ٍB/`YU|I"5"=``ַ6m |t9>k3,LY6"Q ƀu@#l"f N$|jgrDZa˶?b}H$hGY=0y)G7VYOMK +)VK׸e-fI2r5 +=qy@?^ aɮ*,=<`hmhc@;bfj'@Nó%Q؈$JX06u|ICH{YGL iN%J-~'zt9j%>m}]1 yEP.^WN{ҳFHLčz xC?v)Mh:YD6}[b?*ٺVC7)=u8|xkeCЮٶ\0Ġ":|9:*D"j̠܀KU@=[=igh>d!ii.2ThGT@ }\j<-~ g qAګ1 D%4l?gAm&Pu/cWl+HXS' pkw~Ѹ Y;CZ7 RKEKwJKebɚ yN6X<~2| X+(Q \wuC0(39vۅS>g}bEBB_i-':95AH@FC}DSu&Gt "u;`[$"3]5e`ZL.};e4#cS=~kc`\q+j ^@Py$s`qȸ찰_[J]p7.̈́EdhL4iD^Nzi8hcd0BN򘈭 +Zwȅ]/c,N>Y}d}>p[]f+WuiOA5e":5nͽ^8[mWH}Ď|'6{H_>ӏ2; FG0i ^p4miGܤ=vdd9vUa{Ue;;- #K5%Hn56Xw/G[' Ѹf:Mx8%$˹*!*Y>t3ÄUc>wL;ܬ*ECuD71R|Q=0rI,@l{[sȚ^McGo;=`"/;ҦϠP|6Bc۶W>ȚaVeۺO_a\Kl zǨ;_PӴu,·M kLqz {/[317"+Tx:#@#XQNa2h7Ps_M8Pi?Ԡg:RXOMtkR|R3";cEӆUcJ2GL[h "6ħctȆoe;RN>LZ@:o86nqJogT)aƪP!fR+F0Rc/9Xh. OoRNd!?GLiAeFaZZHJFc;ksޣݭ@Ciֆuxoj侻#(Z"rP 96&0 BeLy9"2_C0hUl&P/$POuDf[E0|9g$\ՇV^_JE>+Y31w'@&țN&# I.vC/NA(%vmՙf+.Vu/p ,' b?eMt߫ؤEӎTJoTrO F@nލQ/́6h:S^W$I;vcXCALѨ5}Yj,MinLk}LpWIrk6M+"A`oqg2$`IoKОJ4YN؞C_uq!SȖ46 ZMջv٤:g&. IX쪀@>)\;XѮ<=h5Z|(Chr%@\isP>ic*&f`vw}q?_wc( D#ǯBW4ԛT{`cN;.|NU;Eor:Yr~ \'2)oz5<ܑ7C8nU~mV9gh{#$D!p㑗{ǰCz6;Y#{mh-x".-cͫvDOc"П#YBPuc2z D1*SPu-ĩy*e7wFL܀d@ΓCu3E܇:FΈ^DC j2]'+ӄl`de-l%n̖XWkՙj|8 ji7}Q$ ōjͺ/&^:ugMNWt@oۊ'\ G?m"+QY;?jHRmu2hE`ܶAsZy`"N+."ќ)E3B?j%d &fzw8u0Vas[6WFs U/cSKV %f+y/(K*+Gz3Ω}g4ܔap1nBĐ1mNQk7{Cfٴcx*B;TW}[1XjJe $vy1PY3b;iH݁TMVd؍9v 귙|fD(BJc [ <|4J9pe=ѯ@}J1ɕf||$/fRCP1)v[%El[ A-1'r.fv(C=|?_.::xj8IGt|cYҒNRzIzJĥ0l*ZJm60 S{E3’=~p93?Hw7ձa8UCR[a şij5[/Pςŝρß_2!UnG%؞B]t A-5mƭ 'ZfJ+`|KlqX3XM@/KC99`Z~вؙ+\A[ĭص@(v9tqoɾ=1Ug"҃j2¬.e UK1Җo9hΜ`Q1]xvE2.tӢ^s"=lŭ!ʯuCQ8ZAPTuk'/f<"ˈ~ޓs߆YA!/GW2IkWDɨ/8ۛ# #jc `;"h?/@?^1S~'ȓAR4E?-8*M h$X?ˈ&Ѥh6htWojв^nx*H`7u9C6X`[{g@bP 0 0ƢZsN@0hC,2=9[Qv?@TԊ[Gq J˹H`hDI9߲3%3,ftxS('7݁@Wܿ>n}U,Sfk<|P 3.Up] 0-;zK)ɠ S|`șQA=9F>8|8pr=Ґ=ee6qDAW+?ax&lN@ 鮿k'V@@Z'o+1Q$g] ^jdMtoYsҝvy 8d+gNt-Q0^`*ssC|Jm hۜ&F 0x˾p35H9[pHj~vH?Qs\ jk w?s$Շ쇄WIG@n SׁlB*ִo:^<c73QwKÝ$3'Z*JCAJ#TKϚ=P2U[,>ܨ˟GƕͽA#y5jObX~R8k [qyǮ5L*e/Qɚ F0}̥G&V`>q PI]Iu4LqoթUGz@ QB&z^0D{P4(+ax6k7iEZ.yULNͱP̪\A獪s], O p) g3\D8)ZnF+kgq.uLjbzC0>BVvzwX@=9v7^g~y̾˱q9{Ol.%V E,=ea[o!ؽQUP+й:8LѻLKh+* - eXC,.L0LbŃ"fi6ydTy)bƞh6YYI%˥ijF'.?~l9p(oGFKx)9M C#QqkQvYdϑUyb$LozL0"S2A$!nNNnJRQSɃ#Qa5ߨgA6g7#Q&zQD }%" &7AP)n5|+9 nVZ}#ⷻBѱ/'ݠDLh&0jaxq*!ݮW#g(yUD<d4py3)LEﴯC$FReBБ[iΝÆdCt ?p3jS{؃ˬ`&3L)UaK=}hI}I y tx (=)K$zrp,]_oP0nYGI6F5`j !c) ?0y[QJOI#bsع% =[^/g#W0qSӔsZ &́#AvƼŖ0?qWZkS @(L r#S!Wlw_0$9m|I0K򕙘fBpj_Rm#]Ё+4CM HFh5̒ʈ7l@Um<8Sm/ƻ)hJRȴna9°MzڙX9B5 !O^IF#$z=Xj'lgXLKߪL=W}-\Y/ yoioad&&,jMzohE!ä)sKL3`XShx{ǚcvq4u¼̨6hܝoM`M|^M؂s@jECT*E)n4߇+C|H]B[δM*wWy?&4vXߩwm`&_MδnvBF LT̗%wɇlnB憁oXπkM*X? \itUM2jTwK:.8':^ [ #6vg&"tƗO fc_V[نf#WNyWof5FppC'J!TE.q-&Q c/0f4Al*1zh +kߚ9u}* x! 諭a$VIrj& ]VYj.f4,1b5< M(QkoJq׿\nOv ,hUqVg xSt,MiqO ZuLPiŶD=Op,E* ]H}E._swz s/ Pei$`~rP=hµ![/q3lrjG PY6~i`H 4d}gΊt["e'jMl?^c2ߺ"R77 ۛƔmDTi2n/ΨCUh_FoėO92T9:8\ {jD1x#+['p8tϚfc?p`\bsA45ُՙ9so2wҍ1NA{%OVONJK!){n_KtPʶ•Kv ;kϴD0 :/\;Mzޗ- ,^hj}b5*eݗ:0IQOR]L5ap䚫XkkߎZG ;س݅{Y*$@ëx=VU=+FuoZ-KG )0sMZ6 0 }۾|t;W&Bn[Rt gNef:Ő+h.# YWR_:UHV07O/OKsW`^C9S 4"o27avp[*G[у PafLw|oʦ}N|dW*'u0VB J}Uf2oxWO!vHRd֞<*x4'GPL6sSr遭Djwp-eM ߉+qh+!pPR;ۍ۾.ż3H.>&a5A./v)Cwd#@T6-kD"!A1 )dLwx>b/1U*)IXA2&|#[*;-#L#gr?9蛴l[s׌vyG=3;pX ˶R$.C 6u5Tg0Y =fdz-C*-鉣 *}[6Tfkzb*|4<0H|f_pj= <dˤbGHлXeFH8w$4126mItVG規Xqm qfMnDjtq K]ѲTW B"( Y^"nCfVqz )_ele8QE[a6ƾ)X,b}+"?X$UsԌ !Jl+WԏQW]1P38 ̱stmmň@s*< y|㷙V 8`tTxZWOꙋ%y&BJ`t!qȯ<=4;oT* l]bMg7־ N3XA:9~&WMXA9l?ƈ^߷yF?G1P[HD} bxGcMq׀j8JN`4ͻeҕq6eO&GYc2uB385p~P^vrP"0 ] SZ]f*?,r'BJjtTO]ŴIM+:pYV v)3x+Et)»|Ž>~z"b }#pJxU)M A!A OI?JRӑdrPGmA9@;-ڐj#3WQvzl_ʃݚ˦Ho_D::M:W- #eSL&@W7>@@@>{찌NB 8 U+\SܖJ[@[-;AU,Z@gMؐz2qud2Or"Nu7ͮΫ'SuV({0LB,j>`(00ՍIVG1e)YO%9o8nMWQNn?6vLT=03#U= #]b^ z1G︧?IF{:}P't[.$]hk}yRQ dps d:?Pw`!G|ݷ懋U},ME?g!"(D@j#Znӭ:^!m"]Tb8j)N$j8pdjGpn@WAm wBnk8z2#9tSng ޝ$`Rz݁L9-"*krPo3ST<}1#Z*:I0WVï6G[/lY$ahATjJ9G~iU 7BH-KVyx QmM ѝ0$·|Ě3O,G1r.:HG$+/.Kn2s 7>ہԱ@XL^EWf!/!.,\uEi%bP)H;zM{J0nybX憤f(O ]3 ZspVםLjn&!X\«CeFs, ͂cɕ@)j]6g OZ=l̰1S Ԇ6ђT1$zM.)E2R_ ݨȘ$Muu~# 6n'4қMO|F0##VuTR6 NLlpWAdjvU>F bަI}AOm@Y0vv=bw`4lh gCd^aBg˜kMTŭEE`vу (wgwFʰwf-$Ofi1* ܩ\u4CԂxt"Z֒:,ݶ? +G?WaX" R@;.@}aMk-nhy0&(TV>֥2 dd0&BTXVVcS2{rqMcC2b+hBDzƑU r'QKf w]uvi~eS *kĎWHldwVR~'cZ@rb6;t@3FyQkt*$ zu 2qެKe]F鑽tuv7l_(!&YEH渱*E mrqjti0>}si5bk+P&q.E1!L^PydKV6M= +s>TEm$Eo ԂY&R9tAOIIpj֨S{^qFGZk ^ڏ->O5} - .=b$R{'QL `{[s~Sؿ/K;nFse&sŏDnV!lAw\eO3ـpay#V PnIZ1d(%fރ£ I%ĸjRӲw2hhMS6OJ_n?] ;[Bwe+:& UD&^F0E_6 %oL{yj'c\たa`~./(gl\Z%5]vB9ڇO#ʩ ـ61fP܅@6.nD.>5/>N{aN8D)%"|ےkM˂Y vWHS]#WM I|Q7E8*PqzBnik0-,d5h|nxF0\SVz:/;%ɦbeUGuEJl~\U%6fx=D%`uU>/H+BWmِHuHn_U A>F ncE:fMꗗuD B=c?뿰:}M71%gmn;!c.BF pp#y$Z.?,gA춀F{q>;>H*bl3T>IWh6Fc=?m; ;,t:W̏2in {f(I&[|.N&U@F՞Ү$fX~ ӵK5ގV̊Fx@X*ZݗZ|䳙 w8\6<&yd/ 0y@>ls%TU(=BkVǝEǙ !k>T>2Pq|5\e[J=]r^2!b*7S!h+lkŵk@*E&{ivX; r#pIZ6ݕmӞIZr쑨 C 2 YޑD1 hʑmJS͇jq{wcٸ՘Ɑ,y2]*ĝV ypC! pHK$Ni,{o2ey#:{q2t&7TkX$~$mð&nQ[zY8Yyّ۔xuޙ][Xv`xh|ᶸ~UIdr9$Ƕ](S9 F5."BE;5~:q>k}b_pW +Ps'Ghc\6`8 7:Z1xoY^!nOcòJݼ0VES{EBzJ'ҍ /4gϯssllvH?19PJT"n8*R)d 5 ֣] p-.'\B<6s O(>)ϊEp JXWiv*ٍcwg (}­ ї P| / < ȱyTN)FxCi8rx| a)b]}O= '{0G&"} 3wxۚr[̌veAbAON)pʱCu0Q{v}KzbGFJZڵE;9 $2ޓ xȇAKZU.{sM!S+( >u,NDӶ$Sá%wΆ^^(x+m*KI3x=M] gBS3QJ5Bή!pcphkU#>YiU> Ȭ̵90y̰x8uh<3jqgEs"/G;gnwW5χ3=n0`4UmQ} AC*&&ўn8H)T8HDbEespѽlsU)]ZJh *RP}OSV/Z?]UrQ j׭vQ?&QR@gӜyG^ݩ7/YO X=C[α>-%ԖjXB{8yw=gB7\﷩}\G"F{9Qwp!q/L-AX _ї̷^g9Y~icɤWŸ:'ߜa)@pB`7L쭕2DLp .}q ~P(39惙q>DhWbKۊSvh XS_ֳE-W7.gg}GuꕄC9%4hgdR:%lM ɠ߄ JutBg*yCApSjO!۪KeU+\|Hr 9-Y8'S["?j+1C$s7%z5 h<=%8z8`*g94am>Q̀WbI˔m\q`%VCrQo! Apd\;.Ko aRԍ\|<_x2.8x7W9*S/HQ PH2s戸}Q8l{a4ǔwid/wAF[w }k0Hi ˹OeefH,;?j2v%4K(G) %PpԳ_7- lxK! ^!,6PYLׄ#'r?۳!} ~$'Z̵d4ӸCnpOGl la9ǜ;3Q !=u#Tֲxd{u^?ԣ(I3/Scj3&MR7Ķ(,O/A^ܙgq''00DdZZnz2/>+y8!wn\erFH9%k%5vCp~mٝoVÞuL %5*bJ}W.k&kSIi7J~H$W?V~{m{|q^D~/9Ј%c=W|d$4!`ƀc{wŊF-55 Fq35W)>MjG,Η?3s-MXb8AJcL &O! ±O\z+ kK/dybKQϫG0 n(~H0K,3ɫ'2{s8El$w0;";`}?D|KXBb4ZLpc0 99YDN1=Ĉ`AtiGgKm,8;n[BϜ']I iCŞ#Ԗ]}_G<ꓓWuLД[Q{i6 O/[WO)D*p ռt Uw:{-XUՄ'5#@̆xq %;hH.!jqezK3DQ~ /޵C5DsX@}@]+oL؉&TYyV8]@ UlV[Y1_7YT:eNþ4Bz` &M04?":4* @@AuVF1qԓS.^=XЩ!)"-{F"8ΐR" c⨧r_dqɮZ.s"MYic^Jg늚CtY~m|g+І.m2M'l`ݦM8z-W0PoD8#l50d470-0 Qm mM/|zuxȀ;5,jjTXؼ?_iܚlXB6"K\Hp/$X4|ԖYlnZbButC_k7ѩh>ֽ,zni vVsvmE%H'#"clt{@ddu0hiIc)K~q1\7壘X>WZJ2Y9l,_nޠiB%Z?rD fxN[1LwŜРmTlAxsq'ERˆ*D/v‚6pleq^윭~`]lɒN+ 0OE}i]m(L'iCɚ'.M( 9 ~/ ߆S% ^{ ^T6M8͌^_BFm~ "9͏{ٿO^*pTZ0os|xȑ{mܚdt]pˆA pVH&G:u@o=gyPS3ZWezpQO4m-vY(v VT3%I"o;V2pl.Ncc!QɰYtĉDa{Xyk!*=V B zLt ;4oc\R9\C`vb廉c)œ0 ۧ؎!o|_s ^FN5B$W~J K4mNy<]șyI 8&G-,vge84.🦋U'J!ޏޯhe?,j~i]\u:a E=x&ܟ5-$ +# +ufߞ6{Gha͂w,e 3S/0t}9-435)%LO(fÊK7D|(T ALЍ ׄU[EnSSQHukRV2Ma{Fcz`V}S9x gvŋ9HLY'Q|Z4S+U Zd2r{Q4(8H(pq˵~6y,$u5(X|#7Rǹ1qĜ\_{aG!|!\lhLnXBr~dr7fcoHi6P45NS/j:| `Hp{B˪E;CIj\'x3xNTg½ȃ FkRZ &2*y XAjlXZtVR-G Ó7#FJ5kS3ofޗSy 47Voa)k$i NδPuqAUXטH-$Cˆa0TJ|q$&1ńNSTL39Xe,HG.e",yk NRO1RmhM7_\#ʆ=n(]Y2*nޭK̤Qu2wq!nM cuMB˔B67<uS/rQܹv ha{R;iLџ}uddw"$4$zD$[~XV\O QU 8;\' v7n})*wc}-Bi."ݍxxZsK%wvo ͥ^q ~]Qc|!9|Y<0`[7^׊S"W9"QZdGS'FȇM\שA쁸+ȱ[-Rĕ04DsiA %kXTiw12\pdY&wiwBJ'wmΏRyBv)Šк,'*{kXNߝYl "!%bBjoWC ^L'='`=wN(_ L.<>>z,SŀOQ1.Xe2\aDoCʕ8fjMX d^~A+|Ug ΡJп<@Mp^h :E!HDKs2N'AN -(y:~g`޹Nh~CsN]]U$([T\opLɛ >:G+Ҏ9[sesz<%jYk>tD(Cg>)-%; Wdg|cAYpsamNwyWGzk-'Vlti^?OeC~[Du]PGדZEp۔$JՈ=6+$lԽ@w08Ӏcgc%R=h0K6nC坁P! #2 hxe Dw!]78`:+ČdpH33@nMuQ?r'3iL',NIV{'صy*@>I rfS+ԾA}պvH![>LT-,s58-P? i z>t9ߤLJ&ŐBp`6mM5d?c>NÄ޲-@ښT ",_^UGK\3FJj=7@,LCkeaߚT'0ׁ7à#%~ 5X-6bӔ.W*=Qgl#:tg5qI&׎/J8lb-2Xhe9nm՟rYp,x(51_sT{C t*dUUM-f8hEІI(>vk4~C;BކU ](rۋʭW]ͷYZ3uYv/cTyN<;L}Rʆ1j\*- VB|¾Pv=RB$M2="Vٷ!yTL]yFU(,g͖$^Ly{^,"9.e Ka៊4$xf#3FN:0J/ߢe0+ZgƳXrc)ڨU- 1/rX)J"G`+}P\fSQ-0ECJ )J!vg [7uмRʺAj/fuF2ƴQ#%`Z;[;Mzmiae?y [QRR>=dԝ<'uO);(EMC (c3?8\h]/`dro#p.+T)3 WA#A " 8(0r>~fk4LKLqSd[ڹWS;Te~o+&hwyRg 0ɬ 1W9/}mr۪+;`{'u)_{}rUO*ALrw۳/lMm5|౉i|=Mm5kO͸3SůrqH?w5s EWXZk ]xyX9Kp+ӣ_UPOzu)H0X[cc9$ǮScl{EBo([F-R +=dFAcj_(ՙMd"j/5:@A Ȉ0a/K-HcD[y@=Iyu6I")ZBc ;sVn-:ZrV{;ZdEqx{I⪤s1n~nU;at>\OlZSaM!Ԕ<4 vd$=O m\{ X=c2dz u {)撚Kг`1<>˨3lHV_4'-: ߣsud촻8f ZIR =AOߩLo"u)H"WA0_ga&0V*(qʢ{trtG"#§4 ;=\ښʭhXH&nyGپ,GCYдhW#` B>^Eך ZZ߲Fb)1!!>+M2;1SIEi@5~^q~ӓz\g;l:@76> Uj PsE>&jz {E௚A2yfrCKo56Y#j1Ot{&{e%*#[ҿ;.WȅJ.*|I 'cS~vnȹ/aRФ :Dߚ n^KfIlF L*sWlPICs\Y}yys]b䠒iLN)7S4y*]ңzdHý"ܱ i+o~gX3]?Ͱ5MO4 51 @jmE]qtgGuV(   R )P N@8}"&_21hwb˴Ԧ|sWBZ>#)okw[qE?>({ౄ>;b2/X]v0}УҳA%1,f`w|9@"k-xVBAkކ? "6~ݫR-\ g20K&JTwlzf{VبyB;>W !o[Z O-f*yާFI1tH}mub80cf bhߵ5Y``=`c 6\q0өcfJ]Yl@]+.gJ ^rGrZOw=vŝ^ J:|s%z]P׫;(E2/4"54Ca!OH>Xzro08O#wl-ZCjkjiQ9dr Ek)"O^NKuX|PBWxkR9Ki_uڟ\m?uc,ޟ7+-$zX+)alwYu-=]<Ìk5MWHVOXɬLsMyM‡Ip4i?wy"Uulxnhd"Mm )LJrz| ~>9Vp{"j_xnf [<"+}3j:R"ۅ= [%f *N&6{ / ZZHԱ;zwLYt} Rp'`+XgN ;|.W?ݣho$)-hOg{CcΘ!p_XkӫTf(g]SrX= Vғ*(yͤȂ5ۦ"tbo;\dW2Ps!؅AVG` hsfY3;@>S!d|0= Jsl&#ݽuKvO! nwoa+ϗmq8))>@oc5@6օ[ Ŝyzސ^=fCz#%_V:cX 'liG;+Fi8H}y͗1ps0zq5&aݽW> 3޴w/6G9;'0P)@sʚo)G|EuɹHŰ}'0{uVE[ؙ v벊3q`o.餷Y;^> j]ɄD)ͼOPW_ t&+t14WO,]||'5tB.$9'Z%iNzh9ŽMhl:^Y/O!o@cYTLLh\p@D&4榑]̤kP'>bkLn#> .ӄf$T\Pe'LH^jX4@.Z?Z:W X_Z 4dS[#ׁ3Jx'kѤW`_FkYИƌҬCkm;HlҿH̄$J^WQpc,77 4N몰;e3n`\3`RDmљԯXɂ>3#WQpdWE[0c"!s5w03;,m/̞jd6LJ\Xױݷs. r>4*Дo0CTwYc#i4dX_Ғχp Wmȱ& Cm2^%b&/PCH˔%/2-.^R bsY9`하bDŗď|̊` 8ߞA;Kƥ\Ƶ_r*`O1=)nwCYj6GETnXHH&C`(NG@>L0nHOX/HǑ&X =m:$'~o3.?}⍩ܔQKd(hƑQPpܦIR_$ =X cKC-G*0,Sm1cw' ivG\tT ӦFD֔F11mv,LhcG6W>Q;9<ssX 'D FZi?=!M^(_c7Ԑ~ᩐQ`˴I,aQ9cNya%h!p|EncLj{wXc\zgy5_ryLǸ;S~yE yX8pqGh\֕AT,㧄3sZ]Pn*J\ j&sŰCəNdP&N#Ir 8!|6^Ƭ y ;Ve?ddR"|<9UP0X8Equ;$v0/Sd}6JK0CA>A:02 I p Kez1pzXLzevdy*_w_`L{u~5G/A@EskOx<2~MD3 !Ycr C5˰o1#n NFijOT~ =#8tM|GYRC"֭qMn)>gm|B }=Sʉ Y).*3+ێX͂G2{Hz-fGQኀ)v.'WXdo3vTQ=:3 W[-?ziYc":IxS%qgS<3jM>h#,TdI6^.⦨؄Ohp6W-Vqr^I+nwPUNL!LlԼ9_Dt٩EqMߓd 9 zک Ex~#:q=sU/!\9" FrE?J@ ntC*V]de4S@eX3T:m KmZD9cuj܊̰wdSwD_xՖѦ+[%AV( Ȁ2HCH$X2IZ"r;TWsAMKAFd1~,>u2B}J_%7|َ갧d#rQY's"U%fh.NR6%sw*@ "+9T;I:ѕkL )̴ہ3b%y1UM U׶* 1p?%KU 9xy0ߖtD !v 79!9ZzDXSXP}Vu)D B,H?8jdW#62tppN]'"Zf*Ty>9<ʢnelUS$@0T S^@ߪ&$*7RZ֡T RAIVLh9B(jm;_=nO!kFTCKtā;H?(=> iPtTQ?tt" U g4MRgeF,"HlZ[$JJ+<Q-ߐ5*0:K{<9Z᠈ms0_>{'BR D0zyBCyZX+/L04 UQR@os "KU{|72L $4ywcWOZ{) DsD.ŜTPso^ o%zJY-tB8kL6oH9k(y0$G6(V!жrg0HR黋pI"e4J%0f0mG9&0ϰTXܠSVbnY^/DNT0*_ a)qIaĹBQwex b~&O̚Rn_4qߜx}z7X]R&콄\=Z;RCq]u Vi'}l1zIl R =MLk$V|z}}Ai> T`4v&CI٫+bŅ N :/=(>pjZQ6@O"b_g:~pvMѬC'9Pb }ż[1uI.Lw< fR#;4΋2#Er`j~X@!/Kzr7em߈~4p+Raz?%:6IsY~mf+֠榁Ndo\eg$ g蘆f&t+\M<2_Q'5Y7&NO@,/O|A9s|W\h<^:zǾcܳ@X0tg"6fu"@, vgۻuWcwd~S*TJk o+&6(q+Nޝ4OT)Җ0!;M,";H|&=ūչ+w~Z/2a*@(}~l",Y!kЫn {Ji>DoDm2ݬ,4pP&T _gEf[B_ 0j31kAZ8g&%w3'ܢK=PW_D"[8:c  pmSp]l\.xm/ơMY@`쿬k>/W'hk>gRkt"M6nj5}@I@/<$IaEl/Qge/fz 7]ɯ|}Ր$(8 ($cEᴺ2s' ƥ;H-lPt ۙ\B0r >XJ&GXߑxuEhGEGe4V(v7HAlz_sDI4Gq'8\o>K.uz"rm>:~0c m[ئ'<[kW<! $"xpI>zEibZ@G]6٬mǃ:ĔzL)^$mVWn6@M@ͤ!AAVXI"B$]oŏ ykM(/F:pCM \v7a+#/~g)s0G/F@X޶bG7a~)OZyZ2>؁">fa&|,7h{2Tfz[ZSdxE 6{fntj:}ICE}Wy4d/Dis^3%:ux^\ K1`|+ | __%_?C>.1x3Ŭo"x1ppB!]:: [7qEx}~U!HLY!yw'[bٛ~0*f@BjN{9d*8?OAE<ړT/`ȣqZAUn3QKI6/8>>jF0tk1䜮HTȊ`]wś8ڎf)Z FD+K @vbx'/{qZntZ'PvXB^%!_\(qvP NTiX+msu&ɞ.7)I4:c> hhmAoLbdZ*Ŷ`!PRlqPQbP`%lyԏ?TJZ8P\H frYkO LR(}TB.j28r#=(HE.ӥ?}O fTvs^2 qku[̱hjtԆqXڀwOpDR_^9_2V&ĬiQ4INY@JQ]ߥw'QV$T^T 9Ѐ),MZzң CSg T*tI$zoÊBJ/EPr/aT8(w_~NO] }5$ վWRqn^c~hgO! *dMSț ĘN 3c $z]4D-,69ՠ (j}/77eҹEӼ{=cօڡ7p/ȡ-M4MsJvZ?S0"yepĘߔTra -D0TJ le6^SPȹ憌Gغ9N[qqiP7G?T֝P yuV EAI֦rBl97wk{J}䗫4lS5ŸWCDَNeSfv(0. h.mfhrB "sKPW;O Yptym.l+[-nVV؂I~z@xmAJݵVn.7|Z]l8&評+X&ݜBNtLVhMhԭ" MfGYBt x͖z9vbX2:~l|lMvNF Nm!b 2jbJ.*x29W!ͻD|st+A3S\?C˼.[CV@=#;=Pw-upZN7p]5QH/Tfvܻ``iMA3cM"htHZNU}qWa;sېvK*zJVn aeDt;d!$&"( l wwTۜ@VPnMuĞH艿X{{lB8ꇨ191@.nrZfW1 Y] Zߕ:8aߥGLf9w$q3\jA9 Խ=Zs3Kv}fsh*ݛ, _@ [);G4qHݭwhQAX:[`hy1ZN:-o{lEt|™ʝi2Q/.w_KÁi"1bV_ZLU ReHQF`nv}k  0#V.aR T!*zakySl-Ud" {5QEvA(P >ǥZ@Akk!qΟq٦^{UXΔITEP9$bHD)ՠ]ȅ&3@yŴ]bW-X3]3tǖV`m,L:};7'D -nN@HFbTi|ŘD3\ xc⯟Hh[z|48g[@/OX[-"8Og9s3*0ı:l!a6<|q ׇ'@J1%Gor8ޒU0SmպR]ZaAۨU |f?7X]C]piGjlp Gʱ|~?k? UC[' K7Z}hQPABEv /?[=m`$`] Pi2[X7\iKO 4&T_{O &㬤aǏ8AuGfjӗݷ *݅QҸLaҜ\D}6KBz@}Atd*<}1P0.܊ÖbWR?}к#=63 g+dEse Dɻ2NLY.%dJ컾ߦq:uzH*1+|8<]|SêjqR%p#U$3>N"lX:Fi j7΅mR5k>ɲ7w㫴л`mLY ߺQwH]|[I+ L/޶2u߶Z#U~e_V&~f)v246.By YZ>gdvZ/tȵ0˾~n `B9c?,9;TKZM12x XzTZ@\5J\J !k$+[yhZ‘;?摀@2s*vV١ vf5l/6u|Z?: zh^{Y-)ȸFzdCtϡy+U~FW펚`l45Uz= q|y,QD Œ6|8k o܇B i{L -rtPթ;k?!r {EPX"A$8 /<ؕ^AtFa;!wZI="n/$rE<'{%bƹ5\bK4h`F YpRj:GsՠvEWb~WwP~&WZ˽}ǃ:ÁFw_V~ѝTp%!}٤:>3M^PuvEƊ޲r(V!B;|' ֍Y#U}lC hDx 0׺n[!mM/"mKIVZ:WۘW @]c5=%*d|pm񦊓6R<-zUx4 T7]p7%"5W Ck]η6rq> n)juX9|)e>W.~ݷ|'ёnt~ĺߩE3AmPm9C "3Gq(1.!c9$w@&С' Լk>\a8v^+籀Qꨶ%hg~J>O\ S]T `'j?MWbymrL24"c̱ :BC9ѳ /G/KAʔ<@hCĔ_z+~~Ψag0<-{b;!?1‹՜B$"z8}Z Y(J6tt31S؆:&XYq[)OyUY42(psFտtNevVzBTHs`7S3'8o~iԿ鿰٭VE ゑ4FLȺըnU]h9}7%Zղ(-18^4 KB"oVr,w@T/Oaept_n}Y<;c,sKm0'ìIாWa,GSDS˰Tݝ#OiVq#D~WX`\!%t.b ċɷb,nWb"*#E_:B8]޵.i[IgܿjBȀK?Kƻ-oRIߺcC` 'ʲ!+TtbH|Pe7 UcPiÈnHN72R3d҇" 4҉O2 FȔ]~`J]wbJ5RAe2w!X\\#wݡpSd i%#pcdҗL*l\X椠=WcFUq=7C(O)&y5Ň,sZ%Uvoq4-xuS)rg4-֍DيP u_l<I?&wa 7L&H9h#(ׁ6s-O9< bvyqF'E'tDBh7ԦVPq7u]3yz?٣$3&]VNh V[iX3@|z*҇^ jq:w Hww/M :R`ӕPd<fuZl:\8-<ܿe+ޒ,캾Xe#AC7F"Pώ97@$8oFv" 5 Ob)v!==U`lt eF \c%8"kɝmVRpdhD"aoцmjXE:H*Ʀۯ%tE$F8!S7]kU| k`*q:,}ް _;qz`YGoaҜ7D5hѭ\$S ɥC'KI_ռq$yúDaS-?J@y!x.9Ѯf4/`}h1Voy* bg]b,lQ{mB +]/LAUҿ {6 ,_@'ޅ!2rM[?(o;+`GDXH0 rItUf0^V#hvT\?B*)?Vc3!:ED䃌E[:pd.<"Mp0Qp l@].٦/WL(U -)kFMֆKê;.>`.Q5Oܖ޴\]rrV]͸)bn@tXЧ224St 'Sad)/Z=`ވdy)W&#Ġ2\p >㎤Eo* ʑDmF|~!]9@n)0Wܴ@ZHto@Wu>0)"_z_dŐlXmsYbiğu޽4]^R8x[gL6͘zs='izQ,#[i  즮+!)AvzkW⏜"(*$iHI7.rnYb,{X:rdg'{dc&} cTXOU?YSʂ+Ac)0~sN$s.W+y=ApzV%.Rɚ"?THedr[Vn~4"d-ȏwhWےk,qGEacb9U[%E$bu/lׁKюdƻ$gsĞuwY.dV~l_l&;bA!^1G,K-J~{X{gQEsDKZ?Z#3n1l3&f/E-} kH&:!ئ mtW]9su$13s΁E%@ Cc-|;+BT.3EN4[D9 ^w\+1EJYSU6`TeX(Hz9m8PI{=9g~5 +Į" 5i]`aEOJ9puW70=+R@`~˸AW/WvŔMF2$m WBF/cmZEQM @dl~ Kqbm=m!1apexq:XV5z!yl >\"%8њ{ teul[~NxMC_G$vޓb%,DG{ ?;ŕsS܄,SؙMq(ʍx%/51tbR`z$ -Fgg#K Gԥ™0*]ӷ )#S}WJ6zG~%k^miq)w]j 3 Da|b!B'֢ W eZ`Sk[ݣ'2h}K $Jv mE" w~&Q]1lvy9|ayyx|PkN3Hn`< 밾)|k?p)FS2F@À'o.L-w1wx04˔U]>瀂(tͻh^&Ň`^nLELGUZf&U&r 6*P9RxjHzRXrCnܝWn*%ң|DTJ P'S&n\ˏ ]J%mZ ES*2gmT3)㘧5YZՐplp4?g/DxO@ĀhՏ7#aO-Pq 3ezߌI("l!Y5Hv!!ĵі[{EiD$ 2cAƻ!4+X]u36] [Oig})XWYp#aodw*^[.A]FVS` Sw2h- +b!.#$U=S =nKn/τv0+⫋ S ۍȳ6F gn~w|`u˸^n*rjq D𣑈0H6C҈g``JQ ɡk'o6zٟB-!M F^Vi@UI$;"e|Ԩd$[GMt8:hE >AxEo`hv@Bd.0҆拝T eʜ7šF Ki.G lgC <s/N[vq5A)}hUU kU{Ғ4&"o su;3DĺBT.6=xm*FZoX9PezWij dB\b oȝi,U`lo1YE@|/z0`:+tLCVl;,\d{VvV>rqEY^Nu|d&ts+}egSe) ))|l=T`>m~;z]өN_6>=8A8QWH}gPE?+B;R&ٵ"oZj 3d5`7"HƫpяV4!MHl?]rVeC  l&_#997#2W]7ʠJv`z"fyzDЋ ^ /l׹cEXDJm[]I~ m`Ǵi͔cp3ʴ#:Yz2(x8vB(L-49e}MhԵ'qY}#7EKV 󪣨8'wC&a#[c6#Ǔh6t5DQuO] .KG9 L<)XP_Ʉd }Ix 8]8Z!"=۠=tC}7M*Y2g&%!W` /' XyJ"pr37Kp+}q!u 揥X\#0*#-Hrw :Q+R P=K?]&,PAhgBeZ rSk~2|Jbhؠ!DdBBʦ[@Oyy%Zұ{^3"JCo뙖U>sDTJ^HgM2om$v1D->%kCݍg9Ǧ]U?>-P\8 B\pjvWXYcLe~bp,gh6N`,lOȨ7 Zl3M׵rʩAjŴ> P@ì^a;zMx*" 3H89*m':p l2@S|C<[AiVж\%>)e 9NiXc=$_ hA- K1C4v|ƂQĜuԡMջ,h 7$yeUI-f5,;^4vr,< Nч1=7.,ԼñM 7A3hJTOi7Ehj!Q6^/pVE*,͙3/ZW>sIT8,cIj)¸2j<'H؜g`9#>%3r ؊I s|hKhjQn]&>{Zw<!HHUI%ndyoESTBD1?S5:6㝜S#&J{L5׎8Dl?ݚn}XS`xK/6_;MyA⾔W0^b۪LyɆw:C 3 ^ӔdПH. ə`avsA1>t;Y 9v9 Ǜ-u3bLBTǴV&5uzasc+B_#I"k*t)H)of]˪CN &,~Xth&1\̲6G/:n" }1|ķ>%6>9> ȕsO74N]3|`0NV{Jه㔡km5@t_lGV8qZ_McJ:l"W&5f Į4M|%zW"5*j(~ fi,Kٰia^8d<=*I n8EQs[tAGe) %'67IG"YX"b;Tkk#k m"}Lgb';ǧf?otX9f1goV |_ӫB%kTJwkry|\''J~Z2=/ru5tMU|wͷ$1⹱?]V\ʧ𶄴jsbKxLT{=P y0此O tEsDfzuVփKXnt0vY@B_q3't>16rM?UJ/9-xW4s=Ge =RQzb9xx%1_wвT;u YeIXeF5K90Gί՞.A2 Sm1Q^0G/d,kǻC[ b5l?.w͢ B d'Cgh+Ow XVD>f;}2j妙,€l%mr铂nmQ115@MZ?BU3O ỡ [j>:cu†@,^ f{ z'?WcCDS5HɁh}:-䳪; nw¶iwE^]![,1ˬHUŻH| }ԑX-l|$F수ʠRҀBmL>f+M ͉m^DZT֒j:&]9K.&yx`a7,8m>dQ? TތY"nUΓFRqTo-t1 |mG!kL~K,E_dAʸ 7hi`_}M0k[7D|0+ړ$/.̾IW_W9ꘀqt>gv(spcDp-eqCBUT-m,9{ƒE7U)2)=`C6O܎dZh/?)҈-up.Iⱆ UB.*a{P淞3|,a#ϋutE'˛YdPrp%o"8I \XKږ('gb_[ h\^]jrwlN]<eΠ$& !# o SfA[D?x wfY/S&ʹ*Wĉ8gq¶G jzgTٷ}*ɄvqM Kh#iYH3)MJM`$/* ŮO1U `4=[3 //Q=)1IvvÛ#%,nOK=` 'b}A{ vGJz{G Ѳg V[|,1c[4%A)[E֔&=s'm Lc xƑw"%GLcM d&#;0ōB~^~O"9Vn(sQosw?#fn)`U1 Ft̩-Ѫ)d1ãZ'/hISG$䳦@ۏ]̧( L.I!ik'qCAlnvw^jk[UQbzn ɶE< 2դ_,Ÿ7 {]Csgk kd@c],\ &Rޖ | gU1 ,9Y߹c+8 6Cf|D [ ޶f0()K:fgi`]*nAmX/ؙ gWC"i[GbZg0 Wyu%~6~wܶ a*s#Ƶ؂<ضUէMě #mT&\QTW> ;}5u:Fe>:(,(u}{!v0wW Vwr1álkdښᯬFa /nM$Y2l@έU+j&<7O9]Nღgؗ )-*^%!) `bO | ʘpWRTu+ Ck=$6<0Wpyċ^ʒІ$W`5f#;U(Py'y87tl9! aӠC 2oOGdWs;0U?@nzLoϋy0q>vJw.hM%3Zͥ<2¹'0[5;;Ӱ/S0Ld +!) [:C&iko.W uon(8E}WP"ҳo٭"6| :f"o9~ Sy~ἱս#\bϔQ`?}FQrRg%PźaOlM?P ^]'!F# ͇%|k$Y]4K .>C"q:'. 9dgvrTyDWň}ڿȨ5;?vv>kj 0lTg~j~@[WQ==''Y2볃Y^%&D >.?B\/jDX5WHΤc7L4"JRZ3ED]}om7Wyu|E"*.ZbhD#iF; m^GIOz/#]r,g`>BpPrI0p?8y,a~&lMV'4A$/~V%p]/ \a&Mh+'-:uTkR乭" ]w@7)>s{;pcEM!}Ɯ+xI|!<v`2i=᯦+sM8%+Z,q*X>o=YVGX{ ~%7Xϗ+|Wh[S TtT +"QK_3]ܫ46 083pg~JL[ QUW A_ӲGrdja~/gjnфfr6V51(SE96]AݯZ2o՘-|E*R*i6DVZxy{r}Z =f) ~\!B("n kIWT -lE?j,Jڏق\.V͙vAyk% D;CO6d~e V((GX|QgPP0ozƞecvt)(I 7RxZY@u9Ǭ,gO5%Pʚ_( {nzocQzEv#f(o2)# thh2 pHn0*d,ۜzw']%]--66 #4o^.bMmx zJ=nĄP.̝ʙ!R^ *Ĝ@,9 5:Dp %Z`ot^ZGcv4 XG<APSo;֋ߑE]7RopxP§͋3lc(:kJ<Eό *h֪0ƵjD1/ɖh/ҽ@t>TbC8gUج HImDTv*945@du mu /%nvڪţ8RW_e=PFS-c۰6?h`UWbi_ŧI@"ujfΏ&'.ߺ&M|O"Lǐ]*_-.]5KaY8 M'3RHp,5pGVp[  cS2,/nqM+yyM"#6d+.t4 W斮r:+n/Cy` @:;ky3+_.?!2@؁1Z-:;V cNmcԑ0y6L(u;"5v~"M䒪'Mq05B0#=؄j% 6ya;$IKUGP|HɬЏqeb\+>=i}MacûV,~Q]z{,غnv}$¨-9$UNFiQۓxD#YJشA Z#;XNgdݽTD,[gRMCVBމTV7g%**]CqH~V/'Po,K;ɕD0t틌`N/.}1ʣul|6R$_`mY؄+3?auMgV`;@Wx->wNރ@OwEOMsuʯ"voPaɵ0)1>(=Xl67CImJip1a.#hfDtOxeWM%S(LeӧӴ1C㻷 .'8iH(G)r1oCr>0)106SdUsU Yb}7]Ìw#62zY?BT>c)<#+t+5,oGmH^} 7oN .j~3e2uG ;^Qc=͚) 'zRW8e`{ I봜bt5`v|u*FN?`BGf2۷+HFhiLajٸɖ0i8nA\F2H&zB鼦wh&2^`5X u jj HMN|El?dWN*5#b-ˠO¼3tt ^\=ZͦMz1F%\N+)K&)ИYfz(@oM7|#RVdiu_ñFS4-d>9K҈{8*W9̂xs+T\4j}T?{N ۉQR|llOi-"z1Eo,ݗCG~AֵЖH2ߏ1A< lǦU"U=pŪ'&Tzt\54ziq쌉ʲ)wوJ^yy\)[ft[ڴ8hh}@GZV2ҹjij;9eðY9h@lI _yof̨*x׹9`R K-o .x.0W-O5 CJl= CL\;/c3<%yxܹTk0ݸuF1.G3^Y&yb9N|͐o6ڤA7K#" ̷$yJ`^x߿}w9Ų5*R:]!!>W'^!$,Q("x̞6I& $:Qzbxsуu8:ɩ\qN rJ R}R|GY1Xlh4C<|La°G9u s RkҲ3iUīb.Pt单qp?<IsVh F1wYDȵ [fǤkYsO=b hՑ"^!m-UI5`H[PD[ ^$nwF}"͖/.T1PD+恬Oz;9j $ƒ9ZH7.W}0]V*>ZCPN gLh=7SgWNy'8PHTyM"OKSϙN':264d h1_M);鏯ȏ2,*pϛwmBW=T8#x쭇NGۇo&HwP|5ֈ Ǖd* wrq3rȺ}Ϳɋ,Hw󠘰yX`.E~rEe~hN'Fa!pl7or+1:;[?@;TB~]I葳' EhC)"ƞWL~eJ]n,̷ ?+& ;V't1#0mk[F˝>%'-k# akyA#R"*ԑJV7' fb "*D.6>0*OW7<+p7|*f*VG>j/<|Ak4m~ha[M2nUBH /HP:F6:BOQ t}MjE`_%PQ}g؉+]J}ι=YyQwq~i 4Ǎa!z%b/iQ#Ҥz.Cf}sRj/OTE5U )h';MvJ=7uOb*3۟ШYJ GK\QÙdҚYK9A`鰔_!%3-6#0ݬgSۣ:{M&@CW䇨q]M X}k/}h/ISJPinaKeE!tTm)-=s;t%UtU6A8>tXQ &xymu&jQæ;p.ɋNW$2]zty8sydlљw}%\h7OD!TYXڠn8 3]@7)d2R#3%'ȇ˜?AHΛ hUKpw  -)a&Ǯ"A3Ayۖ=38o8n -w{s;D>_ݫ%xC8HiRk٣rke|e|LJQ̇4?:`sNps;ϋ?@p"]sm%`$}Q]QDTKT1dFr4:dMC˒MQnZtluBY:ppe4u\sk#߄ɣ0YcA>L[Aw,b=ˁA}e-T">zCa ]N/v[p*Q/Lj6 㼳|C4%V􇱤A6, QXL:B_+V2 [{vK0>.~A$p#毲=9"6=T5)sK*OOSK 'kjˑq_NMyI#;/^Fxm ʟ‚^FML0s 4: h^ԃbqN/ͅy|Q 9r4p:"^"蒮}[$K{" ǝ8;w.[a 蚶ԑmA5Q3\:4þSfd,N@r{ ֘ݩGSxȞ] #u ޟkC)5ȣdb6H5\ arմg,܎J6piD9Fўaf,)>7}թ3~ӔbgKe9zڑxZۛa,'=]T_*vйIB cGCRStt][ۅ5Jr e{u {H' >OPF P D*3J洄?G|+y̖=,ߏQ}D*4[71QH9۞%@4;И /`4$F8=nvw m) DS9`wY:Y.ꅼxF3t3 Q'Ҋi >^qrK .vO[ +y+]NDzTx(Չ*GE9v9򕫯qa73KEe顜6$kJVQ&v@gy`7DҳW90ґ ѭ>7EB΢5r nfߨUL%V0_[  BR hݫGTFBL#D-Fk-etEaY>:&  T,sIh׿jY [&dLy] _2%cdzv|;qBf$Nc} !m l(<4c'WQ#~cx"4Qhl#!⺑\g]^nS f+S`Q\5:э$M$v$bj#G6R T`+%;2UQ$`9]\YNp}ವzZqsE[ծx<@S.KT&W+ǛΛk8oe6:ؖu1JoKBE^A(bshPsLLxL&l&6-qf FVJw:w,AD=288Z07&*:{ZFP訮An:gۂAG,gEE-jPYc[ Td6 Z }1ҙ=w[xPZkri3{}1H;{jcAu}i^6bKP L7 6Z}S[sT)uT֗ލ <}̄qΆwŷQLfy,JSv$A &; Uo,0 2'qpS4AF8`8m@x#ab}븊Dk8A͐ݨ'fԡb#KҠ{ DC j)'} o T뛘zA`/ AL+B# θ SYa>͊V~kXQ9Ee,Ĝv|Fi~r~֎#D`^[-DLh?fn]~k@[ncb b ;OMSgЈ܁j Wi:qW<)bIVmM(6GmQ%U#DfTXA^f{Ǽߥ:1Pf\Prbp] <. [ 3A~+CRК/:Oן%v 1mW|2{ f+ 54RB$qaU?V +OD  1dxlmXA hK,'(].'+2y\0Jg)lbKɝZAW ;`fo|uexѷ,[ v HbE=YV 'V_jHT}hmuYAS#̀&}chD:f71 j>?xVLiGl7n65+9Y#ٛt `DT .-@-7P1}߭2j-/z!\G股eB¢#!s)W>8HA9y6_$ˍ%&HdU!z*sCl(VQ) #*KZ~Ad?4*Al,h]j8F^E FE>Nnƨ2}w`s~Dt_LJxܻ1?uzήA?+p5lky"Oq&S2T]`YF&xҞA!UyAVm8x`@㌚8{ Q@N >Z4^/OiL)37҃V:b34)X/˹anESGi Z ܕÑm'An=>bz0stl)ޏ{$di*kE9Qe~OɡGz.@+ۣ<%FkZ+J=§dy! .| md.U 6O.۹um:!{&ϝ c-jJSR}pF^IOi|>VөQ/uLM ~Q_LE͜;Gl^/2{E٠tKW(7 4\Ӫo )J Y/3TLF$ Gի4\J$Rxv;-hig$4<\I ~>,ȺQ{'kVH}\fdSg;ȬTlLI ӏ=,$UT᫜r5Bpkv2_g0`B݉MO扚 |es|v* ~jNL3{ tKN\qʳg*" MsIqzPQ^a1uCc}+M~>i&{w׆5 ٫?U+|8Sil10}W*Ñ;qn#RƼL9!7V4^J$ΔNU|[xpCv;(i}͈-k%<\֢fMn}R׌. HA8\]1TT2I!o ؽ_.,e zՀTm,`C.DЎss)`D%3U'+^Ir!GV=rkHsd1LCYy*CL2[XO f$۟M ?Z)/gN8]=Щ@K$L/9]vD8"ϔ=<V4rDh%~b5}R!& ć ?_37$ƚnPz?./ei3q{ qA=9CE}KcyU PJϒWhV"@Wx2:%,@g~5ȘXUbLAR0Pn3 ͖S'Ogbۑ[`(L-6' {O%<)LZrąY* ϯ3zxp)$SK)FbZ9FɴDJAȰ Xlz1 (lXTN\ ԱHHM`\,ϥY85Y Od[|_ !㔵8t{ :b?ruw8՘r#coi|xّ1k7+ksˇp]whsBdp0Bch^NA-`?畱p(m3%7RD|K0%ayZ gΨkzy|PTm3/傟J;hj1@[r;jm䵳xJ=#K >i.д[2HJ'á^gR%l ݰ)_溠 ')0+1 GPU-@?"[2PТH1M+ MK>;^6|z@k9cUKFX}:3(5 d ǔ@:ea̗#݋Z΃8wׄ JLJv7٭0P9gĎ4m[BOMG]ܲN<317РڴmTX=UMI'O:ƱMSjthl!T@&L]EW9WI̥kKRںL uAGަA-i*I@"1~CTD?\F8,5G] )S?FD!fvn9ˁi{yYO}e\$fF/(x&ݑe睭ݣ7[fg_ΨpU9-~; gQ]}~4"S*KyaF!z6wL^9wQq} U'Pp2!~nJ$,Oz/km$x(ُ,b ƜCe.KNs7 \ ᝢ;f0o/#l6N >a#<Sr u bQf" υqQlZ|h~H^} xRol,Zǡ1'"Q 1 yJme[]-mU7#2z ,Uȝ$HY|a$$xU18{M9NBFy(`XϹ] 0JOnI̖@}BcBLK$g59!аv"U;^(u? 2E렔ĵZ`-CůpČBJ!P=ܲPڭ}ɱu]:x5-lonI+_c H}5V?a1=gd، >8E%V^=]%̱3-L^\lh馬wpT5&v?i.~ h"FN7# ;宎~@C؉DpqM\!q!ŀwB9!?Pdl~pvsF0ӡ@F;cT<`68գ0tb~*d)Ek+nJmԋFX*vrOaXW4=.?@Q$ 2"Im?8X{R4 z3z9^<]rD2d EWQB|[-kR+ׁw1zx7@:7( }"'CIu+߳h0O]A;w:G7UWzؼ(KwC&E%|\cd$kFì2E`ܚ" gy#Ů<2d^nW#YGov]V(K)Edu O_>5z/bm2]..vyQy7oa$$ZdH[k4dڠ,>۬ӑagcOWCm^&?jll%~ ЈG H vp}dnJUy'ՅxM Hທ>鴆$?TEa` [As͢''O_q ׻~8J+wYĄȐ{>^G8>͟]W./Z?.=%C5I5lTx*uЊnܳ߸9nC]"An:}?n9šZA3ɄEwYvS(jpȯ~6y9y3`ەi\TձXч6XF6I£8>#F !"LRRk^;zu8g& v{P$ M~8nQT(ZܷA.*pGIE. K:Y gՀtk˻1󢘆_g8. eGU΀}Z-(D* @Ud3BhEI[H2l+]ȉoJ+uS-%dajcyI?᜚ˬ!!>_97*M!QeXgmse}ʲhdp^2ρ'X$0;MϽ~rm y㣹GoaO\t# @_#Ќsҡi(AVi0&6Q+; rrߪǮF>#JlƁ7Ԝ⛴D-|5zͼC/e2%]ko~UaboOI4j}ÔW*M{UD˭w˒eS=kh4@f3iK]λH}QuV,|q[TTf[fL!0&gxNklfO /j[ۍ*ٌs{֊S]}|i8} m\HʃW8ɀQe}]Z\wjwDޜ+b !.@x9MGfOP{A& U=엥)=cw18ۺZy3;DkK$]uRE(/!Io ?J]L\tA|HL>a*|T?ҍ =@-/fKV[\2JQT'OD!Cd@c¹ iS5foNkf؃v|(RxkY~0w@uD9}klp|R991w&Q\TQ :!~$X| ɼYeW!vt!e4_T/n=486ϒ%gG1dz|+0{[tEDS'Op X f0W)*3|Nߢg- h7R c%vxJ^cJU[5FNRT`|^|y/|% 3uW=g.σ-[; *[64Iucל*rlik^Em6UvLdEy"WAe80K\qSt־X0d='H1h»4wq}9:ZìgEȏa ^:Ҵ܋1Z9$1Wj9|۹}JMS+o.]cOW;^v, |ր+!;֒^l0dk*aU /b?PS>XI'ImhOe~B,#Z\xX{S}vM- 5KȣE\_dF:!ȡ䌙ZRAϱ7 cg{Nob(1 {`nd)}n2\07[DmS7 PR7lata7z+CaU@Q5ǤU=Wm  E#^^zOiFةprgW TcIiJ{>0Mzg޽GmރevĻ ȫG_]2RN ;+k6@*S`=Y%K!XWs5y,mcU ͭS$_"10y`"1c½ao9#8~Z"FOe.5&\l2Vkrw{\>64T9hWY]gi7O݉Shߤ]X!s86a}PRi+.4*Р29H:QMAk .r)%peAgboZs.ʬJ NG[O$ `/EY0`vLgm18g 6DRK |!p)N;m[S6z' MםJyM" ;`tA>OvPq[,)HaVJTVOْ0It2Eݳ KJPQCX(]7tGMJPdk&cK4j%qfia8h:8K_W^9/ߤ \h9jBxBT2&;L㬔IFݘ0J.ۤ/#2)7K{(8ܿ-9;#T'7} 3ݲseULA_/QIzN#֖T/P/6f:N7n jD> 5={,r*\zGDn]δW)mqG2ImJ,T;+e⵶ ޶*r ǫ@;4L}+Yk2_=ךgPP(Y,TK/84{~c_=B&[%/Z @"b}٘ă5هPGX&7f?gdg`=zt=9֫!ޮd\z>=u(,;PzlSnZn&%d9#^Ԩ?Adą>9Vy%*L' j;a1&$W8oR4Ebm Zq/.8S ۠/Z/!ȁ5{}jbɣN7 g+T(|*!ՖF[>FdoM zV@E[TڛMQ>Ԧ}[_BR1YCo*vH_l&` 3X^.ڊ#/D 1dB9;)"TEPG@M\&H=!RM.#ɚCI/(:Tv|YCBh0lկ̚Cޝ-Ve)O,cUk]xlma7l@{V"~}nW˺!r "8,Q&z}&EQ(=nw̔y|4Y,E\s%` s~*Y@8yp%QX\[חuAE:M<ZOH)UK]yiU^ڙ61@sZb&0ʁG{IXFL!t3̪-4S'Iacju`c;,?+R6k1FlQj U+~Z=Z~By=0Hƫ֢Ng}u NhdscI$x)[PAJ8d0m&ԫ8~kej|IFD1 6R"Z8XSzCvk4L=fK|+^1˙-_{q$7Pj*9Lr9hC3l aӎpy۪:5αbXCvT>,G |ݸ鋋'>3*t|~w"ӥ%of|tӇVh:0'ƕ^l?3!G]\&⒓.rdxKU:M^a3rHPS].jBa7.$Z;%_@5U.,B""lb)'Mvlo!^t6UDǾ ~Pi4|ґ* 2|)UG"&;ۋzz%Z=y?{y^dt/X!ÿ@[p^ԥ61<2lu;IFixeDuaHՅZ M3V\efE ѐY -QTz}Ft+Ń*yIC N9ZF@~֨v&m $82Q]+olO65]f+G*e۹ 9'' 6wyWDgKrVY¦T:f$*5d;e$"9iٍze6͔2 *e' bP>KK-V'r5|4%D9|۬G}t>ؗgHrgNJGS &is"Ђ1~biEpնs@7 %im]QH@4O\#Y"3zioflۘmi+P}ċXNpzz:ɲXNRA6L8י }ZO~l Dɏ|.AEMwՇ*ƾ/t> rRxR*:W"J><m5g]'3>gu6H|w{t2gn2E_46 ''^pj.nZv1nزO~Qk8PڢsRiʵcS\O77Jz2 M'P Bw˳{ӄysOCG]֨15qAkK(lBqL&VUF&O˥[P z/smoTXߙz o]suN<~.F%k-4 x !b%|bfK S+ fK^j\3CI/yT2P6T}l/ dQKKHgi(N彺@5#8 ѮGx{fɈTO#(O{pJWuSW 9B 4?@z:ҳ(oE$ztHjT"!k9Ò4.`E7Ӹm(^Σnd.d AkyYס|ѦOy˞3pȥŝ³KޅԂtolեQovXX 7'PU`*!RNeZݷ1A(GunhE)@ OTČQsu&;"7$;^YLH8OQ|67v4Xj(42N{m[ӥs#5`f6'!"`xhrдi!s5f^͏\Ժ@Bܡn)<(ުy2gJ|)գ,.'5mC4*!ycb{p| _އԐ-)g@,I9:3~O8B11]l&BCȨC#am;}tϞ.gws7Qj9Id倶m9?q rS6wP4퉕p%83E }Nx)̨qL/O` kūKKȐ97>|n>{]C3hoTܭ)Do+e#d:rPyM1v&*Ȼ8_bћO,GۿTwŸ0ҊɿذK 6#D19Hn2b1> 7ގ'=_3ZJnQzH+/r7ع}*4PV>gwu{?*,QK8s]y[#cIon/@B}$ʜJ;!p>"I)n#eDH,J]PV 2g ?iOQ$PW[|c#=Œ k bn!0"RK )AB—ֹ,06dj<&LV@4ʈ7d*|>!K}\F*X9t޽rϣ&ZP.$dm|ID3A`v H7c?XTayχ Oc6>wo"x8Pb?1X"LuD$2ALu邂 e⿋iģ3E+ZecMIN~=@f|)LHX0nܓ̄J_Ș`bɃƸ4R˩/{"rη!6pe \\*uƀ7gƄ (} T-,VтWdnӇ#͙3DE4pJo;|9^d(Vِahu$_3MɁUհnєMt5":u 2@h6/"E#Q%?Yv!5bBV9k`Mz\m|J b"aO7&bƟVRgT:LJɻӽP^Ouҽ<;>61;{Wxڲ~ vCZŌXga0wr#|P0ިL[U\도\|m^ !jHIV3 ;q!c3噥W8 AJ*͵SKϭniwτ %nOS&b@N #<{.G}>NKX(~mkmt\̐^c\aUP[#OL$U, iš6lme ˄>%{C2A^IU&El!1 %qeۻfBG-T2HD͗YAnlf'CB@5K_Z{5Q2N"%fMKr@tsdgM4*Wh0zC\͹1D_(Zp =zALʹRjdȿabBcgT 5D6րM:g8% LT8&.ݧYYsrjV~O$Wiw2׵))) gbA"F6kuUz6%|q(r]PՅ{R.ӂ{g-U ~Ror]D͜x>/Tv8K[R} ΏxV$jC[Xq+L*q׵4B0JcZ6>gFCao~D^`hNh7DGeh5Mp(c[TcɎb U0݋i['U﷬ST6C9 `V]൭p&ou, }E/LYRsnLRg F?K };(9pN Q=^pǔqdp2}EКhZOlTk{OB-`!j@mP4i w>sk_|Eu5XbgJA}qF "dY.:Y}plpp+uC琹UQdZ m ) 9iR?jA>U> (o\uKOi͞1\E֡N4|]$Ct9 tuo=yb\Rغ˒*^u`SS*ϭ]}>{V0Qiwh A_4^JP5^({갮4oŴjfQ|6H!غL5gBڂbvt̕4c *ċ% lyan*l1[ 3i聦2 Q30Ki2%Ob tDVxMhWYӜnӷB,;wp]sv$?S:\QXG΅SccϹed|ATjk^ [T78wCC=@`$w f}˴CA? 1 sR=w5ױ"ǣ?85 lyI ]8kHWOq<}wLSq/ 6g2㓞LOa^tҗ 52GwdO[̬XֺA?wv47:E9|/7w|a#A{sy.E ,|uvQr ϊ O :dC5#AbF9 )SO;[QwG:s)nɅ4Fe-_/|FH@s` Zx'upM.>E-,CPפr9M6Ƚ2ZJH@ I[)5;/네!2eBmarM7~9@JȲUwJ߄sH72\0D[ !tVd'pǴ$E̐` D%UM켞MOq6N/}fyQ?^<@K%Z_ n0]dD{r1Y'E>QXxt7!C60vvjU> T*=nM4ބ ^&X;3 l 0 uQuh; l ˗CPu|[=.4 D9dVw6 V<RUwtil>K#kS1:UO: i7֭!MT'/E~ARbIpr)Xx䥗() VYv_ٽ@oPss6S#kʋoR7|㥧˖|D7xɍ+]~fO˴UUkQj G7krFRZ* ^֖P2HI8y&:U9 2B-$QV\oG1Be3OO!20QvchK3$&w̃/zI  W/AS(Fa蒵C,'f18H[{m7:9⊐>&W)eܥtZ>-c35S}#1}j#*n5cm!P֗?]$KgIlb;0IAGY22ͰPxut.8Fr(:%)tR OVٛ@\,ojhV;I` ;A8y}s8ŕՓgA\(6~nEe '@Wr1]ӥ?pfg*+a!Б=¥i5ha' `u_@ȭGn=O)P%'ɫ;qe _`Mk6w;ؘ[ \_!u[JQɚVZ$~Bf ^?&je[)SA3Ls1R#?pEybU}qXUE~{0H{†=E/DYny ˼d8d;X7KDa4 "[KkwMD hy-)Ū#ùfM=0!V3Ku}=q L H}!3DqGGQus[ æOn=웧'e#Q7 ={%sb:C,rLwh,U*3& #?22P-W -AkiZ$/^eDt9@"<+qiLUĿ[zZ5)?.jditV^J7x7~7\'9qa͖HYEug|a\ITf+D_5뛂%(; Wt(AA/0HQr'J)~q3?<@Wj*2i籂HqвD M:Ld!LnAi 6"KpC76γbN/2bX9&%)񠭦a2u4 7Yx!hkp7UOfr< Xj!czZ UO!lIk8{(M#G14 ;@КUaV5r4'"(W>c~jCj}AG^yU+q^R$_TLdcop26^=hD>S6_#;OPu߲sӦ7X#ebS{9"C2 O(a 9?zwӭ-l O2/f ,8OHt2Qpw?Nda2'a,yo |aTSes~aouarLfYwm UH瀩=5oliHBo6ZkgLZIБ<ş`k(۩斤EtN[KzSm3ƊeQީDy6,;?dv#H^)?%wB,mR7m~1%XxpKnk[7R.8f֔F*q3.:t_F f#R|ETAbme9s.8rܜo܊-=p#n@E 7Aԥk m<7gr (.!alxg=%[qp3I"T:u)*Qwy}/_@'vVr?F-hTӀf?Q'نwGiLН,3J 8L-aᯮ¦q`:K6N(.4x5 K^6,sV X1$xfU&n)Ž_ediN<ꗘO7 ;x QvF^ͧk|+cfr8=[hp{M\$k"̙!LgBBm7 OT, %aޠKĊ|VEڠ,pƼY-_f|.xF@KuZy$+Wfn/¬+T:7a2N"n$Aipf:p1s'M_$'AGH|Fq4R,*]]Em(MqK7.X55ksn 43Z3ho (}pbVGwx/"A嶁9vսAa3vOAyM rkӀj8speӄjH4Hamq͘ d=H%,7Śѣ4S&L7NNkp&<@dWuf^֑A$gM[ YI3=vئl٢[nG'9#xRʍO꿜jcC8 -mh:]5)Q4-lHԫNTBLl#ֺWT]i}u1F<=OqŸ?'կN8Z=b9aߵl,2pmhF *pÙ%ꓠGL(a:tNhmЎI=-YEL$oCE|hZp?|WǏ/$/N) 8f`<5 O,[%eD܎\n]nM`,ja`vL/zRPtm`[Z&MvxBvN._U/ Epmђ)ۤCh#CzĔg< ^ %͓# #`:kCғ#0Gɡ}P0pb}jS=ZD,"uoJ7;}:oyExYڕ#N/์ho<(暚2X%ڜ;|90)wUXh K}A!(ܡLp=n'O'/bq}om.U #+K|~8i}u }mI-}Ym8C63 5ƚ\*9!Fl~r,Gk|*)hko 3[Ir5*N>G~0^33+ib"Vȕʾںo$`X+ FU$(~v{@aOwS2RnJ$-N eZ@6 7nY'2, Ů3 #xG'0.9ErJI q[1hfAgzKw{ Aj ]# xy?9 W W\MT=L4rnю{_Û۵Z8+]VX۽hb/{XD]%#e,M[6!_5oN\i <쉜oV ɂ$lm|lSӈNe΋% 6]喖ɷ'nH/a7iWMAW]ٕ i0f@TUX~q9AMO5}DϽhB[0WMk7N'շ}b"o݇>܇z6czU*u}G](= o„xhO02t4DD O v.xK|\D/N|NLM;'KLVd(8<z`QW\a_:dEmARp(y#s4 r0_Ry? }>";c ÃNYA P+m ,tW~:ی0`~|V@nhWz*TsiD»^ qW Dy@4i6e{Qǟpx#ːH.FXIMzJMڜmחxQ3AEߋN+,>`zŎ%N:t4-" ~R$wSw) _;/a>(Ӯ"u 4=XFnuGhyq7mػe(DpyfҐxoJIsft+Ψx<.OiL=ST $ [Fsk-*TbmpxJ:\ pcd8u>ZZx]> p1V()PA[aӰKd"4FH[eWG7`*OjhQj9ŠŤE˥{v`rgSЈg/}=ڤ;[`>xE( Jam  vcxW')-;]WbKڹGC \<5k'PZ2`I<6|hY+f] Iojn߁;pQL[7+~o^ T{żkH^+Gxn $b:DF3_/ԿݽB}lz1; }"4JΥ3lɐeՄ(tn~H eqaH"6 <\.*Ų8 8 71l r Zcddx^R$D3rx@ڬ1.N#3 (4v ]=֘Kఴ@g塚_. lKc_B/ޯwm|:T0|)&-g }?ȣb\O_Xw P2EA3ٱYw2%oii诠뎲Џ`Ҁp!q"JqQy iLp=ʵ[N^ \7.Un S韣64D-tz"3ATOε!g\X\یUJIsRX3@?iOUփTfGz%_{R{y~}6/P `GlTD?5ؕ rĂ5$KP #J&$h*QN3ŕ+qXinEcK,&U.!Ƌ QR 绵y[]2tV޴W}%oUh"`!g`>՝ڑc2$i\:c[b>hLhz$ `q+*gο+w-YX4K~(ҡ}cdzC<}z;Qn[O>kiVRUHv`XU7nDnjÊQ q u/>"iuYdژ::raY ET8[`kulj@cmb:V` e Wy#q&v7= -ǠV#%/p)&~6/\[bWh[ ut*n]-AZ x f-[E n_p eJCuU'Ү!Z^Vk$iƪ&jI@T>08.""ߴi.=mH13C- ZS0kgR l>W. ='#M1cB=q[BxO\tZUbU\|JU!M悛.$%6h*7Dw;16w"LLʴ'GM nK-Nq[!2rJ,BE?XEp;SY5TOjɶFv2Lxh:0vꆭ`39&9[o$ \Y55 ~KF;]ggzaцUmkD#i;p䕜lQip[jUX<Ģ|>r7@gpb&Q J# Ȣ2'<6+Euf[6'&+Vfm- q\C zk]8F%$v ?25},l49_.2>U}k,z'Cft}[DZj]&-z+@GfXZ|@kȮ W,"YDdb oԋ6 Ɏ&qk<{:Aۊ+>#wz,*7aTEKPVJ7y1ȐVMF:_Ԩnc,R=Ѐo^$QC=ma,RuSӮ^>$̍з]|_l@)0m?\C{)I<2 5R=YG7 TRWc(jS֐70 ڋ1ŭIQ7lJܐE-tuSt%_#M:(f ڌRn3|ʧ+۟fm'} Uu$G!Kf91 BnJ9uQʑ'~w"@= oΊFa駮Ko(e&p-J< k\,5iXq 9/zs,'{9t3 @_Re! KAӠ;2rL@YUIG.B]xF}&cOCwfopbMp ŏ&AA[yP)YrެeVO0y cƥ`#0h0km!P nRQ LYxm$Dq۟wy1MaS1}k5nΫH=ռw]AN=ɺCeyݖ ˞Up9mߑ#T[撅+#,]@ma-V&+H\ۯD&f_`AR% _zx]  ^ V-ݶvD5|C;;B#۶t绤lՔB-@PA+imNj EFýKԎ]2U{_?SPPE{0o`~&Ҿ?,EJY!X51nqm~,yu6MAjѻ. WPAWΠc{(1R~<"d X=0z}1ǫҗZp!m=|#?h~PzzŤ8OOO$^qy44P鏱$r@l_Cۢ밄{72mS .%)}~[`ע/A@2AԈ mAj:9p5bػs2BT+Wr<7ԉ kܥߏ2?S>Li/ Fm;O|@yfaڭ SLP̨{oڝT.H'!1>)5\š\RZslKR`tzi?5 !d|C%r>ls}k_yʨ&2ZiVo##}'p{g`t9GfJRQ@ 0r- QrBѾGPa+KVji~h>d3^XvmQ7opW`I30mC$%PQgNA%4V~rlU`*Cw8B[B=;g|\EݒD7o7%OЃA3`:I\J S[~|Ɣ)\~KaY4Ry7`lA޷#8ݫ)hSɍ4PͧQ؎d* {;I[RZ;v)eKݿ&)Dx :β=ft_wyu&fSwU⒛LZqKdznI}8,6!'7 tl Tz#F{s/XH)؝ Bеٗ5]TyBqJQ#V9 [(\4`3ιG-婷E :Ȣ1Mh EsEFVN\&OҸW:%-,N 񐪘'lMRyY|$I8rQj/7Ez^Kh=FC~nBZ5ވwBelZ=1y)*Q< _VJh\Y8I㖫Te+yx֒Uծxc|xjCЁĖ&t Q>K2St3&&' q(\CR \\%Y2=;.`Be~`JY>{|Y^*PFŃAD ^@ 6)4tZz ywmajk32T 4dhG_R #5ɪY0G!C .:\ m@b`X>stBpЧGI*|p{E .F?Ꚕ阈`ixἨ3_\J?b> Q8+(Q uq6׋+i> $O޼6'Rzs/]ܰ*$of 6p 9 iC;Ap՗ %MT\; 뒂~XIrڃHFy*zT;bГ ?uvgn+scGQC[1%x'|t.{=ًbz!gum;Z~eH6 Ijf޸zijΜ0vo^U}Qi6M^Ň.3`î˔ vsCUXٚ%<NG)dAG2ļ28*'[%Icrʕ[آ}(dgwyb{$v'RցCr|D*7Fז᙮@N!I0iάT1*6qPqWgjjEMT,Gd$t͝9ORrk(L;Mx3d.C$,J?:߶@*m9d~o<]ylG03WNmu" O c@1 ȔrRm:gf#i^{H ~5y yX|" CsGmW1[ ѶU^.(bdjr&U+~qb>$fKן`%M[>&=<M@*!v0|@B},? DPI;Ӊ\p;c f%fv 7&6ՇZ;O.fOkdi[ytZ ).d@ΝP6EuK_>|D"Tnl]iŴ"Wak<`CaAnzBf[rC}%BVЌ?hz 2/Y*ױMX R -z߹`w2 _4ӯfb%&ӹFGޮC!p%ӯ_Uiqz|Q@Z[~<10s؉nHmkgF_uugqL=.a*Tƿr1A3kR)EA>`SDC^fk $D> =ب$ɧvg28 MTƲAXrS%C\{Z \b@7Gy NcJ/ɊWST,CaX 2ƪjU_S(1I>d:h̬u 8sM5ENQ F[<c!MX~|(G^/,(Ec!?:P[bYvїR<(Zƚiq̅ f 6PʖИRXi.}YvxLŮ,Ĝ]b?{d1.Y5V;G>K]mJ)I (/Qq?$j::FRu(0P =:pbMS mZQ&N:ĝ^qϵmV?6S^\gɝawHo;sؽFxJpɴm"}^(8r,Xe{aQj.9?nS  A0#^Q>E.Aپ[k=Ut@sV\wу:؁"JuTzVZA>ZEV_ns)4G {pN='2Mx,ɺEquBE ײ ^l*C9o$^B8\kA%v+oq(}ED ͆uuK^k-.]k;S;&1@0|J/8G+/2>ӴКic܃Zi}jsQHWrjND9<ȧ 9=n㟖"@zą;- ;9J\wV4ACFk/sW롘 E46kz`ݖJ}û/H]:8a\)4BN{ cbmpKvD0ljV~a_6\"О`&K"g3[~nm^!r$de/k錛)XV]0/ kU$ɝHfIcM{sK{>:0y+W&ƥ֏QtH惑C}^7KتX:)`D*MFrv^[3a?`zdlUof<PTYElK2 X'+ZВ6L 7] ecvU)(lG|ducyw&NhJ"QڂG"՜(~Whwes@0Z:IZ6ը\ÜC5ؗDh;h Gۧ?^ҹ0h- ֹ6fI\4SߤhgڡK<{SƦ~cyg"ȢZzRn&=yIaO̷Y7S0VV1=JwZKE= x}: b2ṽQ76*W {A:齇Αm BAv ڦu @<×|I:8UriWq.~M7@V Zۓf0Y\%wZTp+Gm8/jx䭗:gA$';`,ni>IE"t dZwU>Qeh|ELmP݀OYsP}[0] U JO2Vӆ`=șmȵf"E*c8g*L)@ȯ 7T_P[},4rYu &þ`}(@ܖ˚y| $hvNDҥ\N|KtK4c2ݒw؝o 'I24!|S,_9# ).yoHI=^4D=5@lZd &udˑ&0Hom>g!UcҍL70'-kj*XɈT o*- Y(F~J`:%? 9օ)n @:q%&~#b4q)[uTG̟=%vW N-3Yp|/· YwLE!OVo;'|k~eC{@`d|=9ggs( _:iD|!32d|CxA]_^h^.hxvT ~=7)-2fZk%ETU6Tw_a=Y܊O*Xuʔ|׌\Bs"\`"KCA?z*~nb\ce?b4{ⶕ =SSF $Rf8vr+qh/%(LOFd6ʈ[S[&}p&ZsG_c~%eIFX٢Y CaD Li"LISSL@5%FD+bX8պ=;dfŖ6N9"&yg8?lBۧYShyK/^IH҄d]"'Y٦S [e'iz}{)Ll^ʜjB6F-o,#V$;AvGY&OBާg“u/E4'"V+L"\™ ѱ*P * Vy׀$Mu7o&p2jJx3nQ>A E ?b/e҃LVӈB89p*:ͶQvU+HHo羊KoIS%LY "ioU-V&xuFQv+߹v7=Jpی[qor)y3uY$1 Q#>DkAFYv1!CbA 2ȺnfN=^Y0Fȳ}#,v'{  6`d"8:K$s_pVPSz@ 2&W%|δk^xRTNݭNQra$nl6NT#~ r*3Ǩ|jB9D+yjvЈ lFf3?u; Y񧼛>|^| U =2aTt7!ٍX˟Ca{ rP\rو\׉p"\hh g(2m6x3#ȈtsAg3\%<^ad>!L@odW,vQ$PB(g|քm‰HGq/woZ(d,@.FǛfO{ŞUp\ziB.Ccs)o^8Q\][m Z+avz@RuPo|9Ԯ gfR3`MUc@#xxˌ /`fWäy R3)4K,ٯ~w}8J͚z~5 sXcެ >% M yx tIґWvVE;G`<=sKn6K% { sJ1[D`QIө a?;sΞO09n$״m{8d5cJj8TS-&~zޅ ː"SV1Q9E LUˌn*+Ǐ3ǹoX']l_eo%Y텘0$,;]kEj1,f$H֪[cM\*H<(FsGV?*Dhryr7F2rWR1kDhB˕DFÕ oO]FZTXzۀ +Q8ɯk 164K_#׆8M@8?8lbUjXE;JkQj"ܖ]%f#T=u`@菟;wʒFl{3r:!>_OW:H ZA+`%Vor7 ÉgTͧfg;l-\!ac+K4'碑$q?5£~.dfKvbBhb*_It *maX-YhpDpܕ4Uu{g>M <:~2q=×۱˽ke"#3'8_O:?'F'q9Q&@I{_L>Bi0RMSm~ Hx nidge[<>ӣy̴DM8z%* f*AzK<]DkR”_N1xiOG ~tNN8,Be=e]c44m͚RY#ļo~ЗEx 'q g"ve˩>hHj.E ڃ4kçF\u|W&xPFigK3*P05N`!.E%~;ԱdDW930w,E""yF Oޱ%'BxX{>@n&ĎI QFJSh,[{ ƎyEG%#{\Q%''۱ĴbE aPl`I?6NNLkg2G-0D?)3=SR8A_2}O]:OS3 ٢?QD~a/&$ser=iETL~;a|xݳEʄa-?x}IGifmV[lnԯ[2~lݿR(*zÖoeFrk&I+5!Wܢ%A* Nb_g? ;h18ްfsn2\HɊ^ޗ/i26{yFuk8Idi?]i73g=0~Ks@(L2~~B۠AM$&Qd󾊳S?ɑ)z%|^Uj}1W(R|(/Ru-1QۍJ z+ D\|o\] 9 U߮ ~7x3kѰ3Y`& J 69fKѺS~E"y})e,O? QN,ec0 Oo{ЩM?di0ޮ(e`Wr +k4ot6(Ei4 Wljuo1(&wD3,DTMaz_%=[)opQDZSòg.AQs`͒6@u?X MM=t[x Ć-\v- C1án&ƞk=dOyV VRj󛗂|jӁGkᙷ\wyL4qJ-+Aw(0'ȸu ;Ъ\5е4y! Z;gLH/$}mƜ̬K{1+N h)V6#0k{~* ^BDMGKpv<\]U3t}L+(!Npm}RrZG-Csӳ(2l-oՔџ[6ùD?x zDv+eR{_+'ROid6=s׆u?? g-nZSBg&*7ՇbWJ 0CߣL7P@BD ֿ& ~Oko vq_z:W4Ӛ~ ]dɫII+a0C)'Ĵ*S;>]"aAi %,i&"Om$l"d>\GVBq7YZ8Uߺ aoV)nR밳"|fgȿEi a{bzŅG G-j<F!Asr~)M8+Ir31}* J$%]S5L>o8[b[ M/xBkduffv+4ɦ@gbB2M؂:I K5H| Ms /%>b4 SfA ~1#!qeQ_x&'aؽZ@~+xƠie╜̈́ʤ麗N3Oے 4V i _fJLQZq\YN^4'Wz RD>xY.5_"8ˢUEb ПC.lIfX 8&QgJ?]OLY^s?S0G!"_Udzj9_7t)񡹬:o3up _K8 |趧orѤ!J޽J,{} [sh4CZ/9Fk@n;J}hmdpPLJ__ͪp0D>gVÏm;)Rl3zoqT epk7}赇PWqk&myD.Ċ򬄁]iޑ Ov\MK pf7>_bj&c n*˃+Xwe HSz/LϞDTרßs]iD:d eӇ R(6j6.vux7 oڣKY |7]Cf{P~wT޺)Z "D{7Ź6⃿.0p}JODQ]{,^%"՜#Vuѻ8s=U̟nt0R3s`η$GF9j!!x-զ@< 4gf̙D$ &pxX|L G,ѹq>| GhQHAj*q7 o;cu\ 8V$ƕw좻է(܊앆'#9tste+ cHbc%2(t^'dl)&cL[Iuԛ)-`.4ALGv/)\5a#A36Ngn*hty)6(h OɏgߚC1'HP'CwZdd#o|𙩎zCZsK&u-&p/v~Ĝ\ ]:6 ˆS@(|RQSזus ^խYsw-¸\"ACw7ƞw '?Ϸ1Q'\jQlNƘu/}Z#W?kJ#hT?80WN%j׈o ܤO !c`JP5}}Dʙ-Nїma.5#n4~!d)!48ϐaꚥe4pXLLbJ%D,yFa'X"J#>Y; [@R]QԳ{{a\ОEt'a#+k[ W<;`&ԟ,K; &d60 9dVX~ @K4eCﶈIpewt)?Qoi,*X0v!k"x*++{tZ˙ϟk;U^&op3==/M ʏ"?=a+Ɛ:J+C#tkwgÒ<Z^9@eot%xX@ܥE- ,)bQ}{Au RVWE"wʆӱ:8Gq *f!I^15˧xEsMy뿙DJDZtP(۷c]پ̨]zuAL" ,í|UmQ~ 7oF<@Z*%(kA Uo /s}lXHSgb+[Q}%bdٚwU]|sx<Mv6TZN:Qt/{|}ꛍ |qRc R=ŦSwq%yh;~=a{*Mk֊ `Q"8R|ʚs H73z$%Ҕu+=##j?[VLL#29{~@ F_Ά8,%.p,DNE:>R~2[jJMyTCPUtd^tbQع/yƚڧwVulyǍaT5q:tg93=Ci>K- RA\l #*M=*c#e7-.sg.r؎]b9V0[3 NUYРV*o 4՞q^ 2iG8L*$kls[!6DI; C7v4~2A Ef)bkwZ!ǠR 7<^'1}ot+fvgٗS.t]߽o-CA@x넪lo03"8LxWcb3 gmRA4خ~KA~lm*8?U :n +rKjբHtζɢOd3?)ξ dmŵ.>AtKU{4# n!Ҍ:4 t(Y ~ {7b/۱ n1_vhX៘Z x'nvup-`{3Fib85..ca Q?^4eڅr܏TeܷtH{Ambum`$KW^pJIb;x}7׺ *. #NGYeuIvE~inI8gY碈s~Q\\攥 <7ގD5Ds1OĭJYy }K" 0Tߵ %D+Gf2`< {'bIF R$- r[ڧ0ԨZQ IZIphΖT. =6}:86l8bTϥg(웹DTI*m(8)j2=uGaQ/L5ϒuW+(lb3_ ˫ 6u}^$Ng5A\\%K1+JFwo/R,^׈|PBq.ZHlN"F s^KY] |&9zSR PL;iہ_G\e2HZ>m Tt25ɭ5^q cP3ū\d C=ٟ;`\W["oӅ.PIX9[H?ՔYO?i.sV|ǓPa _5ޙ̿fh{h//R6v:SLxMqsQ~', nܔ ៥ _ŏaCxܩ٩^ap Bq9dpƭكܕ%|Q0~'],M+rz#R¶,ksWXB_MFsVq-=UFym $2w~ a7TcM =b'hCjYcryTQfp@t]ȕ=?=kerhH׳f;2zcC$?zKKZF E;Jƞi#D\-~\ގ"AXCAQczq;H!`"҂D'ԋ/nosޕa`hAF`}ܿ a'*Liy9>)OQ̔qa+GČ<|E"Q ⹒:pGHs^i0E{6 b;Ot`:y&gT~#t=(ab|{4J{`Θ`cg-$kt(Q$ Z)zD~#𲾔 0X4$@0A b#*rP9kcJٗ70J`BE*M:f5Z/x4Ut/ja4nQo>(XVi*n:9h 5茣!K-wm>ț`ўW4tpj-p~k\}mç5|B~0E8ojW}$NbKo =B&Idn3Pm YT0LFUb%ssMk+VvGwZϝeDObĈ-}L3/ǿA.* x;)E`Up0KW-+zՃhSw+-}CRy.CS+lB2xPONɉ(B[uE ug2wNT,h*4:\0C}5~Xq'r 9;"#|78;чnϝ0{#K)4O'UIvڽ1|ss,5e?m36ps,]X+Q<§bQ&`[B ܮݨ@97HXMJ;USF13ⴜM)b]Ȟy-,Bͦ)|Ƣ*]^HЎ߇?xC;6],aM>LMV l_>ց~l>oLZyyQd&s%j!yZ%.̀ʐnqww^ MR8l; kJ;sܢ/N e['VwGXm_&Zӻq5GnuʣPZfՙɪ }5E9 6a H#-M[ \kVA(] u GO|̲VBEk3a)TNijlO+YuX%.w3kQU\Ũω<_!jOJC2!u_hsX9O! s3|FuS|Z5DTZ)< Zb3RTKP/a)܀J A3Zs@^T0` dN݊v摜@<j< Sƛӳ}%xEW2.+HL$he$g%&<tm;2UiJ.ZVS+娧(8Sb0`iCl,=$܆lLr͉I)Z"ec|ůYnٝ7HN7\d1Uw[W#巸֫߳K w#F=47zl8% | a<*yW':;Yk|#ܠt1[U@߀Mx繈ovjm7&h.sjeخ6%Vi]>S`muvO̓Ǿ:Y En*+WUt`}M A!o:=3[T\ox$"|Ǯ˺0JE uDRM6r^hqj](?XE[KH<N;O d6b\ aM|5jnF_Vx-rDr',=1W!"Hp !Z?Eh1T~Ցn#B 0ī@47W\m7t+,_ [9i2t'JoR=x<[UP=j}"C0ۿu#xK#]Ɋ51'ˬ2DdsN,Aݕcevt_T*| ~6<+J.xOPJm_F=-W*W<ɬASM+J [aL-4[XEW+nB$|R Ϛ T "fwLpc?!;DtI(HaAmט::rDpQe'ߛ@ Z%>G?&4p ɱ5}„S4o7{ Fåbe }s- A8**:?ďXA%8Rz5vЛܨ4Û7r8Z\e"X6Yp C7x/l6 `70"}Su '.,l. .u?o^=S5s{Ohf\ʮ4p1g!<'x_0P\TZ˺y0e u30>#,JŖ/#jX?4tVȀBhĘV+/g@kZk=>\u|2Dd5/#QvBoYMG[ !Un0 {/I0+ (=d6QI)VL{,:KvsmJ9$C- O}/v{bp嶹VF(<ӎi#-K7W]Փ Hw3l=mj`78c4͈1Q:A#'8RpI?Ujk8IMQf^lQԒ#ezުtOeqhLsTIYOesE݅+\b [_3wuJ&5va@[;iSF:ec 'ьIM6IlH[z\F0HhatJf|MYK jQ]$l`!i[Kzꦀz=: 7}$>ywrl\D j,pkd"|[2GeыR2H /|V&kzPAy[H!lDlaP,{9K{NB;J8:T@=C` >MLṣ<2!bέ̋ P;pE1h]pgxTTt:e,q{[NJ]_6li ۳yD.e CwA55RۋEHDד3g"9OѳO;3<'V¾fbF =Wڂ.pgJK)3T褗R\"JBۛI.$,0RQ*[~HOq\jRPrF죞4|3)l.>+s{M\}`n%:Ì6G"qRM2|jӵ@5Ydz`MxDIz҃vc]޾pꃬ\/= $!kT@6ĵ$O?Zm2oH8wd ʹSlЧ#"Ήf%[k`i3s&vcp \8AyU-<W( ݌;g| XH%Oebv9Uf}ZX%5—rK(S8؜LU 0EVo;$w Tt! <@r*!*ԴbI ׍ $m.Jޥ<:* ?, F}2ZuFAnP=bG~$2L f s%%M5YFMaj*Q?pOO 5'k Ei!|BȈOn;sq`} YvY U U%WQ<4ZsoɱܞuQ"2QދvY2vWN6>."۾XM*,QjW򀘓ŕo}}\TO]# F(6'(#!2RXՑjctMڵP۲m{˂xDŽ%ZcrF-h$ryb/&bW$r֨ QHb^?`] <g Gj,rVp/D?hs;h.?ԄECi,/77yUcnTdRo[\Q]&{v!2GMx gT~ 6,cbFF<=F-9PFo3⩓7*O6Uoȧ5VYVtO6Tp>Rv!'ʓiҎ*-;5rK#O1>rY$JX YëZ~]Oع!՘]Ƴ;hk8±s3ogFSoo++t QC:,xg/ JOCh7XI*hnHwǺ8glծ:,"KD~ `uϯ4kzt c (q>0 YZgeosphere/data/merc.RData0000644000176200001440000106205413472155746015035 0ustar liggesusers7zXZi"6!X~5])TW"nRʟXV%>"UZ tBk}MItrU)W*v*t6_uX鎞SH\5KRahwXA-HF*˫f\vf!0"q=1:(m7A$*˶ʕMwibj qܗa(,z)=J9(rDNrQ葹#r<\@ |Pl8Mq4hR6F 8a^|}Cby<۪EC$qŃ׉>1ЄFޅB߈- *p}j{Nk0vkI3+tG3}r:9vd^ {"e'BLYSUAqP(ܘLyOW8N5PC!].45@EG, ) n#f`'D)ZSG*0h[0e8^[ݜq>J_l s| ĠH"^Ip?}[﫟sD[`FVv94q2rPs4f# h)!PL0_F鰔ʫF76X|1(X &]tꝃ v*zo z^@{r.ɴ|tI)n5=;5̽.Sz6OoO:y[-MOcc~KG뷣>;4_!4C\oX J&ڿ}-U 5ye\ǪW ha4[\880 ׎F-|?=__5X< o 6'~l$iyQNCSbs۸ľeĹw9QRQSu$ Y'׌ôv#t>P | V?*pY5dURqR%l| CY.;*aBa8V1Xfmu80 .G86n 7SӿѐU۵b}mIUl~f,ˍk$P$KZ=$Sy=Es]}w|sqXH|ng?( J&cZf xrcG`g?kdObQw"E1ĭz4t2, ]rU{bΦLN 7>}#Qݹ;.pc{H 8Y<[4M[x# Lz ?ۯ%tfF\xGOq}]rB= 8d5,QGJ?N9i3ALRF /,aCh`d7|^}|c9^z-<0ly-  PYU8Rk㙒79PCDQ%0oS,J@=686IFmYTw-OuM 8ҷ/=U | ^ ʋ패3~a2e x1R)=7>_E&DmR.osCf}P]M$u9Hl (D ZZ^:D#A>O0kk#Hza1vDݍie{u.ҍu?|hbrUBbA<>pUG]":_v)-uѼ󕞔Vk(;OiMàuO`FH/<Q4 S@$'JkBDU|9`gb͕p3وV;G2\"iNe_^n"$\ܶNXV/ "q؆AFιqh +x E;k(BU1]`)ldM`Wڟ3,|#3%;l_8җNntcȵbYjQ ~Q(qXtb_:BO`rl3[wscDu-cݩA "cH} .$kB\wcBۄ-Ks&{K o! OPd]WNk, 'r+ϡkl觝GGoRד_LJ~9l>'^OuD#[JK%xG[Q0&4̋wwHФ ޮĆFQkB`Ml5ŬmiI R],UG'/b i:npWAk,Sm?JTHzc}{;5,,g^z;ݪo>jE2(@&@9׮q<"&=85!مNx(I>Cumm>j?V{C%Io^/a[ԃL^ K\^0ɟfrjq^UcJ{N~CD;N`?IUem}Y6Uӧ)%9,7sn@cS#9YZCśrVoIqMΚ˙TN|r⪁aD3rhk(ɔ{Ⱥ$RE0rO0̥2#;YW$8*MvMhx]U *,eip4@8^+fL"^W+OWEc'֛Dyob+CݤE9[,5_"gI^ɗCfF ㇡4rHUm f"AA-&WO #hU(I*<,LSM=nGzմoJ|8pSN]7MT_PxmhxP˴ S6Dj1+:|r sZ}בɤ†_e-iB73:E ˺|i[u Av  J=u3гN]5s)}rƹ_7X_)cPճJ}ȩh];@z[EU<}?G1] !JwS(;%}MO%mWꍎ{%h-x g귚joI IKa#L{m3vӇ_}*kٙWtyW$+fڄαboz|o;#JCO+nzX`ܵ QdHqNPL^P؁4{s9d$-S?,)dєTyQ;&st> igWC Zt*h*jp_ejB) DjiJ:vĶyb$ugDeJJVA>5ryXE|N/e|2t,4|yYx"Rӿ9ʯ۷L0 v .)n_/9+9j-8{)kO.B]`%ba L'׀+ WZ<# r/DPFw{ .Gc%N"4Dm Sҍ&q*K)a(c!Ö^3Wd&fC*թw؎&$& }{v[7{M9sE"0 F]4g "@T'SGadk?ZMA"o,CP3-0!b7Ldp x/JhK 0z2 $@Ig{RaبLqwbV1#r@b/*Ы>P=3̛YNLѣru !,tf9eݞ0YX;\1GҒId*ѳh`Aa5ı\+R&zNk#M(hd}㎻Xȯ%lLb~"裪qk1K9,(Q1tݱ= 숏WcxB#5ݺHi34C=_X -Lb.zY}oЏ@6@E E\siGpgbko>^,Q^HV'(lqj! mEJ?RC3]D7S '? .ɑKRK,#M4ac{kXk`cLdp`A_MUD-S=~`i+@֍@놯P%.npx8o.7\DZ+p QPA#|ez{G73" ZJt|up-t[E.Z5$ϭ IpY.Wgg1 B Ȭ>fW\<܀z@xܲQG>'wъkPN]L9^h[EO9BU;z txS<~g::Q׏4KiIK\zEDo̠ڬ5e4Q,A7AgQGO"oH7Kt)QOS- a4ϟV ωZ4P-Z\hllI35[;~>`Rj.М@yFk+,u҈t2S^tW;ȚAb[ ꙮag0f!7w㑹vmQc(V A(KlE$֕B!xEʌ[HĘLݜt>xP ՉꁰX،,\o|j1bXbዸPH7,9\|;92 #2w^d9H$hv(X$|Fi邑&=ܷEs{`GOlj˓Ęd.F"נ(.3 6+V@#=aϟчyS[o>]?il8Fa&Nz_;3 LwƝj& 7>DW9RR^4[  ƷPWut ϾR5ǥ4Κ`W/Qrwh"GȏwB.:!;f|٥N KːL┳pq_ oQuuK!4Zߌf ԃ ^Ɖ<*C00 ߱[3ލ0vVyaZAt댍HUsi*K[[P̳HKO@75a,"NM{|BtKh |Vl# eRh >ɅV!T>y腷kA~P"\jgXir{PJދi(\6YI+/J,Xo"mΠ2qkȼa6"_Zb_G碭@@fdRfe B$*aH O<bb+tМ%/g7FXoC(K ]C{@r+=ر('ANGuGSf[[ UZ%3/K7п7և<;_>ڄV72Ota, x oТDN 5^Pbu]iwTXxs}/>4nzzRCV vQ؛wbrs"?-p☤CjӢ.]1>;Y?GɎ(7jkWze/+6U %{Ta9Ƒ G-'({bL=^ dPlXan 7Gz;gYG, Yuŀ߱"5p "Ȭ[>pn+kS͈XE^ig\5?h87L=8^W(z@aASZn"WCos l%L7V7f=-(0C%z&l BMTOl*f]#-B!?ר[O'J@}!T|w/:Fxy{#lփU)fD)RY@=fn "C=c,/r |g&a 4 j0*k̨vYϡm*I/E9f%l+UUŒ@T+ÈOϥEK;r;>Vtё^|.b{ěψHL7Ϝm ׭:l}xxOr>`~#z4Nt n)$؏}U?5>Wt=ДbPTz y\dͅJOx:>} W#OzryDC;8J\ݔ21hP/ĥ&ai ܞ] o(8HU\+#7 xkxQgWhhjqHPycx RˆhZ啩<<ܡݤ%ycF 7؞x&nWoKkY$Qv9FJ%kEkL*!N8{7SzP=B_3g+L`TpT*OQ6:) V 0P9nX8`|i].>L<+Z'~xKuh3Jǁts/= 6{l8}ܣ[ s%E4xlF}RsjoJɦLmt-'&z[TVkT}<%uװ!U+̈6IgM;+1+zt4LW֍7 SN[tPlT(1)Jom?Z2s♢C[k9D4I^{ $Mq<$Nd^G,t Ϟ 7+6~n@`wh`! ͎bL)\%DqiFphEP/1|PQV +S镩(8`'&ye/K$}Xz&i)kY8=N[ML[F-tCAהwI6fap~ȧ|99Ԍbgk]$ 0kXg[QUӜutiQt [*P,o9@6;)Y%{QY!lwЫA fL>P᏶crs&$[" y=8uYT O9Ic FkRШ3fj-ɣc`QFV׶Mt!ސ!5ڻ0'wP=|8X> {jTJN T|Qn8#0eÝL]Y22~RSN;iG[нkgM| [1HIPR`j],Y YaPi5SٰES~=4n`O|Kl+y"m0?RZnOZ0ztbTx_yr?]$_l܌,H7R[fG`5ӕ.*IgA\$a\dsƾxqTGlŀs8_y8~Ʀ$fI^Fb99&I3C"Є']C0r_ysAͺkdz;뫟T1=bmCION%joe˚A)FQץxn $ABs$V%S rygh֨~K LMkM.cp>Po%k1dџLa g5Xȹ2D)IRH nl rwЏ̅Z\mbp@$bJҺ *wP)}ƪX͋}o%/1ʪ#!3XG%&Kfے!]B?5{4Ux6E#hܥ{v;SC=r0dj~^G/`Gf= @[PD֫Wb5Lw;Ivd_bQCΊC٣_Fp^bV=/b&6{ *g&PuOf dW>Odlc*OMը0 Wo--;H[of06p`D~ 5A3bҸ G1[O8Rj7}j?MӼ$z@*w`S?ݮ=zp=lx09ub5T c fe2D3;E I9O'{aƪEAO7x3\J[)W0-@Xzlvw?#m;fKd~f4~e4T-Z\_"ko>X3fAKQ) :;lJh8j@QxJ8nLjEk |vuN)i#i#{Q l'u׊/eVl%U*KyEqR[ѧ]fVQ1;sT1 m3;^&z[ aY;7c5Ʀg*"mv}%}K%DC4"ixWN^|Gmc=1, Z:&Z$"T՜^=(BgBD]ȊECRBH'سr9$΢8}NĬO<`R KVdn0_ HY\{TD`ǃg'T\S:TlwaB8Bn hgpYv o*aesT*TM/޸Tlʯ5DwEmVtsZ7L#'7&14O>&ĩRTpa qt>g楘)@Vj=;qڜ^%`T̨١v3 غu1I>,j@<nŲxe^Igu+P⭷ 8bKC55~._+{&a얛&@pJd7΃ҫFfQ!f=*ЇcF ٭P:*L1kR:>j_wN>d`.lEL>{\s)[4 bO,?:xuK'r*KvF>;fuSؠ2hH3EfhwP\)@47S?|'}@:W鞣SC] *T5t +It-1ٹgϡ r c=Um9ZT2XNo )wJN. 1jfB/Щez7೯ͨzD;ot}'Xd 9*wa51{e'rc9>BXhpXCppza(,?'D;_'Վ\zg/QxDOOv&Ɍ ZxU3/_#ZMxTB8I6w7dcACfV$jVOM3 ܓJv]9Ri5IL1"sװ6jG }PCg5y6#)܈(S. 좤y3ӛJ=8WgV 9Ëh G44y)y;tdzuu ,PGl3Dղɘ$QDmO0S.xh^>J =0Vθ}UXh c(` N ]5-`""箷]<܅& <𣚄|$Iu>/;^ \E; +u>NӪ(WVQ}gGLvaW/VaVhxHԖ}H\^>]&]RGzw`OIB> v> ){* kƐpS1+K\x6V$ciez'uWwkMs~,g2ExY~r$&jF&Gi-b 7 7F4 /F衛MUkl=*(ΚEQy-_m:'M=0:gxmٟNisb/ԛ;W s3kmv{7CףqdKC-CT3Dؓ=E@9-[<W,hn1\ W.ouAx3#0AcP Ux±ln^) 7bR%'rbӰ:*y6%CSsUEA?":Yۖ3 2Ѫ=Vrkt cVǗ`9d~}:<%o?OUgcȟJF{uկESIkzBg)l KJg,20#˱Wx"75\2[tU2Ƨ$ aiQynUD黽1IP 5]sBPXjo{ò4Bsq~Q P*BalDo_ZE`eڗ"F^`6HtÏ~DCRaX}#0tv/Zc,ЄGZjzm'(ћ}jWQcˆ(egL {8W~<6#u N@W0]tă P @!/%ӷAEV&w4fS" 2)P;OIJPXRaX(Bc j4- f|VZbcۧ浮K_˹2 / kl w)O8wAKBsSuo8-m$Z gF-tU|~_5 c u %h$?ʜ##΃eVS:Qݭ6~Н,)\uZM)ެ/ j՚?%LU75>4/-<v5ŔQa9˾|gTn" ]ѢF` =WHVE±RYxb; 8b)p#Yt̬d v.F;5+B2Oq4[n7?zt GF{gјjg WfڬP-']µ4qCQS3uֈ?$6d/iLN h3kg-Z(;OH~7mv}]>*1JĚZV|ziYaeS淘~ *l!l7$ ͌t Q]^^wQ)gR-Mn4[VHiF<_XmM7$;9̊:9ڏKHy,&6vjv6tg۱}z9+* Wq«9 Ssr<du _1M}E@6=g!,\Tb >٫ϖsj_LCk*D,!*H21 SMBd&<xmyb@d6 W~.T'p"`\NC98=v٩Wx + +m}fD?:`9a[COp=Yvŋ<Ϭ3th 7.ja D'5Mz^pͨz 3z̯xYbJ*$hKy0<^BYQD1oCNDz [|4 *ix<%g&CaA뛙;u`]0"üܒln*D.ƀ(_>w"0W^L.a~H )"7i:5:>us .c<3 d?ӥKI삩p8$9P[:X!Qx")ԻuJIpeA A=P!0Ю?U+t۩VmWYRq5 ߝcUbwj4,+v>z9?eJm@fcIv3S79l~RcjBʢF„fwFkwbF,ӴPq:Cb"NTSm)x@FMlAw*ߣjvbNV) Q J̋"-FDi4TykȠVkkCtᄰ#3JZn/k~C5ib '~VWV,bLsW؊2;'5s,w|V;J->Zl+ԜI"zvёfuhX*2\ƣ!R Q*IÓ<4/hʿ⎟;&bH] M\L rJ9Lv{n>/g\ WO, t GK'|@%0>amjwmLCvMpḧf[!h\6~#"/\2͚06r=Y8kC NU'y0L6DOX0Ko^HH9{㞁.ڻJt,c6SksԈ\o$Q/L-M=id)ҡ"I֋cH>fV^pU#m߻I9\{iSssADž]ke,P,=©p̓- !ꗶϚ@zp{s ᘱl@Է p%xh]OcPYwb?*6#(S;^scFrÕ VCžO",[YryiUK>=nk!NzNQwŷIy$EH2KVGS?*-Yڃ & #?1aq@$>_xOb]Gx%FJ )AL+K }CFQ 6]{F@W_s&ҫEŢQtyHxYG[A1ڞmǾSvLl+,G^C0&I<6]b ؛/])&K0BSܳ7&Dbim A /ÏS͑·̌1p Hcn`固RIOK2k<&Vf\_qUƖpvW^Y`F%ꆫq(%yhxdov?)ʒ\CѫpUpr,@C.ϹX\Ӂ&IX w^ 9g4iRJf_2:afvd(@w-جbN+m9fҸi@ȢPGm؝v4Ȫ]g\|_AČrgOl?qt; 1%|Gy)\Mw$d=mI>zlpKE7D֗I9ZiJ ?Kjj |]l cKOQ$e Ȓ}ʻlؔ1Fh;Ot60ѳ`=bld%cAcFdnPcBUi?Jϑunn%XKTux4-Y?I$~916dz~:$QλH=_+|9s}͠ТmQ'g_x֛tOc1KʼTDyj:qY5vmx*P*2O(ŅڦTfx`riο@ FQ4?3! 8<N=)Jʡx~6 Zq> ^(Ad.,/S"ѫul*ykPW)NomQ+C1RY_jYP*x7AI %oLj˻x. Zͱz*#ɂYe4#9q^e1p*>Sݤ7O3&muG9*-n5 X|*g4sZ2-$BIswˆ|PY\RSBy]1tTGMytv ~d?|_Sz Fm4 xc>4IPzxwZ{]ÖP 5lK2 ttq½{zNjv~HCr-0Q*VoѕwO.H:7 LAýjYtoda? ]Uf_%wJ0X %Zv cXgi^}l+dIfN6".=fS$VGǙ8# >wWͦ`(+hbfE|2š@70mf-,th En9Z`,hnr.''#@-CM:A+7he*m-/3p&Z`Ą0ABJ$߆ϑ 8",Zƞ I E"(,m3[%$κxq.'F0h d')Qp_e~}Q>%|VarR+F"H n92s]_A͞x8ZɛD^S 0{1*+6L/k{Y^@C<  _ }3@eˑr 7qPK^ۃV@ kW][pe՗lDz[@N?,: ?QP9MߐmG)3N.bbԝМFʶhj Z@A7(E1n @$si=w'~xenW8Uu(@b1 lB63ֈ<(Wk:h@\g,aG^gO,qBpja_cΰC @;7Es׊<:wmbL\3ݲ[)(=[LM`N2澜ÈxDpbTϛ7eaBG G,8YzI?iК2 M["mmz,8`KN:XhbHiSL4ƚ樢U pyR*Cna$41I*(QwF/G<ޡόFWBh%dGG$Fa./9@m]qW$Cx[UPOZtwOa F?}FxrQ6ig :)m/5P'9/)„ӑjU\E==hM%_qT0hC,T!fiU/yÆi&cE42 3WMͫ `h=EFő*&' BEWO MNq4֢LhefIcDg-0N+"0,s뜇x\>z=}$Ia[۔MHE]A3A!h'1^W|6\Q<X~N5ipbb1Ȯx8o嫪1`v2fEPY цqplj=AN6HҊJ E ^UJQ`c [H!9 V|`l {:*fWጄt" ECL80II l`j nM7{_䙦M$z@&|+34w'iw r9:2jt(i`5~Ro灡@dOG1%wv,YD7]@Sj}o)uĝDNJ8c˗\ <,SKVɶ*hW,-+@v b n&rJ&~gq1߈Ґ4/_P%D|0N 2(1KO}a+\66r/LX`AG[DJG b7mVD 駄 ^0tZ=z&Rt[ 8I,!{#WLMs4@A@M!MG?>[e|BJ -v/*V%/9)ur,#S}|dQ,.&+=Z ژ{Y㴰"O{v}Vx}OL#! 0ڎbvb9Bo^/y=MtЅr#vNԋu h&J$_dXv0xTS[f?0_ NcMj=g 7d!ORZJSIJ[{0,G@%g{w}R5pWn%^z=P BwI5/BS[[w,U >+'}l,_X#R+ 35zdx&cv)6,vޛiRE1PM2iҠHH ,Epkiq}J]ǁpO[.^;sr"NOV|£4P}鰉qvF`"dy9P,zӌ\|> O.'yŹ57h4CSd$)߃QiϵshߑatV¡/*2 гnڒ)fcX)tB ,qme}T9]:kYo#=4wbdZspXrGlS v#7)lm%z1&frT ̞4N |$Gkc<'h.aatEq~ܠ\,-M\+ n_9|7iw^^ta(ŬWE6q jt2fiwIjlb˳}waW}_xU_ P`qukڲ/X6]6cioZY#đ=WvOK7!q{k\f$61)3iAc39(,g4B򷮅~oS%7|]c؞Yx('h<"#&lEQ7)#|p$ h`zecB֛${jS+ CtG00cLrj՟(z0()1yV:*;!%f mEQhv[%zR]C%#"|g5F-Y YU( D\ F' )5jf[ʐ~.(F;%u׹iuy8мy^CWÙ9Oo^O4X['+cUvx/kpΔ$BJy UZ;5Z(H:[OYC_ʡKy3^CH,e8z=HS PVh7 /aBXm%eXs*&JxY2} F>_$%Yd;!oKۭbN<;E>[D &;O; j㋉u2"r6\Y2 e tXTPΎJ1ޚu[eF_mYYc<<.0x%Y]E.nH 2Tq%fqvSg"'b*1wcLUc}P(fO|2qbo޸vqyjl]s>lJqYO1$9l5@F_u%MFgy3>t197|c^Yo0=W7#X7g" :Ovv|:H݌܊S2iDEQ)'=YI$ȃl8Hs}0! ]֝^VL4o05 6|kឱEO?_X媙- x)ǍҡXB ;\ I<&h=|VRQM @e`'R\:hc`7"9hvcG mt1HCO550YvK_"5pBs_L: @~4.9U؟1?lĚwWIӔv,H`Xt-L%~8]~S484n!.9`zE&cO\468vݤ'$?CJ!tGjEJ>?l5((&w?VGv~.e)ӝhOjN[Ա_+,7BN%/(\> ゠r.PY`'s?US, ;eHSiI4o$&M `&n/NDLFw"9?B b~0ɐB?[BX@:r\7b7tϴB_ye8IX~ILW)enH{15EQm:8i;50EFqDԢ)[ }ň nEykE ˢ֙l57gqZFuS˥CwXC2!&L$e!@~`&z>u(5vxosP3\w]ot^y}!7n@P{X>ҿd[1vnUJd_Eh3әQxRշq:bFq4m1XA5vvF=7W?GQ0ll]䌘:PMY<; HQ ,,~j)jL۵fѤ.PqL{J&²vD64ٗ>/1 PE}? Xr߿]mCEۻu*I,~ uw < i*Rv]zv*Kx=,9s.@TP&ؐӖaf\Xk{g\̷}Әw9bρ#?KuKP!)2__wa_RH'E* >ku_IkIT& #okQE GHWEnnMoQt2A"EYMm<64"N5F>R6[-7HK J)~S61]drbBɜRο@.Ir2Ԇ VUʦ4)FbuhbAO#um/p;؛\Z3%0ԕoEi+W/a&R+-_r*ΔhwS[Rٱ096옄n x zÇO;9's0GN(ҟ/g - 0RS]Bak}$2E2>{>7Q5ߞkS=s*{uv-SAm]7u}uSD&Np/w\_lvh$Vsj2W]FWX.]ύM]kLE_\0>aG1 9p^w_+Gk?۩b97[n"NWZLy~{6$ggG@p[05/{vaЂu4s˜UV.i{?щ]Wj%߬^gBR{/ݒ."b[,QL@,PޕA.X~!+A(%Vu7IGuqn=@]lI>')_djhI@!q/'4z.:iZxEVQZ}P7x֔Byu}Iv1dW3=UHw6LŨ]$5 خ_? +yq2(|\jjl؟_Q}SH2r(adqgkO Ws3s^ƀ8VWfߟAA{'Z%_+`oOXN!۷j#|"]NavZLLy=1?w+SGzq=e&*)KYsev^czCt 8$~ӕ^BH9S`_yTW9vb!P9$XsuxJ4P92̆ŔOԸzv1BY+VLJ60|O6+;ynvto";8ylsv_tr 3!ɗgNnq0P9dI#/kjܚ5%*/LkS̭j @E+px֌J8I U'/qdžG,i3M",Ju \*lq_&I#FSM h(('{c~eՉ4aeXʹRlժ*t/%: %ouiAp~CBzt) -݂U j[yg>q9`&[>fMTVghIї8;^cTq-O%9΃ا"8@!y0E`}1tBL\F|?4*4#Ai3:-!&.9E69kol씂ќ"( `?49 T$dq/I`sL]5cPYS{b'?q&ӻOvχF{[QJ|5)*ti,dh,DfU-x0Fm,SS_:k}mg۵`ark-t_ZT.E©6C[ΡTœYSUz/NQ@|rs{=( ގ) i].C }HO-\|BQwt7-m˺3S.g3!ԲR 1>ǥ5kGHj:%3oSDoώ3sqi-O1M,\Ν7g- ći\:>E4_hHX'SyG:ޝ> 'JZ] F5qYf5yYy+H|U]{'NY=]%o)\S]//@F@=5@t58V||؉A  l}qA1֌xF %>)u̇+NrsO]I4,iؔ߈w'`o#WPoZ&=vQ61 Y@(G$49LKIz*,KcO!Jj&6ye 氵Ute(Wqs,:#.`$)k lFq Q< r A-*rNHP;g5s6MbHNȹY"FĮx3UؚJ<^'zC"Z"GJ <%3 '`CU= w'V[[/q&.0D4"һS:ȈUPEq{*콦 6jBJY$0?ɐF$ɶycJYX7a;ĚCКPfOƢ6㞧<ᠷY@tgK8勵l??MC Q%Suj ZvJ__TMfژ]vNj`?J7M3If.|v&qpi*~pxӽa}.v|6!WI kz &ܳU׋^T9:ЙX?^8]{[`qRbDiO=~&4PBgHjL1^7KPn*ˮz"tiӰ+M;iHYGh #S# ])D?1 (u3Ҳ ce 6ajqU@Rxl34مpm*1!a|c+ʚC30袁A]nFj(['DkrE$N2tՒrkV 'i n9^n봹R7¶SDdr{d qL09,/o=DUFdR0Q>2rRН^\7-Q,nWbKk=,B`@4"pxE}aT[I#XQvMsq=^hzDx2BS(ImGGvD5Ai_@PB#_ }<*Y>F!\{u*QMJlgj I t=P?;ۯ5%:AImfz_ أ*,^[q1#o ea0y)̓KVj8f@BP;QS:֌9|/#ɍu.1(%+kbF)/]Cq9~98j0`;^M/`/nG2#hwu3Eev}QInO߮+2${fXSs.?CIiPJ+e [1J(9 5Cpno̡xffVc' W0f + i>5(aR=;2Da1h<%4<+9! 2Da2i}uT^,-f26F1=.Bp lrab  ]t2×iSɯú̪jS3ș>{uBbtK l ~ u)e' ˬ!t׺^%:tMQy%T= j1ù7v03iTSSMV|>Vrh|M]llʖ;Iu7&'8b_ T-YC8#hLU94@ϕ[SzQᢝHVx Kp:Juy2 ,9QzN "DKxsvr4uӅZAܓR}4SzRBHz?kPVgC~cG\W+K(0b4%P6>uƫ z)fNcl=~6Э Tt`|\zk`aM<=&_"#X&u6. >}vn-:xxZ|$TõTͶ1w1;4 co"Da |vp]0 w*zg]dqrkx,ȑÓ?O(mWPN~PDAɞ9Cf퓢G5ٟڨڢzfm|hФ״KAAt¨7/G$CvM {x{smWїY?:a皐cy%{ȊnRyw!1Kcj8^[:%XO?n|xϟuC}MJi-aFB`(,'TZƊ"N+-DЇ~ чބ΁p=~JBa*)wZ#}x!ZyRV)A}\޵.I ܊uFέn anIG7pӈo{D\IP"Jd<#K  N'Rtl* u|MB2zGxeWRR;5#q8m,ԅNu1ql8؝??RcY%V#{wYP~ݳ !W6{j*V'i_| ^ٙ<iƥo3wuRx=9ޑEſز(C~u}迗NՓJ {je)߭jARdn!폁`O-xfI `">TU nMn5P9S'9;F,E+J܏6b X g+X #̠7Ir'4Hߨ=5CóV8.1(bSDDX}/$qd&~3PmYL-#K~Wkx,owXI%;]ag'Gr#W( aD+ b)֤3F.哤Dh`QzK4&wzT".9~Ps2*^t[:L_io6*=,PM\wJJ ;@_ɝk3Wzԏi_0 rSzCع:{iݩx28Uh$]4u:EY{ۖM}vk7q^]@9UpY 2>/^f&<2ԁ+^EDץ{/b l5O<[2@r;[^%Z;- bnV3&#`ÍW_U,E 4q{?O+V9q!Q$śs@=u@sˌ5kE"l SվsjyC8X&RT⯇5 O0< f LY[ i|T0}c;eW5 #q2QiW'w>.Wb_*!A˯SA4ċHDhOY:,KtG*8K3cdqxvSX}Y$Qy~hq6,S!՛]uWT :9lppGۖj%V)MVǍ3 TlOs0>@H"XO\"s工 h@ql '=g̽]Ë9Ea];ٷE Tw ¯ wq%XZCZ02UڕezAlx,B.*AD|AHJ4iV4o8$'a.dp3d 6x]khc#[T, _(i`r,%,zXfb~4SߟUN{)ۡ,F12j @f :SiP|gm!ft"ٙA/d-V^z^/x}S$qq.穯 wi~A.GRȢoR|Y@3G+p=z v JFpϳ==T,w@ڍ`E[QYqҽ|i)ם7.gLvǪv ;<ꁳOs{1“`B=bȾa{szq+\li!9OiF4fik:L0-ĝ'\on A И }x!f?82zy\D,֕*Ҳ5dQm~2:(3L.-\MTqI&PWVqKRC|)@Dk-XZչ&rS'm4~@;ZHի&SOj2y|B;DK㋛"D
Ca$>ʰpոfg׸C=cjD χqD`&6v|4_wxWܹžF8C^I@[)6Leg].DPq$hV:Ű,\VD,[hv["ʣHgsmTK<%R,sc TO!xhNs$!WѐhiMShxb,'ɒ8Ɉ ??g;9I Ӓj̋M>q# ˻0`QRMQ6Fk; }/ DgGEϹaCH6uK0QY!8bcY'8L C@"q2+{ i;n#EȴG2XzڒF*aZpfi&!o w;Az"ʡ;F܉ EQ <34:3'\) D6.R4~>"]fvb8qa[m295Gy!Olil ^K-Ye-bt;V{23;<"&n^a5#:HZ{8mmI'ǯ͢+1d.? ^eTk$q]/е(s2~-Yx6X}ƐGt_MŢ7ga}Vǽ,.0k%J.RBc` c[l7eIU [4_IGJ i+?::d"%a6GԴC4SMs->Lp"Ek놊نorDLN0H[Ե6) )6haa?hf!u<|`{D4:}*oPoJrN]*m+*f>#RwYkwgwƪQzZ#!} ʄaC}v/YAS9/BwmŒi*ZueqB?~i _qZxz܍#O2d +/lUWтCUؖ#XOūS THvЁvz~< 6u`1,ZcgNs@?pO:|z (pG:tp$ML08WWWi8NG'l8DWϹ+xJjIx0qddns˕RG&e YT~|ᐅyp+NՎK +8Y$q#V/69pVZ;SCSTBWXz`k^%\#l;4`q&madP'ẘUcPC|Ņ#dfct67Mb婝c(:EnܷJ10pjp M9z9- Nj $WSE|_oTL޼$CBA^)-',(/ ȅƗ5yN0 *Jib5JXԛ~;BYP3mfΧ/m0$c6 ҭH]J]qpWz"PeU٧*,/hۜI9b{S-Wz.udSx1)I]$]?j)jPM\9A8l6}QNW;IEWĢ]=ٺ<ƯSZξ3Ų(3h At(ZQN,'>#-1#g4{fEmTd.H7+X..$ږ}) Qyz͞ ϐ[99S8}b1ozi̎@SC CHp-!!/i/#Ħyj,򧣡͛R]cy]䈉!-Mf" ygg,knc-4Й A֎lزd[mY"攜 J9Y%74k{W8Ʃ;gDe&/g>A$VnYYe思nYVn0^L$K#NϒJ k ZXqq%GX7 .%svw8Q`px+sb`wAb2j+\,4<~qn69?+Ņ3m=vu9-tp0֓3c< SB<cj"_"`Rs,*94jiţ (% =4TZB3!Dx"A? ψy? ")\!7Fc:rl]DBkuCa5IE8^I$ŝEydF  &wm M%>9 / xȂvF+E$AI*w 7B!@ĪOw3溣#p+jo9(lyZzhV9M5vIoZP\[Ѿk#"?qnff$(I'^ܝ;("ߎ.Qu(M<U=9 Ţ({D(ʜ^ 煝QW<|VF[7XqWl_QjS:q0:!*g3 + plm 7rR"M3m1$]fm']\?^O`3\_ F-#vؤ7H]Lˁ8g]J]&rF^\bfg|R"Ϯ_g>E6d{%o\Kl|yg;Fe9뀳bPA %?WGah~5m1:،>O1(*xjhǿٻ7eybf݀Duߙ%kkm1z&ZX:t|C<^(@1UwxI.6{$KB՚%cW`X!]1h݉detڵҽw!;!==؍gX9{A mk&dkDpeV8k>=ǎI;0 K8ó'3IvУ|Ux6:RO񙒂:(]_[|6- 4䠔1jOvi-F<],ݰ-sv"@=@ n( "sé#rAsi8B9aKU$xZ4۲˔Z3YFaxҰ}:!0iQ ߺ_dbOm2$8+?ќT󛞑U%WWv~W =#M8LP=y!N[JsB'0UV>Zl;vN8 z9Cۋ-X277`&~@k)AXT%iߗ-s`]["3k$^SOowb/J3Up+N itf—GGMIe?~,$?Z)Ty I '׷1!v4r4%Hpke`K[4\=wm\n>V/@IA ^AF,J]3t b6oʁy1 *DYVD,pO\RĶ#g/'JLÒ4 uvcuژn^IڐсԊZx|!xJ3gX툀iU|)wlҎ(#zoыA2n$& gNh+ߌȪ6w_(a}ӷP7 D 2ᭈvEd#%1r%>hIKPX[4m̹=onh%C',փnOť?VA.|jѧ{ǒ!D蘣n|[QծisPRUF]bG(ʽ_ BY@S.-Eo ިV/sU~XU8 AK"L JXغK]YYrUf/CG,&aGA> Wn8.B2^.Gq:'yzJP56n\GA | ^[{%|Qh@czlkeOGb!HPB-aldDMh6Wđp+g>a VFM]ϻрo.y"+ӝ8;0XxH"(2;TD$Y apQl1L' q)W&:b跹#]ϣʭgc.\ 'vҩK o[{ CN)F\8wƞ\ . ~V'wZ JZL5()ɛ iK{} A؞~6E6$_^{B'싛V>TYLz9C2<+tԜY7OZlfpĕqW#=2MզG9IVFS'A!T9 H8wϾv*@J=K}g]I@J L#0Whx(A:[-]ccHDX*gպQ`G!(01wţ(&o!1ԙVW~l^ֱLQEtt[NۀOZe`E웕Q,zx|3f/6TMÓt\0D+`ySK@yHi~Hht%b ]Tʬf]}Jcx,Ck(zu#A,Tn*BWT=d(f+-o34644毕 ]^XU}u4Sq@< (rvZ+ج;"#G?$2y4q bOoE(g &P~j ]I?a$+{5F-Wlެh6Lؚ%^pĐtJ`eL:`?[\V` wt!EE(eu}Md`GԐ,(d~0jmS,-4BStiUGxl(6Z]n; =UG?W;TNXBpj$"X5U5bAEfUI8ռU}@Bљb"+ʐND%`PTj[UܩnFl4uHW"˞"Pg&kn,^Z)޸ں49Mn@i`3\YA8( a^[$)oNTԣODjuzJVoا?vVX 48Jy$_a1m[dDBUIq<~S ̚' rw~l,'~q;=S_G6o} #GXe~=y3+|27Ȥu:"X~_ch泝3? b}y;Q[ 9k[X>k_fl4<8sC2YaOf~#Gutp_F7w*/w@ s Io&9x.RT e'K=kVg0[{l5#,>JRZ^֣$r{Aܱr9S|N!VKTtı +e1J=20m`-OG;5S**O4B( Ħg*e3_>kw> q5Zl<.j9!RyT gEuvә#y [E|H>: i5?r:=ܓ>aglw΄b-LGQtyԾ)!ҷw* 65V2F׎N к%< )vRvmSu]F2VLxn5&nÒFVȖ1Ll)[FQcbxkNQ(su,?GL|33t*5" C0oUmfX\A.?qhd "@^ʵ#Cs!z2c-Sa0fT?ny;Jw)2&A{N1C-h*3~rbhlFOOy΢yOEf!{ERH'$tN{E=0<N{B1zn]jX!r:Y%,lmNr`Y7 a&zsh΅FAAlFA>i=6Wb~EUn2̑R(eNbxtU`#sX&DE-6˩YVWn WjxBD}ޅn1GUz&]y"f[r?vzG#4W@f[ˢqw1V2w4"i*zO҆mN;.;tĘI>9wxQ[Rw RSL \.<lƜR#vmS1a)M#//^o0XhLeXr'.kqEVsܒ_URCĐ% *=Zܻ_)䅮-i7BEw^8x!]5 ZHBt3}5Lv 0Wq֠`J?8nFv#o 3܃- .4n^,ij,.Hrɠ}Rc(BǁEԬYwHyx7 ToHĤ5nw%{c-"Ѥ;Sh7a޹+Q2ӎ'+4+gAfqĉ kD{w72qE-(2 #tU*-y$vҩa%ozr*Lˇ@LgfLWс5R~4aq+TozmبtoTGKlxM=![6 Xx}$a`ٰcsےϡӔ8{9'oB*iҾ<# cBEt;Ry:(q!dMW‡ K蛰tQ<ړ8Z ~&>Di'{(g9H,-OGeˑ>3os&x>M6Z#JLVFI5M4M FTN^>pд&]8Ta!uѠHS@Re1dA%[NбHh^!뽘1}ۿH&r= ?eM;O:cP]"e"&R;G}[dHufL*_3.zܤ*Uy4n#4N6CkP*ɴfB{|H_5))T4&;e?'(XO~ӫAwt~ 0Z2@c1 E3zy3?0\;l,;<7plyC{vk$]厦wV k=6Aǿq֮2? ֪ t!EѮ+o1 C :`h}|KO2F#[_]&Z(-}ׯ;xSO6cB3:|ȥDR `8 եxsJ\>-2x~>v9ݞSm׈2R"i[ A=OWN,B)N}f]r8LbyCQ)[oФ#mAdy9|H5nZ= }5j}Cns  Y Y#”ӖA%>TtpNHpL#%LҴoI \N]e'lE"TgaVֵTyO >ubof Xhyu1&eR3j- `cx>>]lRlA@EC>~]ƪ`jqBj2\hiLXwN卑1VT TX y3ov΃Ύ(s2  :h8w*APCnUI⼵pm(^Etc3n癜nPI/ =BT>=?i'6b]eҤp$( - -//oZ9WǷ+zD^iψ&3Ӆʛɉr/0vҁ mv4>+dž1&\Ut ] GQ0j-]JYDs$p'w$ #`y'?&p:DauFe8~96A00/ZkBC~^3_q5Zi2g+e3qڊ7'㞷ڜ!F/9\5pCCwuAfh'+k.lr-q4훖bEYduNS!`H ׼XBYKn>!Y_,i"bR[ nv$CƁy?9JU&[u0!tQD4xn.o"s(c\+6tgEs/tN; Yկ-j@"0:C}t=xIxv<4 3attb/ Meq0&k :v^ImƤtoUE*$WKi.~Z0]]/m]|{:)4R)I:8t̀[fӈ'22o0ݢOiYE=Vi`AOq`|Q  &e>7zt>A3QHswKﶆ78 BJ!71WM(Ǎd{MSzȏ#ŕ9CToYy:M2gϑwHIq=^γm\0B{iٱGc#3J%eׯw>nֳfGV/C]7$zy׶= ,FS +cqZ*10E!et|{Dgn)VGvHĥ6 /6ϣ"Fl`fd.hn|2Ø<= qYքQ;7oՑhss&dבXZwH͑e 'J(Wȟ| K?&7>r6aGS:\rIz3Yʞq(JvGV֐Wb\m+z^n%MuMkVFwhijrƣ&b|'i4x()Fyg}#aܶ 3a(/ H;ZjBXj2"Aɓ^Yy Μ㗽*S\Y%if7N #+VgFeb&R%:ɫ5JyK$U & DT5xfZNJ$Tֶb~tj$^`f;'=h74u\2]gNWljKƮ7hh,i)oe„U"smQ((@Z$J5LOr'F59h f lI>:܅e5B >T=Dd%/±:=]rNHHF}<(:I)I[Pd% qls_G;?E E옘E1ݠ*K4=p[l?3O aE:$lOWDqeoySΠ5jTGJ\+W5^T{HdbK':d}*^p*9 t VYG# V;$#Yٺ>ÌXRc 9iE4e"+]UBգ'-g {=ܻF>xV@ySX&qu6 n6ϸ*&w.!]JeԦxNᓇ=\4Le]%⪐$LgVAfu,dzY̡NSSa)ť͒ .l\?s!!̓&F.%K,\p*斶:{UjwWڅ[e`}~4b5[;rڿ#bpkIJK9Q͕d,v.w<3INWo,"u"=Syض gyg]x]fMO"%븚󿂉pBsclҜ"]=Qyz9(!0(u C=ܾX˘ե޻5#y7G OW'ڼ{EAYF5~ ~QW侓㐅n8%&qdw @U8Z  n /l\ 5eVe=w4{ ߴ8Q]a= ^q}`_im8I_K-o|~M`cqчӂ$Y"MT:A= bKluer1wSxW(hF)9NZHӮTM?03Tg)m,K '{Mhu/+!oYZ괵 [Dja29_ ~Ly}ntu(1nֽ?퀻~af N;47ܺlI@gr Um~"a8 YnYgboA43R*YI[CWF+ `7q5{7jIW!)8rV R ''TEꅻ.jPwmwg03Cr0KtNnV9 c՛BmtgExN.p(_zV-EUȲs k"D'[ܤ4ب)3#(nGMQT?-KM1tJh{X>P|Vss}I4p?WTVV)=v*5(Dx#jn&h; AŚ!@i|4W?Dƚj59cd0 u! w Ozr82셶ZJ;C-Hid(Y&6[L((K{r( 댿kT6Gl hpv8O#+LIQ|[т:GA~ ӑ:pϝL#NdC W;3tRJ[t*q\2I D5'Nzsp Mk<| P !첕~QSVey I! 9"yc*78@0({)[Uܨ% k\@pyԯϖ:[shKSp<R<6X1|ׂ& !%LZNlg|wN%1fx~;e Coӵ83aC>".},d?yZ9:3#-.(ᠡƲKy <95!}[oBG%tNֵAm)d.B`E]liYaúvF X?&Aܫκ'&%{v__U'n+>TH|ܷikAOՑDt87qAfEe_<+VWh4ExZ[jh9iS$b_TԎC{fD<ѨI0=8"9ms _9/nǿ&O gb B,Tg ZH(!hJk |!dwJ|.: ?rȷ~ڟ[0 BR)1o&RfhVQ(1$y L'}=C&'TQjpm.TK_nzSc*`#]aV#A,Z~GN8T1ɢh}[HfmLoR&D,%Hub($>z c#a ?oE_/Iۚ;>nTqtQWQZbqUd.<}vיS(݁hFjH v[7t ju$  moC:d .|ꓭ𣓈@‘EemGfz}N V6U*YO%*Qv>8oxh@ _f%V&"^ rqy¬lC\Jnj`JK϶\4<4ոedv4U!O=F_ ^VɑKa6~bzŚLZ 1uͨ/䔖,ƪ `O)!8\P&p}IF': n`ͮ/inX^m^KPR l / Ŕ T^|}nuf$ |p}G*<_ wCLĔ>+~ǜS;Y}Dǀo Pbd`V8ytg9~X!zJ{Ҹk7Rάq%}XYq7#Pc,up]{Q덕 Sbnz*9C3e*Dk1aW$L(4,̇+iQܳ["iAmD]C2PW!\*7)2&>ZCiN7%68@rK)Zo6B~bOs5%F3A7^=a PW+.c#)NUQKy'EZx,l~q2n#}+L)wn!K8OTWU`Gip*7xH9xbB! dkr7U(j3mzpNLiDu֌#QщLuynAuc$Tdp *BNv> 2(u-g+|.HmҘn+2OJ>zj&ڄk4ՋF,1cuGAby&5FP>}aF`8>%<7Z-WXf]*e쩃'o`gˬ\ZY*3¤gΘavwA_q/>_0ic~`7gc[]:(Kke_2on*>ɶsG:ӿ[[TW2LM.e8 ,y-5^z+MΔ q(Eަ0`mG,΂$G:V<7) R8!tgc8\I~E#ގuh!iી9n;9eWa6* Lb(ȗgP&jas3I\9}BX!5z2ńEQ*V!D pZ^>j"F躆D*&G*VR$ ]DB +W8)T-J XQ (; Iܛ>J4O38XȰIwFgbV7m+<}2R n!yD/OR;!׭%U :{ߛtSHI |i}?NXV'&7zX>R[ ]#,ƉM$G$ FF$/|ȨgȻ5bwތjvm)\ \L| *dc!qM~mD bԒ΀lVZIϐDoꇃ؎>'X>@F\_`zO d|_X]wO$vWl~Tɒۥ! M {ݷ6cH0:4/kXs=4;Ghs*)^(|UnU\<rR1:q)\ހ3 Z։f`emP-[D|+qs7LŲK d,[v_eH6ˏ^QT㳧 O Sd[Zo%/rLMX ii&a[tX^aM6o./˙>MnذeUZ@P(g95/@ΆI$oxl ^XPScK "j(ymOzJxƙmH]BC;G!od.zolnH"~uGED3=6 ^1[JPL[p #EM#Td ?n#vjҦq)@[шn4T_1B&SPa?aRżVvq0]t>hՀ^?K^3 X²^?c)>MDH\?k?}dG)*NW{,9@[?q49t"K8xgYPpEK&Eh;29E$ŤxT &B[Z͓a_E"%=A"X5t.Eƕ z4깂CV6S-g)=ҔYX "2mMk™n˗$Xf}z׾OC̯J;L=Pŀ#cNp"+-化^4hsM^Ae2aUj㧅X`6!_wn-V;4静w+p ywG)ɰjآcNFMOZh4g2Ir3u,tļYx7b$sed7y.NuMKscX֖ +P$%G̡֝Z5lP | 3`L"Fn->]}oUub+o>*B[#>LsBCd8-'=7ЪP-oVW_ݡRE9 5Ţ!K+vlh3RӸ+W2҇ WC2@ f_ddTE<={,ỌNp% )prDǻ pFHdݏj^I@RV~b#rm 4aG.Lbfd&!>7@ vB<;,=ycfࣇ|l͹loEЧ* u T7E8+APڰY!~};1b+C)8}-سh(рLꑋ j@Ei3=h<>}5fl]{(&{j:BåXxɄ9 Vdu=rujHD{vүeͳm)rٍ ;ʔF/ ;uu: hZ6;㹣;Ƨ Wh]:f)%&{[=QevCS?KS5]OֆLu#WG;0ykq²Kz5_/)A$Fw5( j5CbOdep?w[:`]Kq62=*jݟ wXl6W=ey@Hk[DIib#p`}D 6e?/'6k٫A,@QEV5ōSa MWvHF_<{/?4޲%>ie(-w{Jvjn "sXc(94hЯwiTDUꉝ{%)@MGN'2>켐 +L?ٌIiJ8be&>/QHīZqJ8wq6.3 VJ'22XLD ң7ꃗY'lP7D".׋ I+k04aSu{ 'FheTśX?lLJ sEzi_ *CL|(v- Udu$:VsYϟ̓VٲE9O$|H9DP%HbGV7$RdR]$/(*xi_HO/ Nnf; Xd߅x)~.APgq_!m?ئJ@d1t*j4=`4GEyMF\ٷ0b GWVy7Y:uގ Jŷ8&\L.h9'y[u^-l6`$J_'`6qrfo nC03%u/ )W"7Cmen#qq'O&2/e*uZ p$E ˻e踙;I n w뽾cME*Kb+Fօ%и$DݺN利ܿ)7XO^ 1GQ]p&uØ`J?!:qm ݪ[!_=uLmhH‚ۡL{M̏Eooou[®ꌽ=K-/f7+м{0{7 Ri@59sazOw>NP,P禮HWȺO_틞|L()!!-بMR+~>jn e(:b È_!ra;G@Ѯ3<6eKZ"LP/N 1Asݺ9}*L/]7J;k jƻU^(G+10LѾ1[ꉚ-; tw'(ڦBIzͯq{Y lUjfൢ3d!bJoRn@k_771fa5}ܡ] d,bI]}q+@t98}8i CYg Hf=qq٧wwRz/a~/_by(a(J(;?jmyӪ_}}]-}|0 #ikW م53UCkBrMG|}z*wnpl"V{LЮXy~Ke2R-l%WIMmϺ5?/|?-WAӣ K`x/jGɤ=~S-$Y@Ә6j.ROl4"M짌\yh02PDfM\9(![r+>ͥ(}SO)Ōo)OX=g'dZPCOx ~L$w>B 1MDPǏ,M~DBGE9?Lt{ڵ,m?L%ZC萜X ֥=#)IRx,tN`r3ǴS2K4hAUC"%Gӛ'4gr]ql[=^ռ;Hi%߳aR'7u>e%*۶E!!^0B֭LjsWVye0$mVc?5=xBZߕ1(s2Sqѱ:o۵Z*4P | ID WOQ\A,B!ـD#e bd.3fʌ9UCSVk/-VVՉ.ȏT.z_6}.o>ֈS԰Umi1G ]}fW䛥 zb¹:Q?́)' _top X]-0IkXp, PpA+FdIQRK$EJ=ry DO2^ADj6 aU|;5 c9SUYUu Y(D:I} ./کFT7Fu,o jRֽB55ԂӚ:ړNl7Vl`rB?#|S§bݎvAߨ k^S,fW΋qb̗v{8ؕ2{rdS;xp6Uk~L娐:h5 ~G@{X"0L 20cEJ$b{S{14ož8(/ Jfȿbݱꪆ3Pܲey%PO;Q&Al![0ʨeeB(kߖ![|j1 hU(:y7mel62"ùDOȭ *\4t|vXk49ڃ¶k?5HhY'oe5 M[gO'q$ q@Fy;ٯ ^Xb? ό RV8M9zݸ/MR UJ@o /"M$G/ctoBҧerfTy'ܼZ/I&3rj$hZCB=؆oQd.5~ 1K_ V/ 6JAi@PJ f)t0llCá773چeN)PFÛRjlp^ED~,7]#-HSzuG"'&#h pI{. C̶% \$xcNuoɹz*Ü1Fn&ﴘ4}pyใsa@sl?Iggz4JRf8C`@`KgVep?+SIg_OobheFM 9`C2EFc8ϸZ!zĽ%T4ɡ|ۥi"-+HUTH1 `r,P`Et9~7@@KẼQ] {PJlڥfaBJcC(Ț&l Q~͖8rmfm!oX S 3pCD<TR $>O*K I0;PN5@_{.Kw$PS̽x+Z0nC9$I 2hZil۱3Z`0^FMk9:WǢA͕=hY<:zo|:{F5ma6{ 'E s4c9 Ab;X_[~ 񫿃΂Eruq5`$a mӟM3.ÂZRMok"]vgGl^2c"kW GEӉ6\YB[HQ`|3h|4eB@G@"_eV, ?kt =N8ql>mUI=.5ɯK^ho1Vp搈BSNTE"e7W ^2OX*C|I(j=0-+3v5p6^/>CӔ1|7YA ozQb].LzDtdYBoWNs]_AteN ؇`G6tdK}l\u ")@cǚilŻzomkJU@ډJQmԡ}&6)\DՔlTo6HK7Oēڴ-q3KX4dE_lp|<Ɂ,MOXZqvUdY,^a~Ny`FCs,C`~bp]kQ3֫=>ob$%hGhkDxD(Ē 'VCϱ4[Uv |@3dJTwT%} |AEdq;1,8&<Ǯ;Et7cŤwrUCjG:/ #[@GFt{wM)֛CR`Hdf\1->䃥fjپxhsLx$xphQLEak@^AՅҶ&9ڵŏBxW%Y~ 9u&8HIa+vOfЎӠ\=^_ngK`E| 2w`<] +~sKojՓ:U?ؚލNҧԖe"i}|`>hS-'8j@dho3l*"_ڽ͂աC5ѱ]6C;q8謥Jdoy|eIjՊ"?%~z^$X/![~W0%eYE~e܂uU<~H#skTw]r^2rcw#U!8&w^;G4eߟHxݚYgusg̈́#XllM0DkW!9\QDXC\wxz|LCGAsxnwl;B&T (I+3ݒfM;)uU< mfaSXpG0>n~"~[]7˝ezsi1,Iq&(hktsGzP9RE |E:cn¥lh7CnBDh5"C`K~<[5CMT3KM(/yh0 DBџm;f*NȮ יrl]4+'v;NCxfeHzp9gAc0tk?[3K)iR& ]B`&ڞX&b3. Tciz(ԹI2Dx6[Djȗ}@ Ǚ K/xO tov!yaU à<Y\zAl=$#LrM<,ءi6вFKf~n !Io8Ki;˴^(X&F0 1'VrK"[ <@fsV< y2[a_꙱ih-ݵc%TSKW=J!ɇ)\$sTYtd%D[ ܨ^' ^VeL=tƛo&Պ_ ƯU1;@Q9[4d84 *@ k d!QnGbA!w9 .icS|W `KFg6;|mfچlHfӟJ~dܐ _)p'(c|-]K:*jͪ%C -z,btX}Ƭ-wO0Jؚ|{6VOz\Uja`0ʦ( x.*̍信?Oڪ1;Pψ >"?t^Fœ/x I %M3 `mIT'׶"2*b2ɊUŜ4-nwKK1rΖ~ ,SO1g49 |GR>ޢ^,I𳯨slO Ya~A W^Vh7PQJ\8xauBE;\`|X6L= gnhLFUX$!;ɧb/Q-ݫuG\p N!`_LgqY ^6s% lG گu:5m^ЅK`<|މo̙8 ^t5tmύpa1#WTv쮉'6 ESۏqu4%rkl®u8-bdߧ@~Lk]xԗ[1R8`}šXS` 3qi,t|I'VRE8fh7)yx7mwav4ÍT;/\.]% q>uX72s$fz³Jv \xr@;s-W@80<]WNfø+0w101+%%4:d%0)3:DJ5I~Ycڠuӿ^5.1^f.x8x<3헸 5b# ==ؑ4_!4M)u9"h {Ί'(w"Mށlm8uQۼj1.oJ.1S5qS/EɝdS|82 2τ!D>RSԫ0l}RAcV:oPi*YKe[sj\ת&}&N: enxsZ)36l.KmP@K haJHtt/eGW+XFyDϜXQ-:r?q o޺c&2i$]#,k Jʱyno0i2H38E"Q_gq1rc!=,1MY↯yF%WMo$Ymj- cE`pvaOg>Y!;XK`[D򘲳#R*Ќ ̫?m=${M#m4'*z2#aדصR5l3qij0!ǕۯYyYUuKVKJt9ܣ؇KV&uXPr 1IX(ZG ?z _: ӳp *%#7+W4&0.]1,HO[產Ra;cFo,pI3  |G}Fxt9 De #M; 1<{1&jO#5/|kMVW^Oxpƌ?HJ(DV^QCZW-\ =))^8A=[bym&5pͷAm iaM{g cNem:mtLnSnv'b+rcra،ӝJII%>S 5QŢԖ@>eS(+_$VM_NREhڇgN\5o u wL1P24#G[VK˒ Wq,H#0'j_,at'g7'9\!ZZRջ2}"5r\ fgt|V,f[ɒN!rJ[10V:a鐗&ʛ, n } vtbDHRJ ~,R澹gZ>d} X*ke:5"|q_.ЭQ^ 6VK'(|Udx_79,{ؑNӶh)h*ck,U6#%C-WuD]`'~e$Ռ(CS\av DSI~S$~9̒$c -A'߻;wӝaco#!ޤ3h#–uNTm2W8v*1SoU&nAQ80+;6&iWqvAZ0=ѼD# B4tˡw#:Ht3P"{׊qxPsa#hN(!(`&`}~ 4s4M5(f9os}pi2 9 ~hv%SKpsUI  en3P}zQ c1OzN@/=9jUzE ODpZ*4s'с?f^':Jp%d TNkT*ȯYD"vO={H0P6'ͲT0R"4{\r KA'x慗M̾Z H%?'$9u^K>z$1ۘ kά\pxxWX?,0ҴzZ=> M-@<wN P8czED֥ jtznj!vG`Ԝάm9GbAGZQrRޏn]Dw!k1h&.F񇙴#\U娮buZkxg;?Xg#];HPdAWTaQ,KVTF\Y/϶*B0c@B0}o_b SBm*/WٻczzbI.X_ 6͞,xOU m%"`|:(F!G*QMx^.+y;r)@+'#_)^2Qt>OO|Al֪7BϤ .]nC@h,5׸*NqԎ=dJug۞$6uh$Uñ$9B'Vŝ+H 0bz:@+]΄r g(ثA,%gxϯ. :n0!ãc*3wWw)jc_s QDrƸ,)-Y>Kn^.=Ċv_M\ԷG L#ŶUyݿ8%P~ձ~c3 ܁ءVkNB]t¸:d:jz䵦VlB^Lpw%źuLӇ}W9F˖UXJCTlb?w|=ӵ#)XH} URtp ~x -rT2t>ķLZt~y $U1xݼάUhxm7FH::l/IdC/rD¯2TtcU([i(h--œQr_D$nN')<"}9' i*کWyH2!/Tv[by6j-im<@؋8 !t8B4ch-pE;ꧢ~|(eKd/fx˒bEk4>KE&gQ*՞ :$ŎjxKXm{Bso"%?9ޏW66*uBV辊7Z n]86zLw76GACUcBN+6v^ǙyC;A"饤Zǔ[ r\{)1f8QU'k ,zKh\ĭlhda!>t-O!@]-)ڙ NyД¢ע@1ynХ T/k2Đ=ICݔ:6nb̸.FJdϨ[/uLU* `^ͧ,H~3%26-fcKΠHj .FZۉs@+ ؄Jjݶscԩ!Mu#Q*XU.kK4C*9M#zF^ҫP!HU`ޠg_F-քݰ`߉hc?nF݄^a~U:EC-L tbfpb J *|W.7o"9 Nos@c{atCOڮ7qtb,( qƥ_VgMM3=< <4/W"g敖Yoh=KӅ+/H!Yt֔B__L33 j8F|W0.y${<9ǵL]{F͟F#ПDT,>']mhq@\^Wr1|ٕ*?~ # '6bGJjP&md]z~+J=ے RxP_ zp0F7@Q\)6p(K*"Ix/3hU茨Ԗ*?KNѧ*'ۭCi8:ϻa/kh(0%Tqr"#}G"ÚO+ ͻ5t1)W׭\ @BTp[Zb<&Aџ+teڜ; Щ-ÝZgj9ae@j[lnuD[s+;|WC% 'כ 9:`z|_A.:{& "NͿ"ݩRZs@HRVrTT4DK*tl᣷k~욀$r?O'΍lg{.7T;Xu#I"2;o QZP'1D-w&#ioűjCYskBRTL;JHO EՇ5Bi}Ps|uHy%HxEoT;&]NlUD&s%הP^ IL8ޖxj͔:OgN?u# bj]tJ?}¼b˻u5 Ф%H]|>Q ]0:WXyQ?]{Yf]ՐՆsa!ȟ/?&i F~bKC6I1Y$@NVč/#q\po^m}~!BSnnL{VztG~|+ cRi„h7ޯWبabvP18Py5lAdl,e1W0kHߵY4׸uc<#a;j]̧Kk Cj0BX$UzU0yY0Vc&4NbFXsh[=I= m(u{8}hv,e PHV[ Pz^El .pd.嗩gcQp˅0ȦLOkXECQgn$ ao [.rqY P"\@=RNxtŜ2˽6Qŷ@=7t?ԖmJ> \܌f߀✵hء>QReL"s}}MXjiAmߍmA]+~jsoX&mS`KAW8^@WȨKx|$W]y85O']}893O^yIʨ\AL)=#I'F GulW x-+p\-K(Lgf$]' k'S%3䩞/gg %}0:ح Ev+V GWے8|X$p/+yJt&e;$0J%g$' ̶qK/,%_LТFnsdq 4W4Y1Ǐ G\p=4/ߤ)E, =h;'s胠mZ{_2e5QuF#h/Kv:OhÛ\Z|m>u[ ѢY _J),\U-ˇ-2%&^0 Qɶ!93ƼS+&[[1ں$tQtVQK"m/l9@g-U ʷílNb{k Z['7ջ4WB>w(2$a/ck|ARJy4\ &㡷tj'ʍHF nat9^ GDV\29N埜!Ft w? Wī8I~F^+0?Oj+<<׿SizF>W _k];JAP[&#E tU R浂>`Ʋbغ%b>w}͕XJ0Iq͎Gpڼy,cuAHl+h+s1W& `ȀTG곻n:& N2ӭ=Ĥ6'+6Sm;sE33qe[2ِ48D.c2 D`BA(RtvV jtAfB3IhNKH{&F;zp[5YK|pP,Qc[%zkT+`2sʡꎚ݉ {of1XIq-JI`'\ snKs_/*IC^Į"S+0QbC@9(]Q$q˴nW 쀓ztuW RIFyqS I|q|'}7~zTN#RmwD3HU[=W|&Z_ɩ%ҋ*p cKtz!eK0յOY5G3ǣi"ydE❘/2CSVہʧkkk7{k35I#['y`Kn\?rRyğ@p/fξ3YL(ȎqӅ!>`@T tl ;lΪLG m[{YݲS}cϡf3}c%eq6@j- >iҝ˅FLk;˥{(*;J65+M}o۶mIo, Ey\c%>5h=-3U+l!m7~߈;m?ZMQ VaՆQ]MTy%g} ~`{qW}so}CSj}dN-l[K%dlOTKx:Us'dŻTi G <\ dj6U`,9%g0 Mz?Tb|͚]@躗#9dK İ_}a+{Bەnx>qRs&m|?6׃r}Ø*>:sj])t6=ijD&SyaYRFEհ{Tucod/CIvӼvΤ1fH{/ށyB; JUz+>8!ARF-P8x0&ō9guc>2*#+vLI>)cQ3@.TdܴAlO e{-lbh 0LzO~nbp:)bF` Ic%2-գ6GK u)U PҜreġ}MS7y% 㿍RIa=:ېgϛs7c )(X/_'YK):=4dW C%; d` DaeoݔZ?™T2IRj頪8 ao&@P"5 bڅU9*в晇p e> ]&z2e8kjo*#|=y]u,4 .}_4+ƼѧrioD_'.$tK4׃nE,,d Ų.ʈ_58_V)6vI]l^QXi}pt/S}F2/T K.oKx}7}'.9Q`*% V7Yp6DL;:p(DKES[)X-_Hk׈l\A7)[ùTN!aVbz+e8l!PĊ)M͓@UrO:>VLh&.U!z_6R$W.lXf,FYq~GIFokZP7dw$U`xD+o2rw{;-THc)ǥx1EPC7Z7= 9W.\x2r/m׹⇌ѳ_}2TԸ+^g03f"Z#_7RSz8e,|VI#hMJY Qظ[h" 3!pϫʃ4ɞԵ濜:z5oEMjv噆UQIFXh5l 8$ w@E\٫vÿ +V1-KFM" \10_v~2ñG:hmwL8ؑ@xz'c=a֢./O'U=ڃu9oK|in]0AvjgcTRЇgO]0KMIh"T|&" zvyuABHN=Xz.V&jAv7N{Z#bk9@{of' d9@VR}|㌷ob '*oW]ĕ%?FcTi[ʙ!cOG$%ˑ#]Oɧ`5"9mVC˧ڰJ.x1"5 f JMwZ / ŔC Uĩ%KWrzZHh n6z.&̐#v5$8Vf"1 8qgJqzl7W՚<2%%r]ԪFkq'G]ͅX}cpnsB /v?:ûYҟ th?085o8Zw&clEeai%vڦ ~㢘YMxRؠzԶ7@s3CA<:)x2'X6 ,W{X\ļHEI"FX6'L={QDgY) ӮrcOLxߗpkݧ gZ$dTN1*N≪:ʇ l1Oswi%hʠ#+ʩB5NѣrF1`6i䙲%d/"F (s|U]UCr:w`ϴV1vlTա S 5Mt.fOQZֹEZgɽZ_5(k81΃W-4k?vGyh^u' xtWOžP &c1* 9!ɟgA٧F>Z8fڪI"wTsu-KT~:^QWCW!h[5˰O]gR#9uͥdLŊJc+g)&#$ ]NCYrV?`+-i]ph7kpkƍQ܈ htZ#"IYD|c$6SS~{l0A6hgǎ[ץw2@iPv#9Vq+g7DЋ+7dqz7}GY`}ҵzQυ-ѺQY*ȹMe,i> #KK a4_-&^2I!= s/0kd@%\<.ylfvmɱ&qYrfJbPl' u܄>mPb'f4ڥJ;,` `((fyv4 .̚A%{[یJyӸiM&h $mc5-U!s" z=pxrU텱#EAv/:$=cӶ?C&ArBt4{\.ڜRa.kŹ֡z;?}dV.E\*6&eߴu7r*Ͳض-ԎHaS}Iq 3rlѧL:۪wߕ_(',>(^ Js+4Rbm39 N)ley" _˞˪rý+ r𽪩S &^6Q~{nDIEl}{v ?'jba4}3SH ;F4bQmeلT"DWJ* ^ſ²zZ E8[~NpCNпP o߹ݕþk7Dߪʌ]DXŰo>1p~eUJ$_Hj/?oj|׿Tp+u&+cB9X9Ց>O<ɽ'Q+FW8h*ZΟ:eh{Ex`Sp; =lVtXzi-[pنFLB[}. %4T-yYU~L o;H5y!1*Ok8OUГ2)&@tk7:,g < oAAA , Nn.Oꆗ#q-3%`jY1q&ӳYx0ƛC." X'M_z"_0%>ӽoH/mZsK@eO]8KM}>yq$m5Y ͔.rI`szM4|  d9\p=L8\*YTHj@(4_;B .^:4 &*ҋ;$PI@~S?~9pֽ@zڞoue}!*lkf1܆>TU*MAasWY=YsRaõRX{=m2J݁* * 4cyj70 +pD ." zh7? CΘ֊͍v所!#~c ilo|Xֵ,@SXY$c:o?چnIu܆uo0.ZG࿺iX\;=/7:՚ޏcw5CrJI8з)"s`?qwhؑeeif 6Ow|ݘTYVսa~y)7ii׳ĭ$>1)vjq%.pgTBж$.] u^Cr.`eeM'%Mӎ%1ݺAN?pZ& &O]&7̚ҦeH.{eJZڍOϰ^B76i[Ef|aj8ֶlȑ`|Xi `m/,|5_͐Ol0#yrBF/GaE<jsķ8M$Gf%đ݆}=T|;fuyHAeaLKfbxW]T YV 0 0s8欐m偷 `ͽ >AŊh$w5< A"Z C\^j񺔚۪w(~.a*zAa LcuġEyz:w|.y?".ۅC0HP:݌y{98ƹ ozf Ij٩EbmX JՐCص"NL?A4S > i-H\o^Ia?@b9 1SQOLA |jDJOA2[@m)dfK3<Mʄ~I.1{T:Edn_[_3TprrL>oی:Ebh Pt|kY$#FK q7o{B2S[p~s5MUVzNfs|f3uEa 3I"-][ B8Z'8Mΐo\&sFQ d, pG._~ \O ӋWi7R() `v`Ubz  -IFo;p3#lj1~zKŒ$`qJts nnb\+;Ǩ0s2/5?~1 |g#̥uiJAkr+RMwL*PI_EðϵdG Zc5xy  hyӜ^9UbLVx ,n۸o *K+ o~/kbTFSVO^TDiޚ$ ЖoH_ apU"|z7? NT>@#-{&ܤ_Qo{/JuYɋcQ6Xrp{:vxc\'\%䶳.#jyɉ&72\])YyvL8=y@scbJCH7L֐۝{gQ%7٦XDŌ&#D4cdǠyŕFcb1R4U`h첦2{xB!fLEqlFK1?ďQjj8E3}z3Spḱy-;R .:5e7%/jwK+H-9Ʉ<à?H®v|˧i n% 7?[Tt0 څlX0& ۷r!{̸v]C-? |(R/|d"޵Dd!ًG񛌴\]p>]iI23nO<"U˜[.gHRRu%@wwa6\16q@",ZK H.KBa pu~,cG?Q!̽[hn>\)EHBY A_sR0fBGpjRS k.iyq_yڄqe+>EU2w`: W.]^qG8:m_6INCP!B"0 &=~X,m휛b em(WtMH$b__j53<8 8ggV95ƎnkK!/yYm^N| ]}Bu;Ab^eUO^@W=s%vɅI% >Do^N*hHk5,:c Q0+зBP,tg{mM.Sf40y'Kb`(~:y9oE!t0U/?D;'QyW=~;g<(GCR;'Yhqff=dl ?|b󨘾 $H0殬hJP+7,q}{( xNKwj\5>g^y7YLFFS>jⅾM{*gU<Ih:|h/0wFcfS >G%C2 [uYS~RXBY|(h8rڽs~APeo<}kI=fIMl܎xg[xjʎ!ޱMȹٓI~/6_ɏUۻ,"6 K)۔=\[LtѥuDif|lbpN*-?}{ˣ.ܶgSt)ͬ> lkGEO)?IWm9(?9N@l27>98SemZ:fSO"]i-YA,.Τᣃm+01XY{Ȓ5xa?72vgNșewQ7D@= !ā]J $(C(v#qGrop1]$o$>92s9")Ԕ mu$fĈxPh *[ݥEM)`civ>0Jw;OyBe\iM'3jLc7pr:VeI/%# P`8;ω߷,#f':\3""5`e'"J/$WYHr89ӫ j(IUA<_\^En6J%x7Hi9s`J3':~4kR4 0m*.4,IػA\RtSrS5zn1}A?2+V(#^e(ݶ?7b<:`Ytm6i|#]4e17OMᴀ_1Q_8u\$CL;xaAM\+v&k{>Ԛ=VLBcN:ʋ=2w<͸.g%{s]oSWDG򟾞::L&&' y,kL1!g?Ԇg/Oɩƿ s vV Z츆 BH^2>*(,ٚxҠA9վq8}&t؟o~ەa-*Z~$ʿD- @%ØS֏F1^s.Zu" mW$2Ȩ O`B~pLAXM2$,c hH<,(Ps< , 9grNiU[_NBǤ[r_og?OΖcsʑxg m?>+NH,S=in4tg=D[5$wGs}L/ƳF蚨چ:',h .yB& z~Q4(+ ~`?<=NK)!H+R|5 SrG;=/W.t5rj)j#~H9 "5@ÑR8W6ֵ[=l2 h֔P#UqR-v$h䪔D`|\TU q?J>p)L[LߡOš<_{IcR =#˦Q|.EF75hNjuSSRo 7R:7D3}&q dIpy!a'jgsY @O\_(Iou30ZCð̐ M!W\ ;b槮4}@{'1?RO (clft4RJ LLD%:{obݜF 9WivG&96o4R!&UDHZQ/xu#NOv'S]6 '<tO'I]!a/љ[,&m"Z8&Dtd落LzRVxntӔvQXP gK(.<C8^D=! ׸cR*n('ը"4 u't9lqcw}‹oJ:#IF0K1D}BgC6J,2l⚓^diεiTszCȬ 0'?t }u. ٷV@ʰ8~ RF_8KˎZnY3n5o4Χ\> sg%ET{|a/SB_HD"G~ʮAZ9}*/" L>*]&ņzzI`W?Шy.vλhZPZa<㍪sة 7a n*%:Eq=KtqsJr Q >+"g(LȜ!Y }|*bՓ.mM{\NDA%-V-me}Lq פ]W㱓{V& 'IO׹v-c2h ɀ oW +q FLzuL0ó) ٍ%"kAko,.gj\:C`zkB^4ot ȸ{I/r4Аz'ώ#IW\6 ^/.\qKXRa+Fmo)DQMhnL dn_~yAf$l#?fcxܒT>G'5KxnȖ'Dj- c@$h෹}NGM,5 P`S4 f3gXV<+N@w=Ƅܙ0:)1eyʼnj7pU@GhRB蝩C52za@zt4~ O/oSȵnvUs/keJ)#Г8ng< Rk㙼S1<֢AbQԓEWCKDQ͉7tQe"q6v#}gK̖p8</fd;h\H^ݣD v.Y| b/BkbCkc!L$=(UokC %)ILR:Uj Vo0k-dlc-Ec` p?eC&jY~C{ lc55dŬ!GV!Kn#5(eW!m|zJxH?k3:7ur݆ύ?sڣu~:hdf7詶,t=8F~[4wB|~n/Vɝe"CO˂SM{+=G ]"*EqW^)&6kq(@:?!tH@h6$p0aFiRj:U6Ɠ䡫ao."Kwϒ+&#$}*jЮmԛ%I}fnk̤.;oa`kpjT20m\q*[ { CKyְmjswhh8D_R2v@qㆥ=."#/)-I0J[LXk7M=|SU.$],M<&)SZs'BjzZ<[\DtlKƧxWdY[qזY?j,?C ZSi@<R٢0=s)\bJ'屦!Hx~׍ qqG25ot$'WDL! kRf޹sа,Nt 3'{o9^rB.Rik)": rY3H(rҼrX)JIJ&1s@ `g;29>0\/%?vKwsYSk#v[6r@ tw3ZS (_vtz5 5[W$GN:7,tvѴwɇMe<+ިV3$vRާ4ǃ5v L<ӭMA,?ab3=>#N"qu/*h#~ƦsM%Hn3κhݿYjFgs _""fmmxڠdo ]BH!I%AenUm%9>@١rrDUg$EC/@(`懼=_D-!)jfљoj ]CWKb[S D1BgE.v|qy]ӃqR,Wpw.qY}uP*01o5*)tO?tE~grhZPXG#tUExE O)U[h#f]q+$dE\]ۤe}k;u{ًlC0nvAcbM 8(& 3hʋфFuA̗3wT=G=ggcIncNHc<2OUzG+$ouw]MpӋmr;4¹qK5+@㪬9&\~} E([>M`@>JVBLXsjlMjBm rlvpAmA԰n7eq׿-=L&$}?YU>GMP;]z|LuO6 5tzj& `szeiC(GG>`pFy4r畳ssPJ*4pƐ7a4c_aP@`,Jk?`To;+k ]eٔ^Qh33X.Ҏٚ<'P`[\MṫrzSxa2roFcg?jzSdgr$|G9dΘc^ 3:R؍+fh@sSq2Sb׾dꪇ6J#z> ON-0ű&. ( J7CDTw35δa:$3m:1=InUL:.[&a#}BJ ]P>I:JL/ho7z qIMƨu.CK~y; /.0ܓX ajtcS |Kgn:43Pve 'To4r;V<9Ntɺը%YATȣƵ}~:R,.U`%("ڋ6g&crZ;gF:Ǥ`~&}g'V';]K S#sb,&U&@XaKF዁t#1+n1֗ÇXjyЩœ|qITOOހTccZ7+)ts'Qr "&\.49E(>Ts=~*Sq4s &A':u\h\ g7>&ީelDse1pq2FwOJI<,ܭb+Ht!`y !QkE周=&ϟ5-N;A+18v Q4o6ƟS+P:y@l;0&{L Wk֢:cmdFT4O˫dPb۹!I(|4&oY4(FO_)}v򇹓 P}1 @AK"5+]ŦX\ܭD<ijO޳7LZj^~%,+ pTn?yOv ,gpZ25/:Id#_RZ{w/[7^ . z J˞f< f P}e3Ԉ̓ (sPK9 omMAşbrrn0.&dO\ gj͖:QŪaZD妞Em{2`.-$Xޮ@B$3>7UP)pP&%|-h*\۸3Byg}G)^'p0z/RpTBMIx]7!UuÒ؇.bGΞŝjlL8+;Q 3~%[>G.E6Ro_4'AaR~k<$0jatRXdzH|p~ -<%童{ t`M$ X>`#XT >}.~OP]:O ^"ME=fsƹ[GȞX vǛ  m2f=VW=O V=3w>}w FOJ ʲ-Tѡ[8BA1޳:{ nDzxcZ=w6/m^BpgGѳz6"`Yeb}8)N d`!DOrYm:M\HWK6ev}V+O4 o@E{_[uЋ@+eK.ru_&XIܯӢ6%]%Ge&Nv6xcrqȃ7%B/' 8m4) !R\\W\§Cd f o}8&f'Թ[JZ+$KZa.ʉ4ٕ;:yE`8R3ΚP?CP{yLNbfx0t'%jaR n&>L/ =?n3;f.,ruRb.^ u+@߬jk/;#T>N:&7HoN4lwP5-n &(&SʫD+02NeB 6fbM(Iq >бjldD]ņ}Qʲ:G"x ``Pʹu(W{P( qh]i߄0sk,( |0#ODL6VU\~?E6THI[bH21 w2 xp[k"?QVbu 锂5In;DZ<#9רfjd4X ./DJ(sjx#?uؠY urGm;xgKCp5"d$y K-m @jB*2IjH⬷|x oΎW2ZaCVyh 8Ae(I>$~о$PZz> R :Nj.S-ߧ\}7. E7?6+Ô*UGꕨl.e|ptl$pM{URtWgkbrxQnVi;AN.U(kD~*WN*"~/-a^֓KboX+k"csIxM=;G_z9_[=biu{CyA'r@"[UGp%ž8@/VFwOcrgG0NAT!\*؁0޿z6 9"h@=e3L-bGH&vs8zҤ ·x1ShQ2^㥯L|\vS}O1aխ2@| <+HfDő<&p(oW=cۨ/lҌu&"Wj{pċ!a8qtX"= F3^21$ZPdE|sl}pNG 5ύpY^JkoSiLEN{2]Q v\G( [U3Lx5`(|rs[V7_/ ;0J [#lKN oVGZE(ZEL-6Ӧy:}]tAYK,~S#G+Cߵ6(թN7ԣ\TbB 톌}\~.u4kQSZVimet[IiI!^v$NpCíHwCdn#uc5|4Z81iPEwpр&Mښ4la'(kZlӠoPbdT&;'!n'UI7bZ{II @g|%C(qZrk8,8ؒg_ȸv_3eacS4bϾ C :r7Pb|=HZdwD5ͳ'G6u8W߭l}~,Y׋3y GKQy.({Ʀu2J.NW۫}8!uZRf%ύQ?r홭ONšV+c8'5!!xFᬽքVPn?o*=;:qI# ü:i5DcǦa[-'E~YgDRKC#)t:;*寏,Ґ- ڸi6$-Ŀ*:L^`*.݂Y  ǁP7qLuʮ S{Gލ݀Wpsal}4wDU!ndn>ZfDŽL%3M"o!?q0M'&)B'B!jiM’Mrӈ/{"'0ˍ5(Hq %’Ӻ1'1<]!w I3-̳+C!Z5ϣŐc* P*j% ʴ<V6?}VRX6j[gԂpߚFm T;3uC'4UW>l_9G|ڈg";r9 rrظr4w%tmKzu,CTJhOw7t?:f1bdNBDzٟa v<Y7&`9q\J `3 3 "As̉0-l;Nm .&L P%=c_Ҥrp>L/ Qr'!-Z1e'#kuAt߇bb7ڙh:G&g2 ˻rUnj?r? 仴gYdQDa: JhiZ˳dLdjTFyB)E3~O ֢Oj"Lg\L]L[rUjjK!-eKEƽl\tTi計E jӱ靟G]X-e-f9dǐ4фVsO$2 ݄Ļ I[.@W)CT5qCtP3v ͹%O~η5+GGb<珁eZq[ڽ HxX4a F!yFD(9RFȆψ k ^hl_ \Y%mD!6-Ư?Hһo5h&"iW}G41B@6^)G'o#d5w>k29[a&he{ ČlEoZ02W۾T˧9!\Ls!;wTC)0LIZ25?_v}/YkR-$+Ae2IWK1(Ci̱܍.#s0Qq?@/}pz/ ~o\L `GLY 79RIh&sF?Yp[@J&W6n Xj"z9 #˺Ob|EXXg }uH,Xsm=/b s1k}*XovԼ2 1q8@;;<+5>J:7ǖSChI%+qٿ|3hv gD;+ IJT&3(K5=MVsR6uز s;nש=-kҽlrvgq 4Ja?w4g( }Uk^{^4#~7N\\B@6x0G-L;%{ ,`3D²vS˔o}LjdʧcOoՒNȖom̪ 0a*0~ɩ<$uX Tڒ-IQ;Orj*jqpVA$4,LH _S CIqSxHĶj @p 2eQ'CmkJN]^ԓrĕ ъ=hUX96bv.|ΦaӋщ:) 1AzrrnQ K gE:Fk2Q%C@ 2_ :vuqe_ˮM2谗o=[},\gvFK ,ԯ~"2Pl6\3VsnRr)g/[ S^ߙZ2 3&&hٲET^kPIw >I`}wLl׉zDi (Htp8ҭ/Jepy>a~F$;˨((:ka TG-s 8m׍p,|*yxYuXvxqmYgS͜&lf܏tz\ЧKoV?yR΀gP8B1ʸ|A=mm$V8"غ6lsZ#ĩr ^&jKT}f"Rr!讹y]d|o| NT!iQkH% nFFq(Ra mh{Z¿?AWugznYpVRQ[ G9!,[hH'О`eܶ%7ձ $AwWQi$CՊ4~3=~UV++mHd~fmaӖjc{/#$լ)D,iL_z=glvx$.!l|oNoy iM1$4Cw#ÅiyGCj:5⒁)[ߚRD7 STowftJqRB!D 3 df[Ⱦ]9da-tg h)@_u%':B0[iCc8$"LGAk27eJKhQ@QM 7<vO`=6P H}rpaziflj4ڿpjs$}YvnocfA% ~4<`4 Lű~?N3|֞?D a2d C6C[߲zv4T},p}yyAVr)ݿlba1;ptglY3ujs9U )4- ~}vq4V:  K<;h}ECEDɒ+e`{` 6iF#oѠ":y Ru~q"O$XTߚ6N++tXoOūd$G4!9GS"-pmYqDJyh23ۡl?KR v_*49z-!ߔͨ^Df{ogy7X⼦McODб#(CNiuv&lQE6  e'""O-+uEmQt@wBo0)#2R˘X}t]fwUVEDžR}8*rΟ,5B-hcm:UtEG:|)R[R> x40#c؞eBG:a S5v]1 z[e[#Aѿ)?)-o|ЇʼTl5("wFaI9Bl24?|掅oG-)l1 ^茖7p诡^4MT B~mC]|njgD˹\w Zwk/ǀ@ǭ7>WC]/e@<8wgETebk-%JK13Ѿts3&Ƴdu%MorSeӂVAOHMw&Oe+;qX.H2˛{Ϊ{_pJpobƇ7B2f:d7d:.Sx>o8̠{UiE7C9<NuB:_S0G x$ (ǠmHs}+h@CYAM\Ln" @~)˔5}lMZ2ą&#U[Y cx$U ՙ ^tRo T);15կFs'^tx9xʓq۹|XļlW$gGzr,_}6=A oEӞդ,f6\ ;M: C, S%p$@Lj P~.Z Xj s -j6Cu%|Oq#֖~$΍܎P/]CN7t˪[%5LtS U=JP?ɲ2WCԕw j)tλղB*O`1X`Iq@)Mp}8t-?y`ɔ&ޡFw7f;7#70u#9R21^?x]gECI;-T-,mY>! Q Rv4WR ؾ|y$i5ݰ }&i\%26sLem3 8Ħm4zNil킬|JؽZw,L *M?p#T\bϙ #سosZzղ wT/巆|[Nl o)SBkN~O[o%ƖkѵQB ٙr|_&*ʉ@Ao75P~񪭄|:U*h6u``puz Iuaw>VToA)m~f7WZ'E#4)q 6@%l`Zbāc#.Y@G bjwri_,}"H139cү`Zk6zW3WCEdIsSg>;o t`B]v1< XﲁUkaҡ[-pYysU?ft큘[?W8)MSRQT瘮9[+O')]x`yD~`J%1̤`)llFfuDRp1% Ō[9,L"3S i`b(*\48864iƠ||,_[R(]7\P@i!h,̎U%x}?H Ϟf+[^q4P" |UW|A4:6ۋoH?dF"L8/ߊ, T <ej[?@BvX޿+ 2 QT|2!S1oEFiƨ&*ٟ&':O9 u|.ˬ age]ơ&ڼs \v!%o4g`쇶ޜ +m1"dx-)p%=w|k@_ 0sY$%@0{;Au$u ~Ǩ{݀e`Q+-}h@L>0 R,@g%3;r qf "o󼯪y̟1-zY~ԶcTAsz@9 )0םwhD:-md;VPGY(Oʣga yN&#SL\S;$ai2^yIe ﳔlZyV:U>'}HgţDSmukv9.u|h5W7=1u/ɞfʸ&ՠ'5zs~ bOm@8f# [#Q/_x۬^3 ,SFm%;IJefJ?LRm_ 7~$bSI$u{m8](eTVD4cV^q16ΫV~ư>f-W$ v bVľ;}ՍSŬQ!AȊIo|77Asy^#;U L+$;>}&u@uy6'pL~2 .~w[u)U*վk+D;BB68b*męf,2]ovl?U{&u;3&IAƍ=NFɭ2:uU&b70v;wo[!5z9^~Ex */a' z~th k9hT7`e.\ !Q8ԏȕ/?=I3kt5񋲿nʌtquI`7uLZ:v4^w\vrU%L7vEϹɆ0zN0qSߓ@@׈fxj%F0Cu'yhKX7<4C9哉CVˈUM`Z/ԇƁjN>Oӏ~HTŧz8J$t}W?-b3';'da1zZ( F$u{'PNqZ&3/jVG%qGmE J|. 3oH̊¢V64dvs{7PB4kP4K`Xwh)xe'srrg%i18e*iںOpm4sG@|ZtJSuVENEJGgPW8æ86zUb3~FQkBHQ!rs m|)<6o[ /~TA1Ag&q`F!O:kP<ʁR) ~Wu"Z!.#H2YdD >&BMsnddgxs`Ӻ$F#'>a^5M*:zdN4X\09~U[Y^c]*@Ԥ" k.U pjDTQd}tAr\M$mI\a{Rt[ÈDzܩpvkWxsе*;wp"Bu*cb1u.FK w/KIoH[YugI<;S|hF0& M^t&aPs2 zǺǍFA@_TF{< W ./MB/!T) +޴xj]P|9a$e&۠iҕX ++$yG.T oBeRQ\ݷNAL$YRcYS)yp ?Y["UM"[X3|HtIژlֶ<5 aCf|K73#6-OAQ4ХXUޅZGׇL9@yqZ>Z΂-qۂB79yx!bt1.TBib@b'[S9O[ =,ktS{Z>'NB(߶/~?Z/:z n+9U+F Җdc-FٮBpJe1F(4E; QJW%w'UC!.k DRow@LF]ya9ĒvD,,NzWč!i+?6xciЦU0ra(/F?Qxvrҩ2u'vJg @qජJ8М%kri"o?zgӌ(\:Q^1wxTmqD DvDK?)sًH~/4Y[+9fS}^.[tY9WPxNjߦ8q*d0kPp"J@<@HZOnQC}ӉHk!(=dppX2DW6Am+d-# jMUb^د^PoX2ߛ~~-i,'zfi@r>zF$Y1lV=MCͩVH$  .W{fM耟Cr4_c\RU91Uu6.3x3RWOvqRQgWsSyids~ @|.c⩴JEr mAsN% 8.y u~%'" 4nE;d*! 4MJ٨[s\1PIrHQlihw-NR2(hC>?\-aZu 2:m1AACp3*ͲZ>QKpFpc6~7an6%;z6 -g>5P^/E ;dOPT)1̥ 8/Yw[)dUZZꎬnTGhy1DW{Fߋ'8W|32`39>8r ŏD'z.Ԙe1[F.'vDCWBfϣ!j!F? ~|&dR.(Ҡ*"D,pΐʡI:xf`k]Gٞt\Gl$^O:rs2[5}uJ3 (9GDZ2HD#])*hMxMi 9%Dw&XR4}덉WT@*/+lm)z3 ^؏J/Ak_.w|b\ 9 ,=8SRKK.Ţ[8& *ױ:ޠ% !G 2woȔٸ>ل2ֶL 9v*FTɾk܊F_۞c^ey.25g ;G; pi'KMF1"Fۥ(hBI4PE% KJa,{~7ݚi DNx ˃M%mODt-#_B7T7E0@ci++d= ˴yEtV@6"Z*>vM ["2$ֱEߴ}Xp1݆T.:9ȡ[lo63@M l߹t@Т'T+u(7צO+pAƲ0)y'3޶Pi,Rʿ Tk4ǽӔ`%<']<1O'yh,ȍ&!q4CN oŖ \h7^;kbv.@Uɦ\8'/ŜH3^\\4T w:o8<la݄#bLm-VfN7KrODv.b :b'gI= 4y0*(XHҰ/ jO?(twhN_ qyh2uH풛s {%~ʨ$}fLy;WcPWiQّSu]74^%KAr5{%-Ft(# Y0}jA*(s<҂7SCoF>@"a>zVD8ğA[:16:ky"TX*{a@ɱ݄F &apd>՝տPS!>u7bNDhi(yt>l.+qeiR ѸfW:4dN2H! il_s"./ƴQhF|g#<"[r(25-ip#+iMa3D .3RbQ"/-+*YΣyїv&U_>!)T/sB$/2/#y  t/@S{CH [p]f7I_JK`mE>+S@[/RhC*Irpe2 >yՕ؛L@PsL2UbTlZXcP:tw~7W(7&g&[ݢՉUBkQZ aP<(9k inJ=ɜjw$s]V>^ty))^ua.vݩ$o5:xKaڊa5<,ח$/QY$fMM_E1&>EQէ#AE9h_8+fty. zR̊wo\~2l$kưSjetAHDN>\ -U3KT׆IJU/dT[xɘle &nib!^yp 9nv5oڒKK8CÁPD\Y:@c;kvXm֞ : /$LxJ4V>əL 8UZlz" C s|Lx6k{}t$6J |(rtvP.HQg$ Yv~"aϭ:?NVZj^^Y~R-~{Zq8lh~WH1Kѽ6IDB@ H53ߖ د>n0vhZ ]H _5gNom`%GXT{Z* AC*nz޷@L> QdTĤ8xL!jJ2hTy`pl{j{oȵ/r|!@Vxt"kq!1ăZ5]O p,ZCsijRË8A }:cJO~K9vvPgݝ WD40Y_2]c3_s/ m_8PɥlF`5x#^yY7ʐSg/)SXhR_x#iGoK; UмU 6/kfKPl6v5A[=̀Eޠm}}t8\,kD*[;3tp0eV3 du]Bye,I0%ʜD^']e[}&'6 ;[;8*nJ2!ll % x v)O# A μf;:J&NZ4 iӔHfd~/DD\m$% fOjI?hVįrINeS:hi<Ԛ@[!>"#pr$3zNJTpΎW7ˇȞpuźq>7;iAz}֣_PbNsvnN;> 8qL̉4|qS8<+y5P油4l0Yq!{JVT<@QWhuGR^ td+&bgɷ9a ѝNvA W%V\5ڠ"2(Ѭ<nUQEؘwAڊq0h<2Q"0䱅J˪ʭ gH#@}Xy"K$& b+lcP^w( xE# UNLon`gZR63:e79pP T00bW% ,C9a~Z!t>x4n{4NǦ2Uw  0h>t EwjE[6[.bI;`lهU5?'J "pac%K$ ?ۉ7Sm G2 pv\0y4g?vb/H>nLX<%(I|_څjHU5q:}|1rG |2/z4PVzkgLhHrD5^ m}g.A#wڌq^-Ɇ@V]3fwT,nQߏJ&CXv /䴹Qͼ%ct[ wſ苏G"!-a^8C j8+*jB5 <(XXՎq\62w֪X1˖ ]/=S趗upOm*{j䩅LyF5, =% M?O%l/J/zjm(Y?ek'Jcp:䤚lG1Ҳi|ZI&Fˀ[\ 67 n}CB FA{aF><"t M3X@SrR7efW[t 4Q80j:PI{1WDDv&vEHNHæI/Zڞ:d3֖57c]cQOөPD-eT;/Ya}W4UОZ])ąƨ XUٷ@3љ') pxΏ![ϟ-P|.4\Uu 3RVW4HIgCky(ϿC"㘜,ה T@RX7 \trsmm\lP}Z=AB36,H/ң2߻Tgn'YykT[G4Q $B\Jq6g )_TZıE .#pI;~%,CM7=i䕏BhS6>+ζ0x_ 8{>O5g(zB\n(6t@`ITdɍo{0 F7B0$>üpWDѣ @} T3#=*ɣ5Y,#FodDl Nē-&ԡF^֘O kEYчo0T9gp[0o7U䜔_}+%+]~&rXWy`${ )b,ފR*i ڍΑ(`BMA~iy<:"{wݛj`15="lͦ18.b1ehI ^*Q>/cqed29U̖ADGąc:-t"gt={,#` y `Xeɲz˴ljJx KUox5ҮQd}=BFN",WdTK.muޮ^ӓ#YT#iHɣ+u` 8A6JԺr "OR 6Tm{ YP5ԡlֳv7~rZm^3Hb᧡/#R4Ty&o&NQ|Ir:t!0=zt ("ڈ*`XH^JF)GvX9P(7i0D7\sBZotG87]~c3j8PnQ> yJO3.s$b̵5rKۮ♜uRD\sNVݑUcw7}N:8؏o%"jr/Iѹf --md4.__,zэ/BxeVHH{5.ݖuT=1Tf~?&7UǦ0 T t1Q d1T2itZ0><[{-"B[ mٽ\:TYVl& .RО7U6,K+ =g3 @IS6>}㬂:r73qjwPTuz4ʛS[0A&9`vDUvJs0['_4~4=b,"LӦg5ɥƩ̴ëT]UՙtnnM‡ү%;ؑ@!aЄuT(Y_Zpvd\ÿŹ%+H܁9@@W Ңt}`8; KN?6S[vF߀-k1mpg+5'2 _&7˭ϳ%1-A4CŸbY 乆ûïy=bgDzmϏ*F,?$_QcǝAAUYvf!kTӭLWkETUߞRyAY&+)w"i$/)wں3NCR'jٟC-T:E[9Sn}OjH 8{y=,h؇q(m\_cW-Ks:>Z'.nw̰td$ST U}br]x&K2e> 觝'RaK( W$NcWG.ylM鐛$v2aFjrfǞk5uO ۲hkzb;r[κPT9{6S&GtE1eMجl\z{O ] ̹l۝{r('7;i ˛XС}5Z9o@:J\̮, ۭ<g<+QXLEK }u+!Bf5H0#jX)䷱D®14ݠvP/jLwr#E,rclߟ$kƂ=yNXbfAKftsãFh)#D_"2\uSp9SՁVYܜάw-* k927 y9i;<_jڢ5d4P7 (A #Ç ((d2*ƀw^]O^71M.4Γڄ"ż95@}ޠҀ0xm߬;&qHl_>qG!;(|Mr` $XMʺ<x ,WSW/u6؄"XQB7zqL\qfٻI o}!3N}h(vAJ9c qkZ̘B*r =SWk )=:Z߱XT:<`ygh߁7e GxK ^}JkAa`2`י͏Bϱ!.8Tc9mERXB/1D5uC RL#7(7nq$ X(!םCl{~9B 0Do9RRL zY_\E$Z҄mjdQx]6L>4(8=ݞV%'MB&mGLw36fc)YHA-}m:GN  ,)7S!\U_{abzJQCq.+U[l0 kSwBkd[m1 DyI(갌(sKG f8*za`مNd?rM{\VJ$ %E* 4CF8P?/P_jMVVd K=T@LtrYl5%eZ\PcP

zc܈A7oEA]r vFWک+QeXC18N@+j#n;8oQ5q((Qe褮,5;Y2N Ʋh!eBe*j|:K=HABAܔ|h:FC?ksNpeδx' 1vQ@ZFٳ`Kt!" D*cj >i`:Rr`DgMj0JMSqR pJdM<^E/#Y)-tߌ5l>ngW(#?ڣ0yA^4}qd*t=r"#R%R4Gs[.8g]=8Ar)\CpSΞZ\el`9xJ *)^;F!>0jgV[hgJ"nXa?E lNIͿYث̬C.qۀmtti>%9=ѫj/ qr\iPջyR k&i1و61&w ca\& wIs!geܵ[.?l4EZ:hJu֣0vfLScfP޲Z EvԵ}¼cjQlf NV}aG[}YÖu6aPQj;yԸriHzWܮ2JMLbSUSJ> %5O̳ܡ~7a턄A-X~El7`d?~>*m׀d]x˩8f.0:vNl$qPaC8wރ]D}ۻ\ZR+(gcfEԛBԗ򢌌̝~F[d]q׋B&>mf#L}C?o #AZiOm({J3h};B3+9hU٥Q![ȥ iIor]f2Mrd] BShw^^$r!|Q,t)~ѭ.AyzG {Rs_p2䶧san͗O/jUnfv^Ia?<M.vxO,v$ zY[OH'FtYv%A\ҋ| "ʕ8~ ,ȕc`U)cաŤzFpEi]d2VX'ACQQAu-"sW 9* HM]Hs$GB #|w/))4w{H!]c~O1hOs }[jH/"DLkA/'j{`k_J2\"5ȷ}SxϴR~׍~k:Ma"-N-GAmNit W|FgU ɂ@I?Rs{ z~Y'X|*G椽eWRPٰfVtCJ,dWdH_;uf#;rȀ@GB2*t-)A `w^%vfoH񯽚aIXPFY/PAqyQċTdIZK9ņIㆿK-̭э 4f0laRS{7-Oߦ ƍ#ʌrYJ0K-u]M%;0R(j QH3bre I!µPa6 LS淧W}Tظp.%jK.j],?]zqYda >.?mL.f/05iA\>r7rX[~A>{WsWANtW[g1B Td*YЛ sůʮ^ĻnrLҾ~+?|ֈZ ,<]ᥳ QJQuKk*z`\V 45MHVQFulPwd)՘;F$%y5MKG{W[A~Dz,dt~s(>_.wՎdFڡ ?[*Z詠ٝ)ySeX6@|c-Z!wVi3ob/p՘P/ ߿O9Rxcy4'.h,j3bwecdAMj |J֑;vHO^0Ю+GX5+HH76 X1]Rt\@'ѶV|{i">%{\edc="9P]xS|lHe3Sq/ ]ck1Nxh>fDiYKq`G*+H V0KJ^]cZ*B}yZP" ݰPsCS:?Wi<hX:UXX.XH{zi`AfQCLeOeOII4D6i%E&A(YjUpD?wO2o̳zѓJ7L7>͚(Hh_ #\UVў | uO'Ǵ(vVzKe-^s\ r*hMES `9^HGRaY*ov"6Mydt@I,Ƿ<%VrtOUxG%u_EzDP{"N7¸L]_Hم8 amfHp&!rH <e?83hs5x/縛֌2twwS bGmD T28Ђz=n^tXQP5TZ^ Ӽ_R蠂$vy!;j2zeO*E_D).*`r s s\$ ڎW^JeH3WmfeHO|Tx$ ]M4w>G6Zũ vz}<'zv+ZuSTԶ.Yf$Z}O](3$BxDt "|"AB;x- Vs1뉞k1p5Dt+ش;vT<-ˢvR#T =bJRnԫhVyԺ$a~u&U>@~kst"Dʕ%>p~`ґDGn4 B\^{L LI͉<S e|M*b~ SIЖC(XCbe E}䖨 =X¥JNV7:K^S>Ϙ`tT!tif"Z#OXTxlUPB)ܬ'#r-{k"䙳wesv 2MOƦ>DwLk&;!"93BSe&cNĔGec'(~`"knLg`|Oh9Pk[BJf+% k @v˪[\ZEYYʖ1ZQ՚0 %v84fM q@t:Sۊ{6݈v$u=93ȝn)Io8 -!{v<#6ޏ HlY"c4ނR@t Bw۪67>wݏϓ^4>gFr]$ʙ@c ϸA:M8;+^pLB F {[8F%zt<_>S:z/5\*.@F]LڌhF6G?WXpDjwB--c6h 7>I|b~F`x$Ez`_F)gs 8Yu1ٞz\t2r"v_`D6AԻ7 S\ %!;zxΏKZ|mԽصW F`jn 7i'5}F6J[ak/`;h ]e/ѱɉ:wҪDZ+pMyzi|F'[D w]%!pb d:$q3zb+{%>}o:XA CSGqf-},*q/qv{;SnW (K#>k 2_lh ̀5:};ɝiGuҔ6C ;`IQ$JkC3f4%[|;)lH?skъќ-&_C8-&Xq#w 3m}VaoN}D𒵺2Tf>6G$PF=[3- M1\]M*r5mx(Ժ˵VEYJ 4EcG?׵KwP+RQZɸr5=-T+ -ƥāݓt5e6Oޛ$jk!Ԕ'qIֳfӺW ѿ#[#/ca@YivF2lDTtok= ,e[k< #- t&T^xEP8NyN4q1QnT:,IЭb$-l IR\aQތY9aw;pZHcH+ep%SS* uȪ~AG5IޝCQDǒK3 ܫIo=uE ƵSk)Oq&,n8984r$GdR%@ Ҹ"&,E(S[AB#i6%]\M1Ȍ(V&#Xcځac8뜝^薦O%"+!t Xq6])QڵyM-MLq{l"C إeyZ0Y6@@l*5y3 A9k.`)y>Dž 0,jUNy]4AԁSi |/z!r@IȁwE~yy݄us f ^n+~2Ir>zMLXcxM'?r%`O/h|0^<^VgȾ jA.P!Nȝe<؊1v''8^uԀZh֬,M8zY;MvLh/˜#s{T^%"%ҝ_lkc6e=  n}DUavڜfq$X,,(c%)&`^L 1Z-ٙ}w\m 窓 n ΆxR,v+Md<9q.̃fo[a%?ܾQƶ{޷IL;:$Lic~S^dts!lx*r%Z@SD'P@!в[:fb  57c |pE3/n+>CM252AC&㯸߇umtrBfkUTR1ᵲ!mz pKwI# N&‡IWcF{Sfs UK!$52za`ii#Eύ^־`6i6ye", ҔwhW|z*!$c+}33DY]jyz5 m YZʣג7Pɞv'n-/k*e==J9*bIH30և_.D묣m$̞5ƊN;xz jiOS9hC6玩Һ ѿ{ \М#ng^íPӬJ8fmqDk;\,5{%Ҏ6HR+Ty4+ Jڿ ԋed8D#!/-cF}.v3Ԫѣ (ewkZ8)w*} HV+^b mY[qᯕNCN>̾FiRrzQIv^b d屢S[114@ (ps"QZMax^~Q*g?E+Piy u{~Oi_rHGаCջ V'3/$l"]Ĩ#Xu g޶M}k7i/WUcBv CeXle-𖤍/(FuQPX~h}t&jTBK_D 7.Ke!n[HaW8VCť]GiVe'n[nUD%È%ɂJr[yRdreޝMpI(S6>ѺG8Z}pQx#V]COɰ཰c."~G59 _5!MÅ;y6 lwt cia@Ny3Wd:2W(FPx 0XC{:$PbvǛ:f6.!J:IRT}wq ݈t="Ԭ~6ԅ?˛H9;o8g(yGIH^b7jxngZ#o ObXdݗD9Is^gQ ,]`TpSK9G~o`w0dq> 9p S"8'}Z{dU)wNj"maGE,K21ֺ Ft[ժkZ)Zm6ƨ=%gˊ+D-06({ZtJ ILcx:SHS,t~œ L7|z$9v6n=W"Q!ߑSUEdNb瞨Fټ9`f~xRm 軼kjq XgJ3H{Ee:5P)i4'&e?oWr,%w];?_Oy޾ \ζw9K95IŵgA=-`^_0?4mklgS861# oσ,ym7y TÿJO!jsuAD)ӂgL`2"U7X/mϰ=[ MTW:~Y?((Uh 'g' YkbxޙaP{NdWE6ͭhN7a^&ְ&G^`N)ͣ6:w7gY Tвtik;n0P;kd &.6P_ٕscIc\fP^4mXa3w 5:AOI䩣R<^ʭƈk,5ʐf` L '+Z(\ B]_7?+{ p82 G"dAXh\F:ɛ扁> [Ԯ1Y̝uw.wra/, Hm!tڪVQ. U3EKC ͭXpO2~m 'IqKoMݜhKFϻۭdoZo7<7nsOn+ḻu,X6=]V? o}M9^$Tu+~4h>oa:#:{Q+s6eJiILV}Gw$'f&iCc:!tQKr:LdoR7ADJݟ~6M!6c"+  Pwji[K&%[e?.US(V7w7.+ ].25WEOZJ&Hlb#c7.awTZu#*NWFH^Nb礋<}ˡ|0$\Il{Ґ?:۴>l:;=hń^XFiRҞ_ir++_r=570t)ޚ , z@};K&/TƩK4MC<<9F)6GOf Nb]@jje 1D8[~  j|""w% ԹνXŤ3*MnO gs- TR^ *~ T_}?% ˑ#Ns<k[%|*cKcr@(I/h?sɴzNuzf]C#d^-'po{a)w<+Җ\Lb޾ x wV#1 Hs/tw&e^™L@9Q^U0~FGgި;Onxz+gu7u%#/2,jYߛ 2!V=|ot h`e0ݰ5pDCA#x*6 ߄~Yiu~,O+Aau h)&e#OCD.CsONvVm P"09-8RUgi6؛ޓ=!Nc@BTpZ-&J+6tcLRQW~_z wV@-@{Z-~\nx'HёE♊  lu[k` 9`܈P5m"ڋM7w%M@w+bq[XhbFߩCBγCYyUj@$чgpC]%>~c]wլ]҉WؖGIjDV#sr3RfPЗq^^CH9mIMz%ݣFkHB,RTw冎[&C؁*_ #JA cji-HsyDDP M091!J){AQTSG-ZnlYkmS[R?w uWƜiQ݋4QLx9⻼jǞ^E^:paICS-}5o#ΒNGgXӆ\:l{}r`QA/!\EgԜ4rٵUYA$}/K~Ҋkq]"i=h&m Owllʂ-[Sp,GiP*v㘑*Ğ"_cmUTVf.Bp^ߘm@6"x׋+|Jv'60jp oK( fZueÊw1 }c:^[TQiRY븘/?UL [R8r HKB[A`OAB>A{ຳT4dsxk#10u7xEZ.T$01O%R`l3!qc3G;l"5|Ŝse-[rQ s:vaɮT,@I;WBȼ".l/W,o7U UVAZL"Pj&Veǚ)FP#WKYĬ]p;uuy>H68;Tya9 Vb 0ۏ7]*Re6%֓^M&ͯ7,_-{ӹ /Ԡ5(yg,%mPyMͪZӐB$gpd ~J0؄GlLD>y/e ufqiR%pO.L~pB* U2LdblIVF t= !l6eB'>hv5P-󢡃eӫ'E{RF4|z߼VbXb[|E 9p ^ab|M,C5x(( :A {3 H !, [:qEX VLk:˙gl=<_'y7:m6'߱ xR#xngTj&,a?D1\1|z1w>m?!ɀ%!\wͱ2vQV> ۫ j  S(OR>*n+`.H9u"$5`yj(6gXniI*GzbiiZ_G]_ dQ]tAG .@R9~x2e'hu 4ۧa˕AM֌kBì! #'=xe^uc7$~qbƁȅߛ"cKGԋCͭsBיH XH'/BA@f Oe0C94;d-.xиMya1oWP$0?vJQHCcjDCIbUFYK34ݭ,?MȉHr(MybseM#WvVXG݆|1E:qT>0VHW'duu|H؈'VL+ &砶%2CMo6=l_-,6%{uDa%FvR֮ܳƸ+ss؍ (;?g/ALr?gQ[$E9"f>} ̄0mw$B [`_Zk##(iBBČ7хp?Ul2|u:VpS[g;:G^9#Q_&)B+kϦ8 oT O)\1DskuEPQcIF$Z۾s!"u5(ݥ:ܓ9NJβr2<sڴ `z\lUhWWQzT]O]G0 dA<$ZA*:Pԙr|drr| Ge>w9[2Ǟ*.4'bҏ}رR٪eҗ2Auκŭt )Aw.M;2^O%(wZ H.( !@Y[^5vlBYot>;|k!tJ@cKNJ?*4sMa(zg)OuS0:^KxB1/(芈sK6f˥bUx1.:!fꔃ#QNC1†ڏMnOZ_/5RlEBjnyym; "³ #*(FY&{  c8k࢛Jzȑu:3"T[a Vv$ڻ܂,R%oE|U6bկSC$X[ؑc\JhR$lqAG5"@*TIS`B v)Q]zA끫wui5|+ZoOK<H/  G _DbBǦl!4H唪{}uJ:x_~>Lbx0H>JgY 8] Υ# {  :lwK { :=7hs~1(:dܝ?<ȸv[5j`${ew͡$ ٓy5h(z ]cN'"O8PVc*ף.P۱dAejnx׉ʢ1K+L'h}fZ獥?U[Wz[<S$o'mC*g3$l`»G%@ d3*BkrNdIcSJw❹#Gߥ+h)_0I*Ɉ8ԃ/IR&65)/9hV?UM)aLC 3U$jEc U`;{6lDBNki[Lyۥ:KbrRB )b#0ñC =X<^џes;ѯ uKB($N)DvZi/2qx9Fָ:' g9[XbJ(givh: 2"OC@Ђa A}i5E0bPqwTtRu&=ГC-A;ngzIһC~po.)GSvIA2{Q":a˝8|DqS d{^CS93rH\Zjo@ǴgJ8/B%u'kc~ۈ8m&d!?%-+:fh4 V>RĘl.#&SˎY(h:G=с, CN-x<1M+ kצW}rbO2__24-o2yg {v{$L!.~&kE衬iw[/Fw#(aSf>6 7L<ؗS l(iݏ.:%K L5R-T-(P?W|O~Jua}P~-uC¹1sX>m1DQTy Ū gKCR;GL'c۾zNV+ce#daVծuj@I1?NFr1ex>֚˅R~&(cWhYr\:؀Jj>@itUK 3-IMhJ`&q~VP{p.~ĬWxP!7¹)㹩ˊtrmʻ<tQT{:hc:!O 0n%Vֵ $3TRn;~~b-5+Tmr Ei?58Vf `(95tDd8!`ps] S0LʹI[\m͏|0!w$)Z$K]3ݖcCi n\C%4>2Jr.8u_iWu*Lm+g4pĮxfw+㪕,yFrnU5GiڛziZz*E(SG>~H|< ٪S:.I{?KgZ^M v=/0! Y ayETC͖R'dfp%Xݒd':VJulœWFpf=64Z|6x~ 7P~ ȕiowK*()WdICc:|Y_6n^Z)'KҜFF7bF\Uڀ)>G't@Rw܌&%ZXBM^=̠ g=zA;Y߮+u"Ÿ%gC Ff]a +OJ{]=Jl+-&r7$dPVaU/R6Mq"uva,? XKD HD\Ђs=km&pWx7+lJJ6bհ)Ho;;+lXW*f K]"~d蕧> NQuFֆ[qԧIv/҇,yp@u4S1WWB|#&Ts{GM1I~2 *+9x7לS qﴸ-Or^Ev1?q?n.C}ESד%c]:WI2@klJĺ9.+ZG!)=0?'7Ye_H+Q1Nj()/$gCC(sKKHSaФHpEPSCMew{ozqK A_|o8]rIO 6'JظV61OVL:{V,.lپH]hoLwj&4S姇OiJ:}!uw%A-['a gL;l.4#lZo qZ+Vqiz\\Tml`)oD 5<}Ա,V%F@>64$V:[Wmu 6aU|g:2_n2HH Q{*{7RʬN9U ~׀h6e-<.[XZq S^YBp,czqcsupxנOKrF2%4~ 8JBT ϱG"moiLuD[d-ijl.b}Kt;Eʄɔ"%>TU*LTѐaLP~\0|l+]07̑Yi' \zj1{/rۍBHw5U%Qo F̢Ш6wn M^1SOU^q[ˬLp1HW`#Dv^Zc5$|p+(YS|vgIRF{. $r$h4}ykK4ԇ36V3{#"V ?>F>c؟!#?uZ欺QM(Nl u,eDu^$+VL0 胉:YَL/颺waUG4iGrWѽ|A(im#ֳ:TD\%K?B"0 |({dQ#>I[wk6g$orى7pBS45{*f*XeFn^1z\@t,7=0$WimD'ğ5k/Jh!@D`\-es~[lYn^$YwʰyoSVrsL ~;'5ЪSY|29[,G'!2,[bKk'nX*p.$kk jzBD]LCY?l^W<@'[i-~~m4(Yf mt " V͍$] [s*ʋ{d OFS> H6]V6+YA/ {s:nJ+ ~I-_mgBf 5;x~SdQ+\=00V4PΦ,\J4M#ጇLwmxUK)ͤ'r-u>p74>{uLlo ]?GxǬO&+]>_oZy{wַ t4\@9:L9~NnsL lʝCNBp6μ\&)WxX3UX6 B$#a I|}]dR,:2]gPJr绵Xn~h }w${a֬AP)ukFe&k#X -"a\.PvsV&ݚ!Zf5A1w.^hz,(֥Ҩ3G22GT')8x!N, {qi@v@]/F`yM!Y9Aypީţq"]SlXwLp1ܻʖT9y rT#?Y(4[KDAZrL|c>Q3+98>U!  62^M)P2O'jG"X?ǀD~X%!‰1Ww˯/aof0۴3&1. ZĥxBcWLM(0 2g٩xs3N]_HvWC8[cr;m`o.PuC}iW&oy3} K~Jz赳)Y<&W[sқŸNrR1xJaSȫ7 )[T3%*Ukۣ!x;hYA=J / X}?j))$@&檩dVnG(EM3E[;- 'm+1'P\dj|V|$ZIZ1Ɖ欫GT*I }wQXA` VS98DOG2ĵ^\a?f|\._ycn4X WtIM߄4OxMu:V"!+hn&Hp]~YQo *׍fC? d*U #UMUyԏ f^+y  Tq% Z>/mW#Zf8v׽܍d(M 1^@i'6T/>vWU.P˺kN-Άk3$gR!vΔ,'qt gE˞Zek}jwpև>٩@1;}(ԅ̞# <`%S~wc k;:t?¦oE'4ddi6 ؘKQ:ORr {B^d eOjZ&֪ٷEnVc)]*W]VWyеr(!="#VM 3Ru1^4ǁ}o22 SĪ-E(K5}P5J^{͡t9&4㛬M "hLچ.) YMjKZ߻m c]SZ2?d9wfZ k r}D)|)21Vd c W\>gF|cpEFdfR4[$`܏$<(vtL((ח>/]+"WML| uH%.L#7& .hU74' ˴uL/ voLDgWTw*_y`=v:Q>Klz\K5ΘKX 6?js]H5#CA>: >pQpa*eL۬ Au6mN.*;7<)6Qp9$7tc 9y+cmY}u615Tlblh҃,M+M"<4t܀%25P[ B;_n'Tׄ/-?p!MkNdRYzb^h Q[}&,Q,X ;8SƫrQ18nŒ]r-0oj+/)XZii2ǝ=b `rez-x=D>b%mxY4jÚT Xڎ JnC?O,3.\ǛPhy?< bH ՂzԌz k&RWUV38ox66 .)7>][޳/l)6\VbHrhDlݓI }<ʮԇ&Kr23e0-:x%8';I[`٤Eo X~K{kry]SC.ߑOm¿jzBZD0q-l7L\dژ,X>AR.o ?b_'I>SԟԳW'8(h 31&A.` bF!+w^:s왬Qhh\V :LjԱ߂P7PͣsPt5GIVZKf#ZN{͏gg#^Qܨ@ĆJ{,c0l䵴oM4+gπNfA !x:E?qtJ}"'-IKQj/ I|o 5 G|vØc\z9 MǛC2Y[ q0hkŚ {C~w@{~{8nCÊ%NG@l("T-{$w y&^!U[&tFx7Dz{<}p(IS[E8vvia`$%ޖ4uNW&%zz*Lz#f,ϴ _=cЕ:(\f'JDY""o-3DfaٶB jv1 *S{pؓ>l>OqQQk(ɕ0_WyVdX,ÿh+- NjIOJ :~$yw]T>ET@cX*/O1ll ܸc/e=3%pN>jygo̎ӏGNkG-aZW-5 MW9֓]>6l?Lܕ"-N4t8|c#"I>߬+Y/ao_~MG wcW"wh vEIzmaM:kCAPD'zend]nC%ZEl q0P =\,5#Z97L,"#! `șt͉n۶ 1)R톺8,ZPl{BS~*Ʒ5Bho7޴ '3 b mm@s\[4/Hja3yY9>XʴK omQ"g Ez*Ms彌fsc x)Zʾ^ۼ%y>S^5:JĤ7j۲Z,>6TG 7>"]Gt@:BECIQQjydwwAl?8NnO6n̬͡#u窪}RSE;ցE2b#"{40+c?BQkrtYg2@ͣnX@ 8>$- *,!ӕ+'C[GCTD YpDm~(3fVn5Z.qx#X&p7ᅱZ~NKnjA<c5 6.>wd.DvX)Ԇ{^,0"16Hz2U>6_6 }"!3xrJK.* -_qLe(mi5KaTy痬?'eT$Q**ʼ?Fw3|qYs:]7|4%~(QE՚YA4h̸XyL m; ؁pSP(;${k?,|Siad(>O#|+o@zw`:}T}AzG8f;.!H* y<ZrȗuX&|B#^V/g h*zI9=H9͛U&&vED> ޻ #yq4ul;|tfhCFuMMt8?qkN@j_AlsC(#DYiiOOc)zs*Rh1Pen.,f2jZtYG/~BmYqE5Q̯K}kme~3Hu Ռ{׮e%&W$a}b<\5zcs;&fxʆEhe`%{4oQUQ aAjFQjU"5ʼ$=7e=Y0o␗ +"yׯt~c Nm'?˨蚡]~ty?h A䆴<2Ԥϭ48Rs=,mt:HUܸ{j !f=~!\;A%MJO{#-vf7̭}6;6&O/-m{o ᏑXxṊD]s}P~IukuOD_Hx2c#5Ni@}J=ƜXӒRJ(G"qROKNm)u=\ 4VY}=/A*QfI q:*[^L5#G y#:fSNPz~@(!QIt^]_tBi4U$v~Xx.3ͩ݀EhI"9>o?(Aɭzߓע1g2XJ@kѸ8'V۲32s# jO+Uh`d"æ@4 5{u?vx>w!(4U.lD'- Be3P}*ZUwߛž5a>v)%(߾ [T?:@5Te?}NA̷aW[SȍP!FX . `XH~ܥ2Dͫ}<|KE…,H77 @/#^sSJ $>XKpO7­g^QnY&,JP—rMoYv9v[.hJzDNhx9@x9ިj߇PH;x(7\8$Î&8 n]:H\QQ y:+wMZi+(o8ʼ>j&T-'z ۉ8kJ%14#}g|᭏lA/^d7AZ .SXg@_82v kh/s ǂh*% K^S#œnGGt="ǵVUz"Ji*~p+;"l}2/[<1TL-3!n6NNtMJݻ%&ףyK|bm NWMD5" [ U2Uy@1|"GgEpJٴa8 3"3i V>T7 `6 nnE8to}hltdRM|ya=m̻Z 0$*VDž27:UFUF~]߼gbFAK`;/c6UkWIvCV,#Z| 4+ 'lJBve0IzzȊBq ã54G6>iQo7X1*>9< Xl_B2̈kW,(ubI1ͦ@g&|BziesHBf8o,:і,c<Ցs{  ŀ/u{"Q\OږZy"e .'+wL } s\b#If=( ؙ:R#]mߩMNՒaQ6Pn6T(;0fNT*yܑ&0ͮM1o$(F𕭁B%&;F'6d>!]`qYQE_v'g#X݈pXMm2>KĤ|x R hPt}V `p{3dnvŋalhvϾQK/-o0l.dv2F΂e<BN>3gw6:O+0WEPaHW*d00&؍`hEB?ww{ᔗWZb`]|zb ;t⹰CM2i݀&I^u(x We5Y_YtZ*rBÏ KvMAst?k2Vz4TW7A/0xVl;d7ؙIpr>B/ku{a0 !LVU3=> AB|neXli RFnҨpaL{Nw~"Zo:Qv̌9bAy,oyada쵭\\u.(Fѐ7RdjelB,뻙l&68rTu&4BoP*RUUkgSקn 7.^mr༠Os6 K7 o;+OPx">fUSv <&8fLܓw7E[.R "Yz3F27{sN"DGBՙBWX{N ?'Mz0ԒwrSD5 bz+l0޳' _|+ 31P \KW/[#̢U;6琿D:/pY*H”( %>7usZy\n_n~ [)Pʯ>w=zrĈ5?:%ul1f)j-o_Wduެagpm- i!-}̟Dvw^#f5 Iry]Z\*{">>tԲWD7X`‹K)K|e556б &4s},<{aƴuTNQHSRMe$^} YLlNNTsFRJOҳJ c~S[ Ƌ؎2Ud<=)LnP4<biMaL;KLBxf}v:J~^_#?)& }&RW~|d|FZTr^Wf-iXRT=8NHJ{j+@D :0Uz9BDofu8Z?A>?D</P3.<EN UaGRX͛=@N|XǐIp| Eݚ#2f)eݒ:dAADDk /fkPLv[cʜ;$`Ay2U ˯~h$ ^uBxuP ? .r.AKZ֘lRt][`>CL"<8+~a6FNIH^J6lYܭe PXkLgg|SmiVz͔Ɉ{OȚjG. 5dq_i t'w2U=2@{Zܚ;*qtt{_1 zaIrkh~[~)Hv!IU[O:Ika }/j)r_ƗX@k?9Th;%A6L,Xne1l]^#i>D/ۼUM'`5uk Rð \uxԆbFv.Jm *zq|Y [şBN,w>"4OB"D<_< kt9b9˨&,d]ovARQ΂Jϋ k1伕tZ#:jC%lbs܉lV jW  B:(īآm vw^. LPY0&|鋤(!} JL)/!v ،Ӛ~/FBk7# W NzAu߿+* ՜׬rLfBJ#߂'É|4f}8yҴwilrm#y Qgl8H_m!f[9gmlPMȡ.}?9p}69Z+ oP.{w֠ةC._RO N[z6"/&^#&,Tx0èi!b@Ԋ}٨ =m;/CCTJ"^/.we)9|]'{elR̋j"vqW$Jׯ/V~`·rcr=eݚ<;7Pe=I̚-&Q0ُnGq,fSЖv?%x I[u)k㼆#ZɘGil ( j&Ye0o .HUI4f9=hoTKÀd8i,m@"q3w['FB#4&_z @aYz'Fxhv$&Cwc/bkUV!1gcÝL\Tu4~EDoGF^>LS5`bkU/stE^0_u ""^&(7E-h!D*&!V8E~j "~m#z _ Yp9/8h c9 <!u2] uؼGv X L&Oʾ`y1w `7job/v\#racg {A={z..,C6`k-bdOX'$%&n+Y{;,C,´|69uG{ek\pwrUTO,!sf%z]~mY/zݘjK[s:@һ:i|v! }ݓd9 #yz|*BP0).{ h j^7Ϲ*qgߩ-5~qK:߈!wW;&oEoʜ=p2 [pjj b$OWN0S֤q nɁPw=ȹXEw-Eu1fb!-,4ײ?f$ Q+ v/1!u\ˢ)*eC0CuHfyJ5ISp?I,Kk [ "jO%ѼΑ1Q<Z򙯁<" >少5 #h[?@=VtV+9.ÂDxjb[g[.3-qdZ։>;UfoBaE 暗)C+|\.qa4ș(;3|10f;h~QgKKn* g~շ,byggCm%?i@2&̿t3?+US(ʀ'r1&Z$1͡gQO*mѬEx_<0>ZO$iu8EHιrr&E'eնvP!,q5kDm_b<(U_tE_Ro.cA*+} 0+ASz3@y=@^hDA,>cҍ /៘0bw;Cd^ѩVt8Na4Bxy+}>#VQ,VgVtq&n=hj ަz= @0"dXD1r<$񠽾ڍF=IΤVsBOc6zDTR,XՑUBI5q/ݬ WkBڱ1О.bvj@VaP:'`+JSᎫ5N{e]}+LlWCjlk` K03<_!:u0IZ/S }ZoG ,_PcL X :򍙓6'pbht~lio.3KBo}h2MR|#06)c׏eN“dLO[Kj%cX}F7(B qԙ7KF7˺?:+p Q]TwF_M֜Zt|pyGZl՘BLkrbyCX7>=;qF@ F~]M|6[mK*}&cvARo$6ob8L2;PP#?z/Tu_})cNc@*~M:-(TRXD߆6m6yb0њ,`5-6(:ɬBwA'f3 ޛPRW{JRk%z3]K1fҒ q{(wfqep}* |#;`w dȄ̒x$rKgl.!]KUQıR?k Y1sC3kWEIve=oDۨx9t ά6~QYa;=|́}&jN2s .^G2x|;"ؐ=֮ϷY;C 5lAIw&CX\i2!9,e ^XpdǸE.xZT?mTPٱM-:3:RIA֊a,:H>8:]GMqm/JK9wፖw2dzPu#~ܣX*[_m>[JFE:5QB[f h\b.{t.Kأ'gOoe$T 2q}_h,@)1D3q;Dw_O ҘESxKSGڄ OֽPY36 (/v:?S[گ^v"M x|V׋lr|E; >XC^ 6Bnxt*.AÈI$WPfm5i"hOf^`fkpKJ#A՛@  oY>'z~uW<,&>/=$rE[%k1(W[b#D3yȾΆ֪ؓ_ !M$L!t/٬ ?#)n1WT%ρMOĥf"چ ef_cgs\~[E;KӝwIb=ޅ.MicWrR /5RI5:Bޛ}!QG5{JފLQ*ն}=6k4/XWS]D֣Ban~+Uu\BD4ss}O!&l{Xf!FOMcK>ڀGVO& n[Rh}NK+8 ]or^>{ËhV̄/S]*YmRLUra5JSODT0䑓>%U@"j_r&˂HE޶_taS"sV=҃lYZqLdAy/TfLeڬ*+!Oz YF$HE179;˰BbBw=4^8y-\q[C(ΐ1IjF<=sVdxf$LT'RB&1ӻ8'lI{\y(5$  >\C{%Ryif28T+1h:BJc(;:sR,ĹJT>)l۪e| #}@Weh%IQzq!}ZC" )fIG ms-I"$_}Bw$a nnqjP=9M;FȌԷz5toGJ>JVuK"![*h\V<+p mL~{1-G,HU"v&ۋo3%;*i {fbTLgL~`uHjHoSHSVuPhӞZz2#uSuc{ Y:v|˭h/7\TTثU/&| ^eu1.X苁um}kq\4J&HJL-OY\ڦc&D9#ya~m4uzpzK nOޔĦM'LUk*(·(3ϩ@m So_["UcgЕ2WS;mrU&_é7ͻ5yp 4۷)K:x[ %AXfokQ[:@ 8UF9ٖ`vSϮpH =ָϝCT1QU]. #&Մ:q>>W_t!6S}Ҩq6&jh(uxB({ᎠR}W$8nv`鼘ά<}G\o~OY.] S|{=[hrWJw2I( gpfheAxHu5#7 ĉI\dk:nÄ:L+YՂCBWJ< c QshGw- uƉ{jv5[ !wEK*Ȝ6=Fm1ȖYLg f\}J# !dm5R^B!XDrBbR9נY= 08XJK˙I<| ^~0MeZNM86yZ2O~=kR90VTgO Sl١3 ,״tMwk!z8$){FjZyrV 9kNBޮY@Q^-cJO #Out,-Ey6-O m?Y]il5O3'kg<Lj;SKY?XrP'hlT]}ޤRwVF+tPuK 7&`\g'> ž\6|Lϐ9F6d^Stl˰f)"85y2dN38r~9T["AE~YpI0fu®f0N :)l>ٯ%ƷeƢ0%\ƓZ?̆w, x+Pt44 WO3nTF_C*˪oknTZ#]qK=\*v'956N/wskq\o(I̋(C2j@vA#UzNI-_/W ò-3vWٗ= ='tgJX  ~y{(0X~zpCS^W67g)I;%O'&Nc|,~\OAj7ܖK}s;_"'_-2s`SviC5}Gۨ.d=& M4ב.7sYɏ!ϡ%VYOҔHD1EZ Կ޸1tvsv~SF pW VH+{Bl5[9;5}3s^6X AN?~L?i[no1Vt?ANYkI%D*&}[4DgiA[s~`n0n=!y%3B|ʼn95trقʖ+.$李4%pT˙W$Y\gaL FjΑ$sPҩV)*yQ8~QiC=7*޾h: <VN>Tg-'|t,qz7L- f͘jlm0~R7?v!&ݑ_/X8x+Fv4^XiMCbI0γ{l}h;8"AL66Rϐ- ;vP pttB0c\>;Gow{=[ n *2 Cl8PN7TVuo4<5"5,XuzF¦_ ÏgvxhwS&˜;gɸ+f] )Zt~6]=5_[I,oS_nc3X~ =8`phΗ);!ym–^GE^o8YvWWv^̾w-={HFb.Sq Hn[I9!|’Dg'>j֍Vե㿀2`Iu]<9徻aMHl^ws/l ]a4ӭ6$PS%*Ӛ2Z2Yu\߮kn+%ln݆׋bU 'H@!5*206 bv-#""K\aT=ϗ ?Z3ݮ?KbXosN ,e"T5GJsѰM#F-pZq*izQl|U3xkbʉ'ڊ <^3nk8#u!Ъi%-v(E3 }Q-r 2RHR>kA%X QWnA1eV܁rAOYl!@#_N]Tk%bLBs =i>xkN]c9PKYHžmLkFAURӤq쪶eQ K~jeIfCY״r`e9(<؅1q)8z{9&Ý)܎r_4R%n~6WZ(W3kOkAgK4 .eCuw>H鱏E=/j V&npS ;@1gV]w?P1~  GʽsV5Br,MɊwPmã*i`4X|DB2>%ٖ@KDi:KXaIխ&b>;c\ZA;x|L\cnz$ͪ 29L@- O¹mB]~ dq-q]Bxz9 }(ͯ\E?.s%L56XlХU]u sfP)+$-RLu[_ %2 Ͽ͞Yʬ6Z\m`mOӝi^jMa 6pE8.ޒP6Fk\qV+Pc:h?z֙t9\9QE‹[Lq[44Ƹdҍl)}je7^-.h뢋t~p]@cIqOqZF}羈&$Fs؅04x][ '߄Vkx8yJ<c$o{I$G}l Q's.^&P~ rZE&8g Z f8 0IH;w{ŀ{s%b@+lH#^~nvҵ)cy#c n uT0Bvd& W \Mrr*[20=j#0 1 vne0؎y#, %k?*ڝ#i}k.-E6n<;'})RCL"[IN;=ױ a0Zb lK i~81+5\acPf3n@ ;GP b/kd)L"rVID B.a=`$1V]'8+`wdqܼږT^$:(= q\YBCe+XJ, v؃H0+5VfOiYU1 hv&eXCL-+;*Èͬ`"QSOd*y{6!m_xhRz9=iINRq՞/k<%_fz{'u4 ugNF(na2FN4!0gkBL~ک8ܪ\iޖx;PzAe]7gs$qY6JʞnARV‚,pgW(9QyUhwMQav3ju{Em;,W׻^YD~#Y#w]P> yD7u\jXI%[xo(5Q.^?WoPUޓ }0F#64׽~,Tpeʄė۰tUx|]kdz~|0#`:56%,ְ屸uo f<3LeN~|\Ф9P~eBqyB8EB';cwG7 "¿C؀S{Y6*=7Mmrp sb5 \Tb'z޷kƤ/-9D?%BWRzm/?Q4d4yew0e[$Ӂ#fU) dH<Ƙzo]Gw E*ɡ` $eZ/oKҨ3aՇ&{}y9eWV)Y\j4Oq}%F&^!6B Di|Jzs9ԻɕcSM.åbaϏ-roJ6ي\A=, L<k߼+EnS_*7r^h}5ׅv J+bB;Dd8>7Ƨr(t\5hOg΀SNewL(]B)XuCA>qwpu0N@hx@6ELPjs~D-a&8^ 2^o~w eմOh!{v0.8q<,Ůk~fNصjxbe:Ц&aT14|P|u:`gl}R,OfKJ[ OVͶ#AHv Jq\˚lT8lYJà!h*1ȅ@FINk%YC ]i>s w:mg`s}3ұ ~8Y8M@Ne)ʩ &`W:_u@dzc%EH9T*ۖqEPp=*J(B~lm>e>auWx/23ՀG^z[LaLPxFG; ٺ  ڡI);M&H>G-],%WnBPb(ca=ԚC$+*ދ̽. xPmY)0{I8Rq {s_ζB|˒8z{Ic#/?ƻf>37nRdE40ʇTVjm/;'kP`@|1yUx>xO_=~W*Ѯvh$+ō<qx3H%sm{"K ӥ-|Ew'Lf)Ija?dƬp; жM0O6K~t[5$S J7Oo:S48|o*0{UO8XlX*x^Z&d@4~a磽 b? fF6 tWGq)b>kqhTK'tݧko_q9n]z&U\VC!N5*f ⭢OλX~bJ>qw~mC27,`' uTFM:® 4k=Yܫc&o!Kv"KDO.)mH_T /G6jqg\rtEs*aa-988# y8;- gt/| ۰253֘Ф?;amo0͋!z9.^r@JݢS,@&吆RLXWtՓ9 `xe!MaN)=W7: XC^}9߼V{ NK1'S`X EEl WTѵ+cGʽU-\eΪڳ kzJŠ=YjD]m't$Eї1:jdմܑ|hRG!o7Qx=]OZn9xɠ ԁ_%rċ$Q)X-}R^וvҟcD{ 3D0Yv\'7ZQ,UbVt^(=uZ|:'n_Y cpGHЏwGxc|˶"a|U7ň}U"L悔X(U5:u9C6 xZI̝-dU1'J7Xǁynu{٢t#^`^Jtۜ>}WPy٩⪧90^NJXeD<{iaH#x}Ul6E-eaAOZ0aR8jc ob RE\9ɠV ä#2.ws/0Zʖ'wY<_D`l[sdM/[2wïZ~Q~v^5- 9B2ߘ ""Ĕ_G3׽úbGRmsh E.~ bPl|qhd[/8ud|W^P: DY$b \)p*AN`cTۻ ]++= >No}- KAlO G`-5fޟEpN_x #5LnjX,յP46C͈/^ɐbUP''ѹ[4.ЌhLЇ% o~)hKR`:O=Ʌ'@yT:`5M>z$W9m?dwr/iຓo?pQIױm>nN{(*]F~+w0hCIvx:z"Fܸz(gVY 7PMڜj j:Ց27<^˹%FQ= Me۪ZG*!QP8Z!R#+fMU%~r0(NJqbS^FN=kw|79qy 9e;GċFDp}]Ki, cepp`wihI7 - w-w{P2'np|Ӝ`.1 '"xCؔBQpϜ"nOhozl8`E& ]aFnm 8ecS wU_nv4=r}vTdơHAƒ%6#yEM :J1yPL#,dyZTŴi#7@#ɑ9ʧ߁;kizG,:ZWRn nTd+j; EbR,D.ӇƋC!c:z5@"q lԃLp]GeX"xnUZ[~Äz~[V_?o g;⣞{уJg〠@ZV@D7BGJH1A8^d4bEPw^e),G밂1b8rqNI;#klEu+KW&ĆV`{ 3'?AW䠪]xhْ3bNaxY^۫^bDTh"-7C5x5JEӫ`,a(6lVJ1uz݆2T'@ڑf ,!:1b2K`tTי(H\4ؿy`[^fZ_Ў ER6z1 ĚQ~mF-{O::p*!h5gej@pqx&=(|NkP̑R2(v˝ rX·FX@ zY~P򡵤7:erQY֯vmO nͮk4pĔ q3n*`6d,9 S@"'q ^[̥`s\`?pFˎˈ#x2@VaHs.ذ/?tZ˱ع$el#sy.5ݻ)[^ZZYJuPž0/@w e c>d ^h_oK\s,l4!(la(R9Y߈o*"ɪr>W8;ctm9@&ccC-Xr9J*;%JL8ln5)XPg 1'I#| D àr_ɑ9cg!Lf-x+`ɥw~Fu-I˯ү$Gk1^k6էSX2PF,wL*Nb?] d$==vZvk:ϼVTlډC΋u|=si 6=eʉa[R8;?n9?q~G&mƛmT/7ab>8A3yI<ҨIJ&[84I(}Sbmk8ԝWJ3{qoh<n3]gҲ/~("԰A/ahio{dп4>3UsdcMJk*q{o y,%ՔnGx#7kp]zFH D* qio{@ڵ0'K2MTj!rۛ'g7o2: ^*r魯} +/RHXރ-m}$Of_d3&3/=뾕BԶ̦ɇB̭m^Vx-; ) ,hCU,aQ? hF'w.TÓHG " 2A}Ne!q,-$"}VSakjQ;`A6sb1@0C2P vJ#6``j6 i+=`$ۯQbD,LBU01.O,Y*U"v`TS'ehn@-(LqJy߆c bl)Z|C꫹EcE { +)CLLGa$݉y*,o2RUgXm "9+#>6$0O:@|zKFGwwQ6k@q*r7i3O-މ-4䥊V2\ ľ?3&$gqaT[W,4 hߘkΏ)%u9{yځE ;UZ3G)tMuW{&6@ϖ~s?HEf TJo3ծ\<_'blCoWv2݌G$^7?L:qufn׮'2e>| |Z+3f2E/<*I~-toNSUqv ;EՌ; (V)"dUp{YU"!WtY[=0qNl2'w9`^ W ܶ3[P$zO[D Lwac(ߑ6gdJzAX;p|آfbec'r0 ,Ps?r}ϧ҅6ߐxfwd[U!"_UwyeDNdsPBlv%:EAe5[=ijOBZ*W_й!P7mm|螕QDfЬl$l9Mj3#,e$3V`qN~F> 0n*\s6σM+SrT qvL~ ^ƝFjVY%߉?e/\>NVHò OVNy $Q75}o'~C: T}Q5 m=F@ʁLj&o˭h4pKcގKJeiNJO3ضWv]s&)Sۑ3Ȕv3c"`ęL{O|\dյ]G|ToV.S%P4zZkAb{f#Axñ ]M =B==[XnxyECD]g|ԙ${b'*HyA]ݲkJ't.w7q4*xpcUjVlIʯn;o^VRJYżב]p%շ{tʽNƒljIܭy5׹mN n=J-aʜv)H,`#'%GV Y\NM}dv&mFJ@,c5;Vo->>΍PR#l5-B|[× a%a%nӺ`n ٻ%7HwK.`w}zCpv\b:#h碏j"I 惯ry̍ (&k8I2ro*150Dq[=]RvRaFG,k?DU3+nIcUl$9-$$\ %3Vwk.+A?kG'nEwvóo!GW8Rd[Lby-GPp(%_34qW.7YOĒL⨖[bM,t_99i^]|'sy^H*."3H`?/W4/6`QyݠNz=JboK" pwby˒Cigy3O}& -qmW!6)t IK4 gI|UNqMz3eͧe_|@!|Y t߯@~pKV1tֿ{GSQȑٲdhoW/h2=

A"ұZvͬK|w)eٷQI\noe/&HK<\:c~KvSN먈s@U?jb 58wHmͧ}E ɔ%hw_O j.ڑr~^\XkU%A-J!/J̽PFl~jmqo_B\یwϟS/ 𓕬¬%xa#mZ`:b%oc6 L  3vh?NCw[D*}Ս_@:)Ud٨oFaC\'暚W;vBI^ #y[C3!fM0NN/`5dՇG*%sY~~Í޽nk Xs)379X_ь6yz$@W {oD`)8ENO60d}l%`jLk!/p\bJd缎oBoƸyܬWBsg9y3D_UwpYX" Үv ]j*ώIk/G"nzíU}i:Xi3<Mк8^QGAIOq5*8WfXEyҖnm8>F)I:8ڂ}`z4h&%[!o,ṣ93o@ַ҂Egu38DbXV6<*ϩj sf.TQpd=o2c9t[?rg%ֲھj@ &o1y0ζ!Πk 5XPΣ9F\i.PK Hlq̤Dg;^NRrG/g&$/7q&PD MOrK>FE`Տ~\nٰ̢kM=NUWvFRP9dwSJ~k)r܉oiX)+6Z;iAF'٧%_~HӃYK*e ǯ_pD 36{^}pRFj*ނ?f PF΀XM_ .8,I}Nod>6q L[-,o5~Q =g;!AZ$G~?הMfP;aIZmc~=4uui,d4%̓$`or3ѣ 2iy!P!$ܭO:9%GWdhM80]J (Z@':$];29N(Lp'Od~Z}\, g5]C6\ 6y. =;ڳdbe,,-G/"1?e_ݴ D\w`>/k 7da>rf%<N+ NXv 'M:yDѸeQwS ޢOuoTfm 'm_`駱N=h]ӫ=hj-RRKS b_oWVgLJ*W}O< Olߘ'; lX4ũ/?GO"v[4 3߃-ik :hK;U(@{jAJ?1iуN`m;-Da~jVoe&/Mޣ4tVqMXϱ򴇔 &" - K-1JQ;aCUZՖѤoc'ZmbG]E,'*6y#Z_3\MKhuӶsĭ,9ׇړ-E*%;๪].G <Y"i'̙^戅Do&&a.`ɡ#txxUm'&ɋПpֹ2 @kU>΂& ŵau\ o .g~trp̅\0+ Lsa=e&)`zo|@衢(ҵFkC2k,d%`A ˝4Rm H7eb/BCaYruPG3ktAγ~NpӋh?Gՠ: 7 \-w1,=!XAZqH f:h87ѣk<l@yx+7diD[㻄ַ.FUdbkCڦ64h n$ <`כּkDyTyt hَCxPm.>)S Sp2n;~`F%g5M{qxJi/I+7-AG3@ ؄LZ@[PF4bc4eI %/9AB%K*f~uvQ.FJ5X򋋔N4K~90riY}K{1[;Eb,72)򖱃kk2l{}iYF;^!I"oضrKE(l7v-⯂!Cma̲^,$/,Opq.˨{vm*v_'N6\$W:\'u\%qU_Э85*n1M0u5|2 –=V>R,Pw*q_* qKɛ<k 1?BA :_n~v& a"$4Z /VYyl9f\A^#م,*YOaPDybnZ\%{ZtP^c92lV+LNMMwz0Ӫe׮j@|^uZZ [026btRAUbn>ш{](ZӸT}3rP @BȗA4:3}ĒijgKx*\nj@Utp;JLýou,1}(|&KJue}37$ӏ.k1T]DUjϸ-Ȯ'a_Vm+"yqWv[0u770@*=dQTP3SlFy!X>| ɟ$ :<q> Dc(wjfv\+-ߑԨmGLuZm `m]YU$Nvj$F|!%.L~beq}_œ5_ f Jm~Nsd凫4tV1Mh;CHj)sT,-|[j* eЎ#=/7m&jN?`P%MAgzn(rvם4㼒0wz!ކ7١z":v=8}T[̏ƦOlդO|&p"(F=UM>|IHkHJ]͠ys9CVYrX٣WGbaZW7'%k~zo )%ܣ Gacj!￐4GRpW)7 '"UE8nbApq2dyU"C}'qÄv aB 0EKDzk19JHGͦ CU"fIk ]q}k|^l!sdUQZm jCMkN a\=kr[w{ dk=ͥAlw8 v$ciRᎰ$S9Yw^F}(K~Fdl᎚f-pl"KP&epJ:UKҪ/|F{?!!j});Ұr#M67`5x1<D@!;q DEn++Fӆ͸E^/.o.(@$H8"v\c -|5ר+,xڠˡNQn^2ںSlbA"A>3an`%mAPI_h~C[Vk,Ӯ~^JN@0(ġ8;i~A76yU K n|>n̺dXR>2V^,\Ѕ5Wv.Ky-?dC9R6y#Mrs:y;;!?yzz,7?A 6,Ɣ29f6MV;;CK6@m{qgP׻.mN5$EH"O)?4,*a<B!-#q+Zb\.g@|-o<>k V QSr:Ǿ~  ]q!Z3*Q ; II7!F"C!-15˥)VSCLjG WAvďnzVU#mCBRDPZIԠ̣A+@苔%֥lvτ Z@؃MR"*7Lh*< 7]PnٗdE,ɗs}u?:>* Ws*h(pgp H~ޫ:?T މZ ɃνLoC}' )>3U=+C?C;78N_)Lff3K[U|g4ey(~3Ps%h$"PƬ nH&EHXKiϹi.NBG#ĝ}̭>ia@IC2>]:f! T^JWCn`,Q,&0A`Q[cvpV3:Yz9R9+z9 V KvrJI},Mk)=5&EPB/ W\&4;NY\UG3j%9erSIaKNIc*Ng[ ݤVtk6ް|<8[0 hRUca&ilPsӭTK6w'R5۽x2TC%]]C+H52kM(tf/` #Ox1Zm]$yv RbýB$Pº}ڒdV@(B&c|cW#+:.5hGuK?%C-$hE(N$[4V}ƧZw@9?zqX$m![y}Z206dQqGpǚ]ck.u{pxQIsf2MWsew}.մ/sPp>]{P:̢-}2,H^@0h%#q`f[jVi>(BAZC(RxNE\T|,Ed5s{(-O۵X{b5CUeD F8 ddjN˫^fH>k{~ӰTVM#C0F/UPOHXMUꏻ[ SӝWqoR!02p6uOW$.hdDK"Ռ4(@F}(vq@؟v~qK&NesE1S(,c9kuHСk肓 ;3]f)[A*ˑ0Ǜ0N>ǯȌ+':rfYh8:زf Xgc sBb"|)i怉*ȃ0k0eW0DTk"ېJkN }IiDScs1[FլށJGU`#$$:$$=%u ٦j.bB\_0VBz$[zxN87 oA1|_({a2xZpڛUmg"o6qҭð2+3 +O'SQ \S%'OQK~[QHЁs#fj%?JM.-SŪtRJIs梅.{ۿPB7?]Gn\3Ƣm{ _fػbndMBڔtTtϬ UEfi!,Xr :x*uX]52_,AOG䅖>V_:}9g7MenqObyx,A3E`5%Uk[)QjP-ٯ%N͘$͞s=+x4捸7 BA8P_*x”)G\e$ :%.Z+ 4h@7뺍3e6hXE,dU) ;cyK~2CW/jt&hf|cV~ZzX'+Z[5B,&ts0(sdӼ|kؑ䡚ϵ} RRlfLrVFx[z:YӠ=_ual8XcDsۭe:ar4 {' QzCtk,&Y63*eq,HnTZ?S@KOQCHٙraxQJrfzZ|ނn1)+_@$:P{Sqi3Lb VXF=: cz/:tUt )D<#2uaG)?ߎ1 ("c QHBS G}sɇR56U p:6.J.O\>+*cc~p6!ſ!MX\ yd~Kj?AwYG% 'wjj#:XOvj9lq.Y~ϾX_rH/[~۠Ӵ{f7A_ۈlSVNh5]qrHR:ZNxS&=I ^R!X7"Ԁ.[2Hgmb!,Ĝ:֊rk)}Fnb`—УTd&&4n MktΑx~lrĭI  YBj=IOD\(:Q}$bl7Sـ쑨oRq&}iڗ|3 [8Y{̪ ge6=AU7pзʦ{'5Ѽt 'Ma`KSu1dg~>pw1 C~E[p2peY0ʄH/yv0Kbu ϙzSVT3_4C= q3FQ0a 0!JjmX9d8Y [7'#ŹcOggVӨAsSMrQ |Qq1G隞,؊y?@UX{F0(~-%weZ,*M%S@w6sF8Xa1`|9PpPzs4hXuH5r/12R,$XWH}콌)v{H.k(`-,-/GX;u~߯QO|h8~zRRf@|*爭 H6Гޯ\^s\NzYݹk&  q"P@m Y)(w5h䤑[Ln)vq̽IqGǧfid:nI R˔BmXCt8Ǐt~|OX0G-bɜSMJ-/k.p 'HX2-;%݈6=1[YC*h}!xW-wv0P89(V:`KjiU=dB'XJQ *@B=G:1TuwmeSTIĴ9A܍lCWh1hXJZ/_wIymu- 䗼2/X~Rђx 0 f0/ (Yyo;=DWIΰn|2O' yYHw=(ì3ZTjϭcZM.( jOv7frav@'Wֆ5)ic/S B"`%r_'!~o15ċ (щ \x^3N;L>0{RRao?rBS 'a\T 59 dDĴ>F{Lq5o 7Az5/͹. @savG5C ֆ po5#s\z3Tyؼ`DVolSEAX( Bx(n05E DFX*9QAjPQKym7?H3c`Oݓ u1\(q Qv9Dgp$ʃ\QA(jܡơqD*98 />Yc:eX:>f(̼ϻ+&zJKt}E+Aɔ[cY^S&@.ZRehx f<{SBJ$ӈ5*`~  ỲОwZJEb!SAEEJ~K`>!dRp6e2]v_I"q f^4C.w9+a!`JPueUS'˽v MfX `vrjU2\ |8{Rf 6heY,'GkIwcO*W縄%ġ^ SJYցdgkW$[Y 8x(.};E,|zY@4W,i2@ w=ӟ+IU}=g;T!vI9#ҙF4Gv l:(LLJ~)q@"B9 ~q}Vby kff+ ,] I e8}WꋆC dv8 &fz?[`ǚP)s0ߍ$ޫ8O%2m~4e؅`5nM{!n7<`?dhBGےT`^cچknX?NI $g Ux֣z $0.t1q<0b4zRce 6b4m2aācjŮ-zo5?+L)ۚ8 ]ȟD71#KLJ@ZJTN+҅iMV= S!eP N{KCA@;bԟ;?d>.u 0$L"Ob NΎ&L[OҤ)esX"ʏn%VLԼh"md4-̵E&1޽E:!MUn/Dk‰J#C$>bWK[E㟏#==Gaql鴎[>D!2>M|W͕L 0[J[54+1䛏2:֏O- }MrLK~m6FLp%4Jn@5ECl*R|lR˱\nzEg+;}CFىŦ n}36a'xk `,1Yh7#WGcR}%ђo}IVm¶b5>t."& 0}noMZsz"__;Z%բd ${&j^nOkaȖv0]SZ'bS]Y $-tZ|F`;ؚPt(pIu /Td>!{Y/mS8r^ TK-إe>G'o Ec"(ea[%?,5 J9"ICꎁ*acq}NAg<Rs`h1J,_?3g7~@IZfg8it+G^ "_,5$_Ӵ"4 Am~"6 H_rIAwKv4'ZJ"Qqgb&U@8Ս3[by2Bٴ"E1dȁc%b=ceW&,;w wpo謃*GBV,s7S42B 7ۚN ڿru(knڵl5<?}EС`h(vH;DgC6~}VĦESޕb$QOk¯ykw [H@V*G'仅# ml%%Z0VZÝs|YsM6;A ?z6D{%a>މ4BMOu0dj-:΅_(S-Z<ybs@@OwUjts]Zv9C9YkfA+5L,'RWPS.$C ?!RtyR$=͝1Dl yH:CS˵;z O)Hh8 jꝙ!$SiGfBQ&=4ĎjF~Q?A5<`~Mb$&hڤDe$ 0xlF' 5V|+uxim^~+oલA{9_Eט˥Ɗh/gԸE]*=4[sp b$-h@wT`zOuHĹFtAFQ@<;}0iuϴJ:%f2Kh*5DtD˅Nî{.KfvXt?F;nPOwFUD$VgE(q7r, H!]9/ +߯\;,],|"](!P$󨀤L7Ql*AVLvoYٗ*f& @pl$Y" $-CL5 _&;}%Ҷ&gJv(M6uiu:z%,F"$)al7@`v- 1ŗt( Ҭ|s1WEƏY*]ŞdGv@bl{^\_yOQ"ʟxZ䵙891zB76րI5QĠ"wR;l3쿍fou-=Mkjfפ JacyWZJ _1FATO \|czPit92s=Mԧ9zv@f)TJͻ,c |'O7;GKN.6U&ho3T;81^ɟvKsan&_ITc'/$?!VWTFU~Z.mzE׫ë Tl~u.4V*Ѱ>vBZ@3R2'$SnYxþϼ4://?ؓhWW:jgzu_hF=JeM-ol@>R/H{J`K@z%rbE0:Rq:jOme;A\[NH,Úrz-]O6 -.dZ ީ$].N3%}6,ۍoq0(jr?l2w-)1kA6;`ΟsO3ǂhMjKAMΜr]6+iB3 7O&]h̕Gg9mN6^NbMiM~0 +cy~6fƛd=v)Iżl [{3 aDLs5>cSSy<\:<7/ YH^i/!Vbڎ5(g;=`́' EPb F^UNdܾk45,Z:Ft;\jU"#ѯb%"7r"VgF.X:tҖ=a X +$h0~~L:K @IN1)#9zY'AOrW V5@rBctV!TԖ0dQb $;C3-jQVLq›/B8GaZ'Sx_Z vcz6 a eQ!I2YqQ'oR/8DNfFAfYBlUᭆ;EΔ9"uYX>m0lvDs} 1?L^vZu)LC2;9YCPWiwr $l2W`bvЧ!;W+z8DZ?lmԇYŨWq',/]H`~ y Ro~t9~|]D\X.r?DAӡ"Fk[5Ŝ Vbmo$kU75>{q~:5s완Zই9 W;UE6 9?9&-Qڜ^nR9 OlNȽ;_¿ʱPx.:Uƨ.E0(U: &[?% b]W\`Yr @dןjkeF_#'a/qRtoJVPq$b _T8u@m ɂT~5r7™ @R0﫬e,c Kr*][>QpuN65 }f~/?*Du/ g*S]<]<"ry t} ȐYD׭ uɀF=.yjt(Ag4TA:Aؚu 3qL`)h4a9@.2s>t^caH6X MتÎY{_0r꾮G5+{Q)CMg԰$L8_Z!=˔m F1#;tkȑO6Ԗ M˒ ,ށoU{;hнOO{OnU۲?ɹ9EY\YC_aw;=Cr`$5`ɢ<C)b  8N9M o!45GllU_3,~ۄ}v!._:j- AZ:6f𦃒W%"XUfFzS;"lx-&p NJ@dIe6ᦉc#\z_Mt&j+/|"ج 鷋:h4J ^NN@h5-ҘطV\n_m`z SIŦAm* vǸuAoV6-BM`>TDW.R^u>(~o)y`ݤsPJ?i}ðtg )ڴqO"6y9E_o'e_ZkBv[N R{Y3 Q0 &ze*/,KGlkUlM}ho}rSo€^pm)ׇ# 52_0+Y(})5F5Zx&2Gt],GވL8h+S:R@q"4tN ~ΕG+n g =͌^D9{]̕}B+ 8GA< ==H F0xXFU('xڲwPCZwCȔs֡δxZT\ybk9B\%)A$j`cB9G6*R$u:msCM:uFj / Z>bρGyI='4 e-.څYv8C=m >3i%_iW{MnoƪJpL4xh`AS܃䆕6ݗ'bgIwN x Ƚ̎ㄪsGf| /gs_b"  }P vJ ji 3s.M-E FKUY3}4ٚa,~0Ó-1x6w\%& Y. td oErLv`(2J>o5#ȟY!MҘ ޠ&1rt߬.9jі(j˽ ch|g|֟cp~H yE(b 60o]{|?GVǯ i{w'FTZ̜S(*mP:Ft> fltg 0H`c@Qɇj,kQxƘAwє +7u)/Ĕ9Y (XJQUMi&z|w9S^LŬaj{pɿx~"jcZ r` 0"bAM5y_|?RŲv6%1(jLz~\}㧦A0R?>.߂&HIe尥|4|BwA8xMWMy J~u 4i<еfidnGG~+r5Mm ~ ;b~YZd3$ud@zp[Y;l'5~mRr(ge;uޜc ib v=-Ks<.fQK\Wf!G: S'ES7*j+;ed IM }5u 4)(ⓊA괱Lڢ#{\Xe\x@{|ءNlx-§"MKwMLe#p5C$^Ҽ&>F.`}~:rܥP{ =%TIw8*iO縤& E"Buނ9w< +t0%b=̙s=ף5PqRRmgԸoHO37* /ruܗG[O:kc{jW$6:wf)B/5:/jA 곧0!%'_ooupbeh+Q?*(P2IuKgC azE 7GS+'7Xr=`*;MXJÇބ!eF {cx4ɯw `mo6Y1iIMzމa37\KҤp s‡c":(Ob#V{>eUBSj9MLʆ2ډ!خ$Ar@TLAa̟3n:B5To9_"$EY^V/a2%2@'5f&փK]][`uuP]]~p h Y]PﻚhO]l"$S/p﹘N+|\qB&@RI-B& Vϥ'Pzu$6~5B^5V%8U%CgdP\fˍS; `=YrtT<;gg@ Nx3 - 22P+fɵL+yWDv"8Fvzv"kX-$4X Do :dM#G;xֈI/tüiYS囅LF1WP!'"B`cfdjw9T_O%MUY}Mͫb=zͺ|w" t:{u-ȧyS32w@\")eDpzn!T,Y1O(E cB("CڼnYȗCz&łzMϵ-lƮ_1k W^/*wѳmk6ݫhUy7Wyr G7 fwWf:6^xg#+4JuJ: !P8S-`·x7b93'k{dv $}-a`qv]ً;A0Te _ sb"/S*kP Y#UʇϨ+ AW6]˲**nR߶Pc~Lijf?2m~i  Q0DƟC6N?\ ` S-4g9gOBb +@"*CrDs?Аս3>?PkK+ϗ&2 @C !m‘ƐH=Y$?H?%&А_wR$GG0CMt'ZHf)nH}G9+nˣr=zmHDt4`03e8dW -wV7Bauڨyyc3=u@* FblA"+9ͺhrV]4q $CƱq%ٝ%r{͑,1_Jx+5bѣUD.wc0uXZۙ.pBj7 ĞY]L],ޤRyD%ݺ.^Œ|-S"ن4TgqBwg*N$|1EzbĝXK̓m5OoK(E3Μ76ž& (z|xRNF^"uàPB&y~|l ^2̅RqW`yN(Tb:#y0)M Hӈ*O_|WF$(k꓀mcjC#gO=XȯZcʤOJrRGJU p@nzV(*d_U-*3 :ߕx9Azul:|wɎ9cgBPmc>"vxќ>_४rbjָ\N.>}&sd~5HϦfEhdADyRC#aR(b~"ReΦ_v O'|)- }>Y/> (eDr;oOGD+qfٽ~4Nf fO3pj<1ábwS=X'xaȤ-A؞pS8`Ĉ"z}V^&C֧Kn-KulKϨ%ʌ-F+_MB9}/ET^td_m7޷~S Kư^zZfHElw2"o[7!`2(au?}o'be®Kss ^A:h g2hxsKwm+o];S-SNzxLUwl\Ffs ed'1Ւ#eSBAItٺ)vC7HS.DsoE).'e8?9HZZxAܠ _>1͚gT;"Σwo=k Og"?6a? "<GPE;Z ~`_=<+=#ۺw$TMzݔ} W.VWsR:!Z {F~jS+vS(#w&-O;R'V2_t>!%8p}d:bcpxID Mt;гs·wONGytP2uG?1E ..V"l2RӖh]_ry5[~g?A)>w¥HPQJ6ժ$K #!R[>W=l%1ڪ|mO:-{gI2sщ68h8 JB[[-KV듴%T\ /vgweR_| o_[1JGLMZIJ2DZ{iA LI[Ƀ&Y+Ӻ RD~߾&yy41Lk.(SECRo`;UH\zJOX'+F-G˜>M#ctL::;ݰ2EP܈bvAkw rCPM.MqF`yͻQn'J0-U&I&dɝY%Ֆ8pڂzob]\ wDv*aCn> 5;Yā:!mvWZZTDc;ۦׅ!zkf+VVaj9w^<[19cW$I,݇Ŀv^?“@Nyf6R8Ic_ Gb$AVnJ8>3^(,2/rEXm?B]BsU}9+ Ϋ5VM8tNֽ<(>9tH˜p$xg"H>Oi/Ք_7_.M^"w]9Y:5Sv P< }X#֫[< "=[;aAhu]rV?tUqL(MT;Mn%lO,s*$sApΊؕwKgcr$~̛kJb]+p)n&K I~ZU8C\eD&s86E{ &O dF ؍zb>؜wxrDOh W7"]jyI;N[e` JXVӛE ~=KM* #lN*Ȍ lA iej&oKv( \O1ҏR,֊B!buZq>Μx'AOٖ6_ `gM&qrSG#<.1 LXf-Yqe8`û5Xjqr9z ]y{{=[q` JDڽj'҅'ЏL Uu7S"*Q[|ɗW^kF b[cm" U1۠BѢC&} *ȣ@ &ߌ5'P0㰶Y}ؖ_݆mg"MH!݆wTkڽb?15߆%HD*DT8vEé0op:\{.K[ԀoL> {j2;+g"|+}ȥ96-Tҧ(_jk]31Pu}I uIENInjI,UO/[ḄJ!Й, oEPӏ`VyYZ'^T )xl& mp˄Cb[VE !)|gxܖsST>*JQ{8׽ҷZ? +V=E߿n-+-0.=B+K,}m+K2B~p!ePv, 鬶_mcZMQdëf)=mSLLCjZ|a&tξIDxp#%vǑۿMGTHR]BHF% RGD_rBv8n$YtHx!6ɔ}׵8(ÎT_K$bGL>m68?μx&.'4#T&>| CRe,FOA4Kw5KXz[d!u C޿OeCMO;DSW*Vymeg+u5x;;v,XR#hRVS4S?O G|9&4'WO{1^_g<ՌVguhfΟTY>;WˀCqϚN~lwE>'1~GI gSN^#v!T&v*MD ,h[Q Fi"͝±ceXvJvaƤ-޴PK0S2ҡa. |CKKJ(]w2s-M `Ra-"DU/ \5ތ 86C Y#=gb" 1f]/y|?MHC<*gD,@UܣvG!m'&;,,\W!"+:~GJVt==X1*h h#IxIyH\r@UB!vk1a( 2Eʦw mJ7mN]H1 Ob9 u53hǐf*9ߐ2W95=ꐃ/QWd'& ev1ALW( ^UUKPaEu~rGJ֌P2Δ-(''HEd%#:پg^izٽ(W?)spO$J*U6%W~SE7e<7>T 6Up{F Y*FCF뒞K!KT,s r,4:^@DQqu[:=h&Iŭm L|w88X`/`a(#\J,GB}G#ʠh`زTiYO0Gsjj~-!HNLG״ Y i 3y2bMIs5WBCMtT{\B5h=DBu%ranR/ 5Zxצ+L%}Um sv{p؈Th[Ls Wq)|uIjR &< ?w U UwaZp D!#*%=4{li_5Ĩ6?2\&,/jaw7%ޠl ]I4E+AIJgi;F5u7H@;g?4T_VO SYS_r6R޿ࢴXbTEA7~AU f)=!1]:a/j}@1[<4[ĜHM#x3*#g=5^z?ߥ/yxl1ԓCm x}=(|R4R*"7L=WrG^D j3%@,.Ֆ"jC=n1$ M-ϦU,'H`'T-w]BHv7n-|ܻEr 2y :`Da #Oι8j:p(Sm@H̠5æ%4~ mK+Ip aOoŭV҄v)׵5Y2Bk_.)kq.f]y</o;Տۚ_яR;}$e4TϯC0\_) qE3;[-"w\e<3=W(18R#zJ?}aō&$L h!݃ܓ\@ ІcIHR*f[ eqpsO2uə"KcV1РS6`n{3H#AP mṔyU%oiG# EQ22TYDCDL'Y?t$z,d6X.˾8iͽ?l/ ?(|o %P?P OVaKB"A 3vm%2j=q6\ @)?8 8T[PuZ\X4BZnݩtO0U M"-u*Gw8A[;=.<y$ QޓK^ &OpY\"#`Uƻ^ݜYmÂz(>~m5κnVKJU.TW%PmdVdҌW0*-K RTO z/]Y WtAEX'3vat}qyQJPYrnӉ7 (NلޡpXOM( A%S q*P-7(KA.fwz&Ұ8(aպ7f)5| tꀅvz17xt rU&◹8I_Ӆy` €!Δu#E3xY[UqݱhZ-nrb eUD'z3[_SkA.42LL0̤M\&# zÓz3Gn8"i7GԂBI([)·|]|XmUCS8 y9)'L=T4.&J.z[es$1ۍdwZ؛Ћ1>11iڐ<"Q9"'hl}0,_bF@ kV S^YGb1` ]9:R {y@㴢&hDg]o(-yt29A ^SstKf7)'9 A s+?Vn 6ef3vp4m&)&Q|kK_υ"{h @@aV#w~5A6Ku%F!6;YG?/H{Vc؇*[)А X"*/ #+-~6iW #,$&`\F1U7m;tեN =,kC?-~x߮+_N7dip_iEUymxeVr&6Gԗ/]`A[Rg1rݽttշ(Pz雉76&gi=pb긋2X梽n׌AW|PoU'kF_ ܣ4<}P]z*K1Zۗo@26ktr$6:͓εG*439ߩgW{9Ť3lmxKGS+@s|z@ mU',JQE~h0"f@t(I`DRެqwJӄIMkQnUqh*'(Gw#[ ։}euxv!XҎcVYgb[hi2N9Oҥfǝ![v[W7Vl~M@*FjcVlG7躒mӕ7UijG5 &hMҮR.OEzdU"[Bjg~V S)_\iKZoh(,{S^Ύ49# G4"RQv6"0 G:?HoQ'l!gC*ԥxrj_wL>Z@i*s.y_Fl2i;9&\rf.u /4i]AF-bDo"]4v']DLl3tItdY[/u|s$3'kb0ũr ,a(Z-j^6֭#x).&tҟ \Qc+S:VڰGn#s|4!Clnl>U>+3bvy*k,7Jeqb!-g"Foj1 ;ɾC2IVg$ l8fA;ݣn ޮ#}ČL.4oa=>S&Xm1%>FH^}q@$=ӁTC_SS[s&1?³ ,$'rzTXJ`+,S AC+ #9X~_֧l+]Y.P:''l,Z,OEZ1{4zoux_Z灔|:OAl>v30Efp%meȎ`X+'Pqy@$<ޫeP!J|YseV.ϓ8_-Pƈf Wp-&VRS:e!E,M@+)q@븥RB~n:T7q$i#7΁ĕ4 u^opԛhHN3B] )ia-f˼|>̨j4)8(q{of=1}BYɓvXN2KE,E1,A!I။ N?%3pQa/|Щn"Vx>2Έ1epe&8=IrSYvMƕF$KJ_y]Wnb.i 3yL%,Z3h*)3Ɍo1+Ы@!GV{Bf&M89h|?tşt`S"q+^&h.%yT|SPUdr~hźŠ[R6B{C#&{>8 eŤ3 ˹}Ycݔi‹?o_& E[O9iAEL`}e֓aH.iK޲'m4<2IJS`)+e`5)QO뭔BF{_  G'Mqq=`5=8V A&$v]&V[OoCD'⏖4& ^nH=!(qNwt`tB[ ~Zaum//RR>u*6XKK:7w|D*A_f{lc_t0cXkjEi($U)iqחһyN0\1*nɣF͛&Ecj/|8 JWSL_ș= Au yvR Na<q \Pr% |PUܢ]`Vjk=hBe^CUE|:n{?J]^gbMM3F<m 9zgiṰi=N^ V>Drw4N +N&43 u0[b?˘@ɣiC8WP@-s mTBfsy/׿5yZ.薰e1ht-a_u9Jޚ-hL+5YhwM"ʁj20ƐkK<aĖZ١1͍yD*_[.^ b2P-Ӫ DɧE?nDN7hFADo7_Ke,쵓*"﫩졉xF3fNh]<]7/\>XYOXݞ$dˮU:+NWW/^&GCQT܅ nyV_kuVMЊG+U={ZdЅ_j_m 6 X,.~3tIPmOB хޯ#Ѡ8h5` `>̋`"b]kTք654|_^o: Ǜt#(hbxy*m=AwrWi syDp_[cFG֒7и3YC])|8h;ϱq̦aVL} NmcB^S9ͪYV?^Le*^#@Q)?6]X[%UrZy!SYeZFGL#5lx"LdGŠ:yLPfsUB{:s0!l˚GT`%U~T1"43K`[ݮ?F܀\mA ĶNX(P肃@}`y-*yѾ?xA),UMm3#sOrm $J*>a6V{e i5o΄L6rpw D}|OtsIu=Oe3Kwy|XxyMyVÃF{ԧע], k}ͱaj(Y]צJǝ+TL);l^;K+Hx M_"F&avOzCw|)B6:Xe*+?"ec`f8jaĽFG7ڭ@C4ȹ=E4)U&O;rU{W-Nю boɯ58 shP&c<+_D \PAMK ʁ{נmò 'ow|I$"*W T0!$&}Z ٞ5!l4HAKQN0twJy~u' rGP[id!.S9UC;HBzU-mbf'Heâ8ȄW&vW"Ya%~VR }Q Q䍍7ؖloކMn8?dsA}Yk?ShV@sNwS?^2a<Jyz,U{RL6B)afnra%i3nm],`ǭ|ݬs ?9+֥:G3Zfr>C gu st8WNw7ZTM@*|,g@S)fm!/vR;! _ |Ok?f1zu/鴱}M(~r͔sx ;԰d܋ۗ\qužD˅SWGfG{]8Ƙ[ gg#ź^Nإ@ ՆcV%:Fi匿94sAK%u˭*.l凓`JMt A^* *0UIhi_Xr+>;sR #^re:\;:.vyw~#x1~0?k#:_;aD"vm/|gSYSGH̦랦сҔ Uģbֲo"w-/QL::4L)^8 g5(MwB*bUAq7/]y&+sc Zh2eZVr +H/rEB?׷]a3%;5Le'MAVDۍo[a|v(?@}ҤxHޭ#(+M `EiLPDZc60@*Dg ]VԗQ7˗W {+u1\h׵p$ˡ(U]E͎閳>vаX<l^r=y4I$WKJ2endu>pq7O>W &+zԔ9€[֝bW3~T_ά09HqGXFlɅ8buP1_ikr?(7'߯ô|R9FڅDZ.&:b6ejz8YM2MeOщ#zʂ SvL?@A.pl`)h2u7XZ)f]q\hXͯChoL7Ldq wXlm#K)_67ϐCE:pY~@Չm/*ƒzv{.TC=!j=TbMp%PT|B9hSHkM}CX%~xrO蜀PNJݭx>T./v}ೝv!Ͳt"O)4) 겡`kvXb  qp$юoHIFR #ʤC3Se| z]9Pd+搂k}/CSg?lBtNXO7Ҹ- B@TKᖦ∾s2\X9ĩ* [WwM!{ZQ~x+HR{̚z&!8PR~`oQ?}fiZnyT[$X^>~fƉ#cBuLsVJcLSS TӷecLpتߎ_"[|GI.v8))1/N"n?k܎0l#/޽5@x ~r]dLZWCb%`KuQ8&]}[A'ιUUƆ ہn+2}G;.'qOּRxbfSIS.뀎jPDZ3Ӝ4-BcFWc&v0MINE Gr+]r&/K@kiVyWFM¼d9JQtH@6??q[x1t_X7>1O/QՒZaJ)FYl,[+/S2K1k湧iRi؀H:2.UNDanYʼn/ak8PRU,Kٲ1.=ʚU 3c\WLN _"pۑ7>&ѪV'z:45*rx{b&9.7yomkWk8`A3+K{A`ka,\CȻ6Lvx  EY*j%L,FLgitJtqRE Z1"<B;A0ugxR bכ oʱN!K]('xK_]F0nP(&GόqLP#U. &z| 5hC-5,JD%Y'Ҽyf6xl|yHl& Eyfq"rpؙt|NUDg:)Ljvf"g)ŝ>}x溄rb?@*UE=$ ߨI`?*˗ڢ5iE"|zP SDɎ\4fS?{+x {ee F?JT]^.}dߢ 'WkQr,ꂴ BhօSUPC0iwLn a$/M4+M`7]Op+ N)I@$Jjo,gr?C,I{?n֟+ F;z!dԠqq|P$-&Uܦn)*EotK>:jCΚN9jv(۱}B XR(BP3'- D\Z+-nNnvYJF;m1E C>mӯ+W/[3NWNherct4?P~Cebfǫ^oˉK^Ly6hf^ b#mog;c ;;z Q?N fáub?637l,7>e0?0>:9x_iek}TTW74' `W:-"܎7tؘD|?yu(ePA/ aYP}}NGExGJN0dFP !<ъ0 ɞmN"գ\> vy :9{)[\h]pߙWGx7rW؊@YQIRE{lֈ!B8y aBv0mwvù-h:ր`5.֭ -,'72jrF :*/y߲#C>R?q ek$jZ|ydZҺN.[dNY@LkcX+^~Ҥ]eL7z"5ɩh۹,0+v25`KDtlwØżH#sk@Tqa]$Z:a~0 d3ú%e iׅg#!ڶ)}hc"h4; \bJЁ>J2v_ v4zkU0Uak 1_݃["'25]:7l|6CGdZA+eNA2i%!gA83EVUL=G'Ym\,^30rHAX5*"9\oXe}a| =݋Wɀ-!'.T77NnoʦCe0MHz,hiC 㐩Ldimznz_V#+ɳӽCDx2@̽nTaB.FsT5FMoɭߴT@I'4^s^_!$%i&j7-sb9m)kl9Iw(>)Y{ ٜS\e[W <*Űi8=dm{ rwe^ږߺ!M0I Kǟ)%0CW8ǽyaN.*F` ]G;2kcIr%CD}gI=e; 14IÛLc`rm]lrB3[/u2<,{< θJ_͘dHPѩ2jS}*@4iͫR4f(OQ {iX~rPV~yCa#l&)C\| qcW1;!@Mdj2m 9(o<Q+ėUn (ι::y׃A,wؐ%h5)S3}sF|9"Rplةg:?z$Ąv}ꭵ!1+<;Q.~JhxL>3*:](Y( ]q_]I}7 :*T`AfN4f픸`^qhKX{;X^9hȆF'9x&¿N@ۺ&j3<гQLM&U9졄 Vp*$DiANq*vE]ŴhB~ [̚Y4`fl؉ha:A.s~/8 VMH WdwFPl"z.`bE)icSAp-#R xgoxitwUC@'N^箯NFCHGC7$p:QU"N!OLJJ, #xB &o\$hϛ HԨb/@vi+3;1~_̓pb㧚D^S)x(ҩD-z|7#n ?IJbk}9SF/Y Lxtn1wVyl %,p "Oӻ< 9zI)C3z)ho. 7p>smYpXE~շ(qmY 07CJw\Գ߀{0usc5.(_?YacG$E`RMf|瘣N G`M@}g!d4-XN=m,ma4gȶ6yo>ZKa(]plgj6LF"5۟0 PO' *nťf6טhFF' ]6|',&{BFQ!c`R[[`8':o9<6s:X &!;;HHkϼ~D3bFoH4Q8`gcZWmNtS̒suG@&öX8 }}̈? Ioo6sLT?ϱlGVxlÿhcueft[[1CO=R::-cVu 2Us 4H݄}#%GlWh|tjSVrlPH'#&ȁ.lx~sU* \"/Z9~+V2(p[j@|"Ⴣ lsTrS|`K_Ifm2_mY%.٧Xb e=̌]OKjBe=uslX3MFtGCQ9o#ju>.uӇ bî{L䓑ІKuˬ;"0xL$LG 1yY6}uH} 9.yB(q)1G$>ƃ6аO<] $O$foN߬@eio>K~=8EnG/ @kff Wa6ҵhnf"Iwm/3f -LRNTD t.>˄~ލV a'(kt!]PyF#C*XdfpSѸEDi[Oѫ̷VTtpW8!t^YhV_sI8b -@"t{%JyK_(Wc9:_U˱~Z`ED x \ԂߝD?[;J*tjHe>G&TkQ7L]X`irM0}14@I ԗ MD645 Y@myxImd]ij\ U~z(_ RRBD(VIE8*(]=ZoaǏ J)SdV"&5=<}ȋ{~@`Gm GŎ`W}tQ |'fUd/ _P*$=2ImSwN[_1{e0=ꇲ3O~_BR};Lm}nϖ>+:wQgU 4`-jz`dFm3XM,#ip$4{ݞВIUtv! #J>8>+!I}F;7jxuˏ;*I`WwX**6P!&48-pS;>G? c%_5Vf$Ng VIbthPӡd3Fcz+R%<~A18J:Y*2AN{ OQ풋;QoװEHeZr؍&xˉ;GGeJeU7m_Z|s*@$oPA%[F=<>xb0A`h%6M.XgMB0Wn8}E 1G43i}zH[Z`Ҿ-^2@yEzmj$)nf^ B),)q qLHg9q<>YBR[hZqxܤK!iLJ%A}fzrw#pC6 ."ܠ!Alg '-C *YIFR"ܱRu_VIzL3 9 xLQ pӓ-r/,H~>QģwڼGFI&vnNd'^{TZ5Ol&nвWKqNIULvIu`HJcFD+QIiH_v#nSC~٨JK2y o0 j"zR;; l"Kbk1*r]w"LP"m{] @ Ĺ0p;`%u@FNc > }u#Lһ a1)GJHřULc 8 |z+rm^wYZFӢ?$@n4HX|* N`Ş fF%]Fv%@Qx1еezh ?!sjqu@iBќ鏸 {ҺOr-NOjUvR!#._c^[«)}^D͹* 1lCJG%&?.JKoa;ʦ axd;G-B@5N+'g JVs B;~rQrwEN U?o@!c"߆ޠoXB,hp'Cb{Wa+K?I)JF&a ?*gn`dӈH|oc@)ˀl&4h$̨_N۝bP%7M2WAh{ki̭JMpdA)3AXĔ"Pc¸$j>Rh۞IҝK'<![.EX[VcZXmdmD4)lċ󩯢xD$+LF9!8J,#7Dhh>A:&YCW "3iArR !n"8D\G^iN*%f4Ռ7hӟ.M>d-~tОUNw\1("FV)=l@K8N.H  -Tmglt/$ n5[$<'$<`;J3X-L5NIB:[{5^<;qߑVЉ;h#, op(`͛D ^;O EHF%xH m*+5 O/㄰b1:@,gޤ|u(%4 ;N''#s5st8۞M]҇36ىA77OfZCy.%`5;1&F`~PI=7¥nBڮ@Zv9==%$s&rZc8!#EiRFvKSEn1C>vFzq.7ʍw)3xRgiQ\\tr >Q# lBml{f}~= i6m $emHI R3u|y|yQh; ͡I?M|ldg~ꚿH)&AZS<1n"|Qw@s7#%XNJ L:x ٪ }<8yF:&ME/
   *     |f|      error
   *     0.01     25 nm
   *     0.02     30 nm
   *     0.05     10 um
   *     0.1     1.5 mm
   *     0.2     300 mm
   * 
* For very eccentric ellipsoids, use GeodesicExact instead. * * The algorithms are described in * - C. F. F. Karney, * * Algorithms for geodesics, * J. Geodesy 87, 43--55 (2013); * DOI: * 10.1007/s00190-012-0578-z; * addenda: * * geod-addenda.html. * . * For more information on geodesics see \ref geodesic. * * Example of use: * \include example-Geodesic.cpp * * GeodSolve is a command-line utility * providing access to the functionality of Geodesic and GeodesicLine. **********************************************************************/ class GEOGRAPHICLIB_EXPORT Geodesic { private: typedef Math::real real; friend class GeodesicLine; static const int nA1_ = GEOGRAPHICLIB_GEODESIC_ORDER; static const int nC1_ = GEOGRAPHICLIB_GEODESIC_ORDER; static const int nC1p_ = GEOGRAPHICLIB_GEODESIC_ORDER; static const int nA2_ = GEOGRAPHICLIB_GEODESIC_ORDER; static const int nC2_ = GEOGRAPHICLIB_GEODESIC_ORDER; static const int nA3_ = GEOGRAPHICLIB_GEODESIC_ORDER; static const int nA3x_ = nA3_; static const int nC3_ = GEOGRAPHICLIB_GEODESIC_ORDER; static const int nC3x_ = (nC3_ * (nC3_ - 1)) / 2; static const int nC4_ = GEOGRAPHICLIB_GEODESIC_ORDER; static const int nC4x_ = (nC4_ * (nC4_ + 1)) / 2; // Size for temporary array // nC = max(max(nC1_, nC1p_, nC2_) + 1, max(nC3_, nC4_)) static const int nC_ = GEOGRAPHICLIB_GEODESIC_ORDER + 1; static const unsigned maxit1_ = 20; unsigned maxit2_; real tiny_, tol0_, tol1_, tol2_, tolb_, xthresh_; enum captype { CAP_NONE = 0U, CAP_C1 = 1U<<0, CAP_C1p = 1U<<1, CAP_C2 = 1U<<2, CAP_C3 = 1U<<3, CAP_C4 = 1U<<4, CAP_ALL = 0x1FU, CAP_MASK = CAP_ALL, OUT_ALL = 0x7F80U, OUT_MASK = 0xFF80U, // Includes LONG_UNROLL }; static real SinCosSeries(bool sinp, real sinx, real cosx, const real c[], int n); static real Astroid(real x, real y); real _a, _f, _f1, _e2, _ep2, _n, _b, _c2, _etol2; real _aA3x[nA3x_], _cC3x[nC3x_], _cC4x[nC4x_]; void Lengths(real eps, real sig12, real ssig1, real csig1, real dn1, real ssig2, real csig2, real dn2, real cbet1, real cbet2, unsigned outmask, real& s12s, real& m12a, real& m0, real& M12, real& M21, real Ca[]) const; real InverseStart(real sbet1, real cbet1, real dn1, real sbet2, real cbet2, real dn2, real lam12, real slam12, real clam12, real& salp1, real& calp1, real& salp2, real& calp2, real& dnm, real Ca[]) const; real Lambda12(real sbet1, real cbet1, real dn1, real sbet2, real cbet2, real dn2, real salp1, real calp1, real slam120, real clam120, real& salp2, real& calp2, real& sig12, real& ssig1, real& csig1, real& ssig2, real& csig2, real& eps, real& domg12, bool diffp, real& dlam12, real Ca[]) const; real GenInverse(real lat1, real lon1, real lat2, real lon2, unsigned outmask, real& s12, real& salp1, real& calp1, real& salp2, real& calp2, real& m12, real& M12, real& M21, real& S12) const; // These are Maxima generated functions to provide series approximations to // the integrals for the ellipsoidal geodesic. static real A1m1f(real eps); static void C1f(real eps, real c[]); static void C1pf(real eps, real c[]); static real A2m1f(real eps); static void C2f(real eps, real c[]); void A3coeff(); real A3f(real eps) const; void C3coeff(); void C3f(real eps, real c[]) const; void C4coeff(); void C4f(real k2, real c[]) const; public: /** * Bit masks for what calculations to do. These masks do double duty. * They signify to the GeodesicLine constructor and to * Geodesic::Line what capabilities should be included in the GeodesicLine * object. They also specify which results to return in the general * routines Geodesic::GenDirect and Geodesic::GenInverse routines. * GeodesicLine::mask is a duplication of this enum. **********************************************************************/ enum mask { /** * No capabilities, no output. * @hideinitializer **********************************************************************/ NONE = 0U, /** * Calculate latitude \e lat2. (It's not necessary to include this as a * capability to GeodesicLine because this is included by default.) * @hideinitializer **********************************************************************/ LATITUDE = 1U<<7 | CAP_NONE, /** * Calculate longitude \e lon2. * @hideinitializer **********************************************************************/ LONGITUDE = 1U<<8 | CAP_C3, /** * Calculate azimuths \e azi1 and \e azi2. (It's not necessary to * include this as a capability to GeodesicLine because this is included * by default.) * @hideinitializer **********************************************************************/ AZIMUTH = 1U<<9 | CAP_NONE, /** * Calculate distance \e s12. * @hideinitializer **********************************************************************/ DISTANCE = 1U<<10 | CAP_C1, /** * A combination of the common capabilities: Geodesic::LATITUDE, * Geodesic::LONGITUDE, Geodesic::AZIMUTH, Geodesic::DISTANCE. * @hideinitializer **********************************************************************/ STANDARD = LATITUDE | LONGITUDE | AZIMUTH | DISTANCE, /** * Allow distance \e s12 to be used as input in the direct geodesic * problem. * @hideinitializer **********************************************************************/ DISTANCE_IN = 1U<<11 | CAP_C1 | CAP_C1p, /** * Calculate reduced length \e m12. * @hideinitializer **********************************************************************/ REDUCEDLENGTH = 1U<<12 | CAP_C1 | CAP_C2, /** * Calculate geodesic scales \e M12 and \e M21. * @hideinitializer **********************************************************************/ GEODESICSCALE = 1U<<13 | CAP_C1 | CAP_C2, /** * Calculate area \e S12. * @hideinitializer **********************************************************************/ AREA = 1U<<14 | CAP_C4, /** * Unroll \e lon2 in the direct calculation. * @hideinitializer **********************************************************************/ LONG_UNROLL = 1U<<15, /** * All capabilities, calculate everything. (Geodesic::LONG_UNROLL is not * included in this mask.) * @hideinitializer **********************************************************************/ ALL = OUT_ALL| CAP_ALL, }; /** \name Constructor **********************************************************************/ ///@{ /** * Constructor for an ellipsoid with * * @param[in] a equatorial radius (meters). * @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere. * Negative \e f gives a prolate ellipsoid. * @exception GeographicErr if \e a or (1 − \e f) \e a is not * positive. **********************************************************************/ Geodesic(real a, real f); ///@} /** \name Direct geodesic problem specified in terms of distance. **********************************************************************/ ///@{ /** * Solve the direct geodesic problem where the length of the geodesic * is specified in terms of distance. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] s12 distance between point 1 and point 2 (meters); it can be * negative. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees). * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] m12 reduced length of geodesic (meters). * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless). * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless). * @param[out] S12 area under the geodesic (meters2). * @return \e a12 arc length of between point 1 and point 2 (degrees). * * \e lat1 should be in the range [−90°, 90°]. The values of * \e lon2 and \e azi2 returned are in the range [−180°, * 180°]. * * If either point is at a pole, the azimuth is defined by keeping the * longitude fixed, writing \e lat = ±(90° − ε), * and taking the limit ε → 0+. An arc length greater that * 180° signifies a geodesic which is not a shortest path. (For a * prolate ellipsoid, an additional condition is necessary for a shortest * path: the longitudinal extent must not exceed of 180°.) * * The following functions are overloaded versions of Geodesic::Direct * which omit some of the output parameters. Note, however, that the arc * length is always computed and returned as the function value. **********************************************************************/ Math::real Direct(real lat1, real lon1, real azi1, real s12, real& lat2, real& lon2, real& azi2, real& m12, real& M12, real& M21, real& S12) const { real t; return GenDirect(lat1, lon1, azi1, false, s12, LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH | GEODESICSCALE | AREA, lat2, lon2, azi2, t, m12, M12, M21, S12); } /** * See the documentation for Geodesic::Direct. **********************************************************************/ Math::real Direct(real lat1, real lon1, real azi1, real s12, real& lat2, real& lon2) const { real t; return GenDirect(lat1, lon1, azi1, false, s12, LATITUDE | LONGITUDE, lat2, lon2, t, t, t, t, t, t); } /** * See the documentation for Geodesic::Direct. **********************************************************************/ Math::real Direct(real lat1, real lon1, real azi1, real s12, real& lat2, real& lon2, real& azi2) const { real t; return GenDirect(lat1, lon1, azi1, false, s12, LATITUDE | LONGITUDE | AZIMUTH, lat2, lon2, azi2, t, t, t, t, t); } /** * See the documentation for Geodesic::Direct. **********************************************************************/ Math::real Direct(real lat1, real lon1, real azi1, real s12, real& lat2, real& lon2, real& azi2, real& m12) const { real t; return GenDirect(lat1, lon1, azi1, false, s12, LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH, lat2, lon2, azi2, t, m12, t, t, t); } /** * See the documentation for Geodesic::Direct. **********************************************************************/ Math::real Direct(real lat1, real lon1, real azi1, real s12, real& lat2, real& lon2, real& azi2, real& M12, real& M21) const { real t; return GenDirect(lat1, lon1, azi1, false, s12, LATITUDE | LONGITUDE | AZIMUTH | GEODESICSCALE, lat2, lon2, azi2, t, t, M12, M21, t); } /** * See the documentation for Geodesic::Direct. **********************************************************************/ Math::real Direct(real lat1, real lon1, real azi1, real s12, real& lat2, real& lon2, real& azi2, real& m12, real& M12, real& M21) const { real t; return GenDirect(lat1, lon1, azi1, false, s12, LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH | GEODESICSCALE, lat2, lon2, azi2, t, m12, M12, M21, t); } ///@} /** \name Direct geodesic problem specified in terms of arc length. **********************************************************************/ ///@{ /** * Solve the direct geodesic problem where the length of the geodesic * is specified in terms of arc length. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] a12 arc length between point 1 and point 2 (degrees); it can * be negative. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees). * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] s12 distance between point 1 and point 2 (meters). * @param[out] m12 reduced length of geodesic (meters). * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless). * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless). * @param[out] S12 area under the geodesic (meters2). * * \e lat1 should be in the range [−90°, 90°]. The values of * \e lon2 and \e azi2 returned are in the range [−180°, * 180°]. * * If either point is at a pole, the azimuth is defined by keeping the * longitude fixed, writing \e lat = ±(90° − ε), * and taking the limit ε → 0+. An arc length greater that * 180° signifies a geodesic which is not a shortest path. (For a * prolate ellipsoid, an additional condition is necessary for a shortest * path: the longitudinal extent must not exceed of 180°.) * * The following functions are overloaded versions of Geodesic::Direct * which omit some of the output parameters. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21, real& S12) const { GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | REDUCEDLENGTH | GEODESICSCALE | AREA, lat2, lon2, azi2, s12, m12, M12, M21, S12); } /** * See the documentation for Geodesic::ArcDirect. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2) const { real t; GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE, lat2, lon2, t, t, t, t, t, t); } /** * See the documentation for Geodesic::ArcDirect. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2, real& azi2) const { real t; GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE | AZIMUTH, lat2, lon2, azi2, t, t, t, t, t); } /** * See the documentation for Geodesic::ArcDirect. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2, real& azi2, real& s12) const { real t; GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE, lat2, lon2, azi2, s12, t, t, t, t); } /** * See the documentation for Geodesic::ArcDirect. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2, real& azi2, real& s12, real& m12) const { real t; GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | REDUCEDLENGTH, lat2, lon2, azi2, s12, m12, t, t, t); } /** * See the documentation for Geodesic::ArcDirect. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2, real& azi2, real& s12, real& M12, real& M21) const { real t; GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | GEODESICSCALE, lat2, lon2, azi2, s12, t, M12, M21, t); } /** * See the documentation for Geodesic::ArcDirect. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21) const { real t; GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | REDUCEDLENGTH | GEODESICSCALE, lat2, lon2, azi2, s12, m12, M12, M21, t); } ///@} /** \name General version of the direct geodesic solution. **********************************************************************/ ///@{ /** * The general direct geodesic problem. Geodesic::Direct and * Geodesic::ArcDirect are defined in terms of this function. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] arcmode boolean flag determining the meaning of the \e * s12_a12. * @param[in] s12_a12 if \e arcmode is false, this is the distance between * point 1 and point 2 (meters); otherwise it is the arc length between * point 1 and point 2 (degrees); it can be negative. * @param[in] outmask a bitor'ed combination of Geodesic::mask values * specifying which of the following parameters should be set. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees). * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] s12 distance between point 1 and point 2 (meters). * @param[out] m12 reduced length of geodesic (meters). * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless). * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless). * @param[out] S12 area under the geodesic (meters2). * @return \e a12 arc length of between point 1 and point 2 (degrees). * * The Geodesic::mask values possible for \e outmask are * - \e outmask |= Geodesic::LATITUDE for the latitude \e lat2; * - \e outmask |= Geodesic::LONGITUDE for the latitude \e lon2; * - \e outmask |= Geodesic::AZIMUTH for the latitude \e azi2; * - \e outmask |= Geodesic::DISTANCE for the distance \e s12; * - \e outmask |= Geodesic::REDUCEDLENGTH for the reduced length \e * m12; * - \e outmask |= Geodesic::GEODESICSCALE for the geodesic scales \e * M12 and \e M21; * - \e outmask |= Geodesic::AREA for the area \e S12; * - \e outmask |= Geodesic::ALL for all of the above; * - \e outmask |= Geodesic::LONG_UNROLL to unroll \e lon2 instead of * wrapping it into the range [−180°, 180°]. * . * The function value \e a12 is always computed and returned and this * equals \e s12_a12 is \e arcmode is true. If \e outmask includes * Geodesic::DISTANCE and \e arcmode is false, then \e s12 = \e s12_a12. * It is not necessary to include Geodesic::DISTANCE_IN in \e outmask; this * is automatically included is \e arcmode is false. * * With the Geodesic::LONG_UNROLL bit set, the quantity \e lon2 − \e * lon1 indicates how many times and in what sense the geodesic encircles * the ellipsoid. **********************************************************************/ Math::real GenDirect(real lat1, real lon1, real azi1, bool arcmode, real s12_a12, unsigned outmask, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21, real& S12) const; ///@} /** \name Inverse geodesic problem. **********************************************************************/ ///@{ /** * Solve the inverse geodesic problem. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] lat2 latitude of point 2 (degrees). * @param[in] lon2 longitude of point 2 (degrees). * @param[out] s12 distance between point 1 and point 2 (meters). * @param[out] azi1 azimuth at point 1 (degrees). * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] m12 reduced length of geodesic (meters). * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless). * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless). * @param[out] S12 area under the geodesic (meters2). * @return \e a12 arc length of between point 1 and point 2 (degrees). * * \e lat1 and \e lat2 should be in the range [−90°, 90°]. * The values of \e azi1 and \e azi2 returned are in the range * [−180°, 180°]. * * If either point is at a pole, the azimuth is defined by keeping the * longitude fixed, writing \e lat = ±(90° − ε), * and taking the limit ε → 0+. * * The solution to the inverse problem is found using Newton's method. If * this fails to converge (this is very unlikely in geodetic applications * but does occur for very eccentric ellipsoids), then the bisection method * is used to refine the solution. * * The following functions are overloaded versions of Geodesic::Inverse * which omit some of the output parameters. Note, however, that the arc * length is always computed and returned as the function value. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& s12, real& azi1, real& azi2, real& m12, real& M12, real& M21, real& S12) const { return GenInverse(lat1, lon1, lat2, lon2, DISTANCE | AZIMUTH | REDUCEDLENGTH | GEODESICSCALE | AREA, s12, azi1, azi2, m12, M12, M21, S12); } /** * See the documentation for Geodesic::Inverse. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& s12) const { real t; return GenInverse(lat1, lon1, lat2, lon2, DISTANCE, s12, t, t, t, t, t, t); } /** * See the documentation for Geodesic::Inverse. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& azi1, real& azi2) const { real t; return GenInverse(lat1, lon1, lat2, lon2, AZIMUTH, t, azi1, azi2, t, t, t, t); } /** * See the documentation for Geodesic::Inverse. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& s12, real& azi1, real& azi2) const { real t; return GenInverse(lat1, lon1, lat2, lon2, DISTANCE | AZIMUTH, s12, azi1, azi2, t, t, t, t); } /** * See the documentation for Geodesic::Inverse. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& s12, real& azi1, real& azi2, real& m12) const { real t; return GenInverse(lat1, lon1, lat2, lon2, DISTANCE | AZIMUTH | REDUCEDLENGTH, s12, azi1, azi2, m12, t, t, t); } /** * See the documentation for Geodesic::Inverse. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& s12, real& azi1, real& azi2, real& M12, real& M21) const { real t; return GenInverse(lat1, lon1, lat2, lon2, DISTANCE | AZIMUTH | GEODESICSCALE, s12, azi1, azi2, t, M12, M21, t); } /** * See the documentation for Geodesic::Inverse. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& s12, real& azi1, real& azi2, real& m12, real& M12, real& M21) const { real t; return GenInverse(lat1, lon1, lat2, lon2, DISTANCE | AZIMUTH | REDUCEDLENGTH | GEODESICSCALE, s12, azi1, azi2, m12, M12, M21, t); } ///@} /** \name General version of inverse geodesic solution. **********************************************************************/ ///@{ /** * The general inverse geodesic calculation. Geodesic::Inverse is defined * in terms of this function. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] lat2 latitude of point 2 (degrees). * @param[in] lon2 longitude of point 2 (degrees). * @param[in] outmask a bitor'ed combination of Geodesic::mask values * specifying which of the following parameters should be set. * @param[out] s12 distance between point 1 and point 2 (meters). * @param[out] azi1 azimuth at point 1 (degrees). * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] m12 reduced length of geodesic (meters). * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless). * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless). * @param[out] S12 area under the geodesic (meters2). * @return \e a12 arc length of between point 1 and point 2 (degrees). * * The Geodesic::mask values possible for \e outmask are * - \e outmask |= Geodesic::DISTANCE for the distance \e s12; * - \e outmask |= Geodesic::AZIMUTH for the latitude \e azi2; * - \e outmask |= Geodesic::REDUCEDLENGTH for the reduced length \e * m12; * - \e outmask |= Geodesic::GEODESICSCALE for the geodesic scales \e * M12 and \e M21; * - \e outmask |= Geodesic::AREA for the area \e S12; * - \e outmask |= Geodesic::ALL for all of the above. * . * The arc length is always computed and returned as the function value. **********************************************************************/ Math::real GenInverse(real lat1, real lon1, real lat2, real lon2, unsigned outmask, real& s12, real& azi1, real& azi2, real& m12, real& M12, real& M21, real& S12) const; ///@} /** \name Interface to GeodesicLine. **********************************************************************/ ///@{ /** * Set up to compute several points on a single geodesic. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] caps bitor'ed combination of Geodesic::mask values * specifying the capabilities the GeodesicLine object should possess, * i.e., which quantities can be returned in calls to * GeodesicLine::Position. * @return a GeodesicLine object. * * \e lat1 should be in the range [−90°, 90°]. * * The Geodesic::mask values are * - \e caps |= Geodesic::LATITUDE for the latitude \e lat2; this is * added automatically; * - \e caps |= Geodesic::LONGITUDE for the latitude \e lon2; * - \e caps |= Geodesic::AZIMUTH for the azimuth \e azi2; this is * added automatically; * - \e caps |= Geodesic::DISTANCE for the distance \e s12; * - \e caps |= Geodesic::REDUCEDLENGTH for the reduced length \e m12; * - \e caps |= Geodesic::GEODESICSCALE for the geodesic scales \e M12 * and \e M21; * - \e caps |= Geodesic::AREA for the area \e S12; * - \e caps |= Geodesic::DISTANCE_IN permits the length of the * geodesic to be given in terms of \e s12; without this capability the * length can only be specified in terms of arc length; * - \e caps |= Geodesic::ALL for all of the above. * . * The default value of \e caps is Geodesic::ALL. * * If the point is at a pole, the azimuth is defined by keeping \e lon1 * fixed, writing \e lat1 = ±(90 − ε), and taking the * limit ε → 0+. **********************************************************************/ GeodesicLine Line(real lat1, real lon1, real azi1, unsigned caps = ALL) const; /** * Define a GeodesicLine in terms of the inverse geodesic problem. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] lat2 latitude of point 2 (degrees). * @param[in] lon2 longitude of point 2 (degrees). * @param[in] caps bitor'ed combination of Geodesic::mask values * specifying the capabilities the GeodesicLine object should possess, * i.e., which quantities can be returned in calls to * GeodesicLine::Position. * @return a GeodesicLine object. * * This function sets point 3 of the GeodesicLine to correspond to point 2 * of the inverse geodesic problem. * * \e lat1 and \e lat2 should be in the range [−90°, 90°]. **********************************************************************/ GeodesicLine InverseLine(real lat1, real lon1, real lat2, real lon2, unsigned caps = ALL) const; /** * Define a GeodesicLine in terms of the direct geodesic problem specified * in terms of distance. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] s12 distance between point 1 and point 2 (meters); it can be * negative. * @param[in] caps bitor'ed combination of Geodesic::mask values * specifying the capabilities the GeodesicLine object should possess, * i.e., which quantities can be returned in calls to * GeodesicLine::Position. * @return a GeodesicLine object. * * This function sets point 3 of the GeodesicLine to correspond to point 2 * of the direct geodesic problem. * * \e lat1 should be in the range [−90°, 90°]. **********************************************************************/ GeodesicLine DirectLine(real lat1, real lon1, real azi1, real s12, unsigned caps = ALL) const; /** * Define a GeodesicLine in terms of the direct geodesic problem specified * in terms of arc length. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] a12 arc length between point 1 and point 2 (degrees); it can * be negative. * @param[in] caps bitor'ed combination of Geodesic::mask values * specifying the capabilities the GeodesicLine object should possess, * i.e., which quantities can be returned in calls to * GeodesicLine::Position. * @return a GeodesicLine object. * * This function sets point 3 of the GeodesicLine to correspond to point 2 * of the direct geodesic problem. * * \e lat1 should be in the range [−90°, 90°]. **********************************************************************/ GeodesicLine ArcDirectLine(real lat1, real lon1, real azi1, real a12, unsigned caps = ALL) const; /** * Define a GeodesicLine in terms of the direct geodesic problem specified * in terms of either distance or arc length. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] arcmode boolean flag determining the meaning of the \e * s12_a12. * @param[in] s12_a12 if \e arcmode is false, this is the distance between * point 1 and point 2 (meters); otherwise it is the arc length between * point 1 and point 2 (degrees); it can be negative. * @param[in] caps bitor'ed combination of Geodesic::mask values * specifying the capabilities the GeodesicLine object should possess, * i.e., which quantities can be returned in calls to * GeodesicLine::Position. * @return a GeodesicLine object. * * This function sets point 3 of the GeodesicLine to correspond to point 2 * of the direct geodesic problem. * * \e lat1 should be in the range [−90°, 90°]. **********************************************************************/ GeodesicLine GenDirectLine(real lat1, real lon1, real azi1, bool arcmode, real s12_a12, unsigned caps = ALL) const; ///@} /** \name Inspector functions. **********************************************************************/ ///@{ /** * @return \e a the equatorial radius of the ellipsoid (meters). This is * the value used in the constructor. **********************************************************************/ Math::real EquatorialRadius() const { return _a; } /** * @return \e f the flattening of the ellipsoid. This is the * value used in the constructor. **********************************************************************/ Math::real Flattening() const { return _f; } /** * @return total area of ellipsoid in meters2. The area of a * polygon encircling a pole can be found by adding * Geodesic::EllipsoidArea()/2 to the sum of \e S12 for each side of the * polygon. **********************************************************************/ Math::real EllipsoidArea() const { return 4 * Math::pi() * _c2; } ///@} /** * A global instantiation of Geodesic with the parameters for the WGS84 * ellipsoid. **********************************************************************/ static const Geodesic& WGS84(); }; } // namespace GeographicLib #endif // GEOGRAPHICLIB_GEODESIC_HPP geosphere/src/TransverseMercator.cpp0000644000176200001440000005450714323401055017367 0ustar liggesusers/** * \file TransverseMercator.cpp * \brief Implementation for GeographicLib::TransverseMercator class * * Copyright (c) Charles Karney (2008-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ * * This implementation follows closely JHS 154, ETRS89 - * järjestelmään liittyvät karttaprojektiot, * tasokoordinaatistot ja karttalehtijako (Map projections, plane * coordinates, and map sheet index for ETRS89), published by JUHTA, Finnish * Geodetic Institute, and the National Land Survey of Finland (2006). * * The relevant section is available as the 2008 PDF file * http://docs.jhs-suositukset.fi/jhs-suositukset/JHS154/JHS154_liite1.pdf * * This is a straight transcription of the formulas in this paper with the * following exceptions: * - use of 6th order series instead of 4th order series. This reduces the * error to about 5nm for the UTM range of coordinates (instead of 200nm), * with a speed penalty of only 1%; * - use Newton's method instead of plain iteration to solve for latitude in * terms of isometric latitude in the Reverse method; * - use of Horner's representation for evaluating polynomials and Clenshaw's * method for summing trigonometric series; * - several modifications of the formulas to improve the numerical accuracy; * - evaluating the convergence and scale using the expression for the * projection or its inverse. * * If the preprocessor variable GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER is set * to an integer between 4 and 8, then this specifies the order of the series * used for the forward and reverse transformations. The default value is 6. * (The series accurate to 12th order is given in \ref tmseries.) **********************************************************************/ #include #include "TransverseMercator.h" #if defined(_MSC_VER) // Squelch warnings about enum-float expressions # pragma warning (disable: 5055) #endif namespace GeographicLib { using namespace std; TransverseMercator::TransverseMercator(real a, real f, real k0) : _a(a) , _f(f) , _k0(k0) , _e2(_f * (2 - _f)) , _es((_f < 0 ? -1 : 1) * sqrt(fabs(_e2))) , _e2m(1 - _e2) // _c = sqrt( pow(1 + _e, 1 + _e) * pow(1 - _e, 1 - _e) ) ) // See, for example, Lee (1976), p 100. , _c( sqrt(_e2m) * exp(Math::eatanhe(real(1), _es)) ) , _n(_f / (2 - _f)) { if (!(isfinite(_a) && _a > 0)) throw GeographicErr("Equatorial radius is not positive"); if (!(isfinite(_f) && _f < 1)) throw GeographicErr("Polar semi-axis is not positive"); if (!(isfinite(_k0) && _k0 > 0)) throw GeographicErr("Scale is not positive"); // Generated by Maxima on 2015-05-14 22:55:13-04:00 #if GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER/2 == 2 static const real b1coeff[] = { // b1*(n+1), polynomial in n2 of order 2 1, 16, 64, 64, }; // count = 4 #elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER/2 == 3 static const real b1coeff[] = { // b1*(n+1), polynomial in n2 of order 3 1, 4, 64, 256, 256, }; // count = 5 #elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER/2 == 4 static const real b1coeff[] = { // b1*(n+1), polynomial in n2 of order 4 25, 64, 256, 4096, 16384, 16384, }; // count = 6 #else #error "Bad value for GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER" #endif #if GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 4 static const real alpcoeff[] = { // alp[1]/n^1, polynomial in n of order 3 164, 225, -480, 360, 720, // alp[2]/n^2, polynomial in n of order 2 557, -864, 390, 1440, // alp[3]/n^3, polynomial in n of order 1 -1236, 427, 1680, // alp[4]/n^4, polynomial in n of order 0 49561, 161280, }; // count = 14 #elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 5 static const real alpcoeff[] = { // alp[1]/n^1, polynomial in n of order 4 -635, 328, 450, -960, 720, 1440, // alp[2]/n^2, polynomial in n of order 3 4496, 3899, -6048, 2730, 10080, // alp[3]/n^3, polynomial in n of order 2 15061, -19776, 6832, 26880, // alp[4]/n^4, polynomial in n of order 1 -171840, 49561, 161280, // alp[5]/n^5, polynomial in n of order 0 34729, 80640, }; // count = 20 #elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 6 static const real alpcoeff[] = { // alp[1]/n^1, polynomial in n of order 5 31564, -66675, 34440, 47250, -100800, 75600, 151200, // alp[2]/n^2, polynomial in n of order 4 -1983433, 863232, 748608, -1161216, 524160, 1935360, // alp[3]/n^3, polynomial in n of order 3 670412, 406647, -533952, 184464, 725760, // alp[4]/n^4, polynomial in n of order 2 6601661, -7732800, 2230245, 7257600, // alp[5]/n^5, polynomial in n of order 1 -13675556, 3438171, 7983360, // alp[6]/n^6, polynomial in n of order 0 212378941, 319334400, }; // count = 27 #elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 7 static const real alpcoeff[] = { // alp[1]/n^1, polynomial in n of order 6 1804025, 2020096, -4267200, 2204160, 3024000, -6451200, 4838400, 9676800, // alp[2]/n^2, polynomial in n of order 5 4626384, -9917165, 4316160, 3743040, -5806080, 2620800, 9676800, // alp[3]/n^3, polynomial in n of order 4 -67102379, 26816480, 16265880, -21358080, 7378560, 29030400, // alp[4]/n^4, polynomial in n of order 3 155912000, 72618271, -85060800, 24532695, 79833600, // alp[5]/n^5, polynomial in n of order 2 102508609, -109404448, 27505368, 63866880, // alp[6]/n^6, polynomial in n of order 1 -12282192400LL, 2760926233LL, 4151347200LL, // alp[7]/n^7, polynomial in n of order 0 1522256789, 1383782400, }; // count = 35 #elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 8 static const real alpcoeff[] = { // alp[1]/n^1, polynomial in n of order 7 -75900428, 37884525, 42422016, -89611200, 46287360, 63504000, -135475200, 101606400, 203212800, // alp[2]/n^2, polynomial in n of order 6 148003883, 83274912, -178508970, 77690880, 67374720, -104509440, 47174400, 174182400, // alp[3]/n^3, polynomial in n of order 5 318729724, -738126169, 294981280, 178924680, -234938880, 81164160, 319334400, // alp[4]/n^4, polynomial in n of order 4 -40176129013LL, 14967552000LL, 6971354016LL, -8165836800LL, 2355138720LL, 7664025600LL, // alp[5]/n^5, polynomial in n of order 3 10421654396LL, 3997835751LL, -4266773472LL, 1072709352, 2490808320LL, // alp[6]/n^6, polynomial in n of order 2 175214326799LL, -171950693600LL, 38652967262LL, 58118860800LL, // alp[7]/n^7, polynomial in n of order 1 -67039739596LL, 13700311101LL, 12454041600LL, // alp[8]/n^8, polynomial in n of order 0 1424729850961LL, 743921418240LL, }; // count = 44 #else #error "Bad value for GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER" #endif #if GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 4 static const real betcoeff[] = { // bet[1]/n^1, polynomial in n of order 3 -4, 555, -960, 720, 1440, // bet[2]/n^2, polynomial in n of order 2 -437, 96, 30, 1440, // bet[3]/n^3, polynomial in n of order 1 -148, 119, 3360, // bet[4]/n^4, polynomial in n of order 0 4397, 161280, }; // count = 14 #elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 5 static const real betcoeff[] = { // bet[1]/n^1, polynomial in n of order 4 -3645, -64, 8880, -15360, 11520, 23040, // bet[2]/n^2, polynomial in n of order 3 4416, -3059, 672, 210, 10080, // bet[3]/n^3, polynomial in n of order 2 -627, -592, 476, 13440, // bet[4]/n^4, polynomial in n of order 1 -3520, 4397, 161280, // bet[5]/n^5, polynomial in n of order 0 4583, 161280, }; // count = 20 #elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 6 static const real betcoeff[] = { // bet[1]/n^1, polynomial in n of order 5 384796, -382725, -6720, 932400, -1612800, 1209600, 2419200, // bet[2]/n^2, polynomial in n of order 4 -1118711, 1695744, -1174656, 258048, 80640, 3870720, // bet[3]/n^3, polynomial in n of order 3 22276, -16929, -15984, 12852, 362880, // bet[4]/n^4, polynomial in n of order 2 -830251, -158400, 197865, 7257600, // bet[5]/n^5, polynomial in n of order 1 -435388, 453717, 15966720, // bet[6]/n^6, polynomial in n of order 0 20648693, 638668800, }; // count = 27 #elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 7 static const real betcoeff[] = { // bet[1]/n^1, polynomial in n of order 6 -5406467, 6156736, -6123600, -107520, 14918400, -25804800, 19353600, 38707200, // bet[2]/n^2, polynomial in n of order 5 829456, -5593555, 8478720, -5873280, 1290240, 403200, 19353600, // bet[3]/n^3, polynomial in n of order 4 9261899, 3564160, -2708640, -2557440, 2056320, 58060800, // bet[4]/n^4, polynomial in n of order 3 14928352, -9132761, -1742400, 2176515, 79833600, // bet[5]/n^5, polynomial in n of order 2 -8005831, -1741552, 1814868, 63866880, // bet[6]/n^6, polynomial in n of order 1 -261810608, 268433009, 8302694400LL, // bet[7]/n^7, polynomial in n of order 0 219941297, 5535129600LL, }; // count = 35 #elif GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER == 8 static const real betcoeff[] = { // bet[1]/n^1, polynomial in n of order 7 31777436, -37845269, 43097152, -42865200, -752640, 104428800, -180633600, 135475200, 270950400, // bet[2]/n^2, polynomial in n of order 6 24749483, 14930208, -100683990, 152616960, -105719040, 23224320, 7257600, 348364800, // bet[3]/n^3, polynomial in n of order 5 -232468668, 101880889, 39205760, -29795040, -28131840, 22619520, 638668800, // bet[4]/n^4, polynomial in n of order 4 324154477, 1433121792, -876745056, -167270400, 208945440, 7664025600LL, // bet[5]/n^5, polynomial in n of order 3 457888660, -312227409, -67920528, 70779852, 2490808320LL, // bet[6]/n^6, polynomial in n of order 2 -19841813847LL, -3665348512LL, 3758062126LL, 116237721600LL, // bet[7]/n^7, polynomial in n of order 1 -1989295244, 1979471673, 49816166400LL, // bet[8]/n^8, polynomial in n of order 0 191773887257LL, 3719607091200LL, }; // count = 44 #else #error "Bad value for GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER" #endif static_assert(sizeof(b1coeff) / sizeof(real) == maxpow_/2 + 2, "Coefficient array size mismatch for b1"); static_assert(sizeof(alpcoeff) / sizeof(real) == (maxpow_ * (maxpow_ + 3))/2, "Coefficient array size mismatch for alp"); static_assert(sizeof(betcoeff) / sizeof(real) == (maxpow_ * (maxpow_ + 3))/2, "Coefficient array size mismatch for bet"); int m = maxpow_/2; _b1 = Math::polyval(m, b1coeff, Math::sq(_n)) / (b1coeff[m + 1] * (1+_n)); // _a1 is the equivalent radius for computing the circumference of // ellipse. _a1 = _b1 * _a; int o = 0; real d = _n; for (int l = 1; l <= maxpow_; ++l) { m = maxpow_ - l; _alp[l] = d * Math::polyval(m, alpcoeff + o, _n) / alpcoeff[o + m + 1]; _bet[l] = d * Math::polyval(m, betcoeff + o, _n) / betcoeff[o + m + 1]; o += m + 2; d *= _n; } // Post condition: o == sizeof(alpcoeff) / sizeof(real) && // o == sizeof(betcoeff) / sizeof(real) } const TransverseMercator& TransverseMercator::UTM() { static const TransverseMercator utm(Constants::WGS84_a(), Constants::WGS84_f(), Constants::UTM_k0()); return utm; } // Engsager and Poder (2007) use trigonometric series to convert between phi // and phip. Here are the series... // // Conversion from phi to phip: // // phip = phi + sum(c[j] * sin(2*j*phi), j, 1, 6) // // c[1] = - 2 * n // + 2/3 * n^2 // + 4/3 * n^3 // - 82/45 * n^4 // + 32/45 * n^5 // + 4642/4725 * n^6; // c[2] = 5/3 * n^2 // - 16/15 * n^3 // - 13/9 * n^4 // + 904/315 * n^5 // - 1522/945 * n^6; // c[3] = - 26/15 * n^3 // + 34/21 * n^4 // + 8/5 * n^5 // - 12686/2835 * n^6; // c[4] = 1237/630 * n^4 // - 12/5 * n^5 // - 24832/14175 * n^6; // c[5] = - 734/315 * n^5 // + 109598/31185 * n^6; // c[6] = 444337/155925 * n^6; // // Conversion from phip to phi: // // phi = phip + sum(d[j] * sin(2*j*phip), j, 1, 6) // // d[1] = 2 * n // - 2/3 * n^2 // - 2 * n^3 // + 116/45 * n^4 // + 26/45 * n^5 // - 2854/675 * n^6; // d[2] = 7/3 * n^2 // - 8/5 * n^3 // - 227/45 * n^4 // + 2704/315 * n^5 // + 2323/945 * n^6; // d[3] = 56/15 * n^3 // - 136/35 * n^4 // - 1262/105 * n^5 // + 73814/2835 * n^6; // d[4] = 4279/630 * n^4 // - 332/35 * n^5 // - 399572/14175 * n^6; // d[5] = 4174/315 * n^5 // - 144838/6237 * n^6; // d[6] = 601676/22275 * n^6; // // In order to maintain sufficient relative accuracy close to the pole use // // S = sum(c[i]*sin(2*i*phi),i,1,6) // taup = (tau + tan(S)) / (1 - tau * tan(S)) // In Math::taupf and Math::tauf we evaluate the forward transform explicitly // and solve the reverse one by Newton's method. // // There are adapted from TransverseMercatorExact (taup and taupinv). tau = // tan(phi), taup = sinh(psi) void TransverseMercator::Forward(real lon0, real lat, real lon, real& x, real& y, real& gamma, real& k) const { lat = Math::LatFix(lat); lon = Math::AngDiff(lon0, lon); // Explicitly enforce the parity int latsign = signbit(lat) ? -1 : 1, lonsign = signbit(lon) ? -1 : 1; lon *= lonsign; lat *= latsign; bool backside = lon > Math::qd; if (backside) { if (lat == 0) latsign = -1; lon = Math::hd - lon; } real sphi, cphi, slam, clam; Math::sincosd(lat, sphi, cphi); Math::sincosd(lon, slam, clam); // phi = latitude // phi' = conformal latitude // psi = isometric latitude // tau = tan(phi) // tau' = tan(phi') // [xi', eta'] = Gauss-Schreiber TM coordinates // [xi, eta] = Gauss-Krueger TM coordinates // // We use // tan(phi') = sinh(psi) // sin(phi') = tanh(psi) // cos(phi') = sech(psi) // denom^2 = 1-cos(phi')^2*sin(lam)^2 = 1-sech(psi)^2*sin(lam)^2 // sin(xip) = sin(phi')/denom = tanh(psi)/denom // cos(xip) = cos(phi')*cos(lam)/denom = sech(psi)*cos(lam)/denom // cosh(etap) = 1/denom = 1/denom // sinh(etap) = cos(phi')*sin(lam)/denom = sech(psi)*sin(lam)/denom real etap, xip; if (lat != Math::qd) { real tau = sphi / cphi, taup = Math::taupf(tau, _es); xip = atan2(taup, clam); // Used to be // etap = Math::atanh(sin(lam) / cosh(psi)); etap = asinh(slam / hypot(taup, clam)); // convergence and scale for Gauss-Schreiber TM (xip, etap) -- gamma0 = // atan(tan(xip) * tanh(etap)) = atan(tan(lam) * sin(phi')); // sin(phi') = tau'/sqrt(1 + tau'^2) // Krueger p 22 (44) gamma = Math::atan2d(slam * taup, clam * hypot(real(1), taup)); // k0 = sqrt(1 - _e2 * sin(phi)^2) * (cos(phi') / cos(phi)) * cosh(etap) // Note 1/cos(phi) = cosh(psip); // and cos(phi') * cosh(etap) = 1/hypot(sinh(psi), cos(lam)) // // This form has cancelling errors. This property is lost if cosh(psip) // is replaced by 1/cos(phi), even though it's using "primary" data (phi // instead of psip). k = sqrt(_e2m + _e2 * Math::sq(cphi)) * hypot(real(1), tau) / hypot(taup, clam); } else { xip = Math::pi()/2; etap = 0; gamma = lon; k = _c; } // {xi',eta'} is {northing,easting} for Gauss-Schreiber transverse Mercator // (for eta' = 0, xi' = bet). {xi,eta} is {northing,easting} for transverse // Mercator with constant scale on the central meridian (for eta = 0, xip = // rectifying latitude). Define // // zeta = xi + i*eta // zeta' = xi' + i*eta' // // The conversion from conformal to rectifying latitude can be expressed as // a series in _n: // // zeta = zeta' + sum(h[j-1]' * sin(2 * j * zeta'), j = 1..maxpow_) // // where h[j]' = O(_n^j). The reversion of this series gives // // zeta' = zeta - sum(h[j-1] * sin(2 * j * zeta), j = 1..maxpow_) // // which is used in Reverse. // // Evaluate sums via Clenshaw method. See // https://en.wikipedia.org/wiki/Clenshaw_algorithm // // Let // // S = sum(a[k] * phi[k](x), k = 0..n) // phi[k+1](x) = alpha[k](x) * phi[k](x) + beta[k](x) * phi[k-1](x) // // Evaluate S with // // b[n+2] = b[n+1] = 0 // b[k] = alpha[k](x) * b[k+1] + beta[k+1](x) * b[k+2] + a[k] // S = (a[0] + beta[1](x) * b[2]) * phi[0](x) + b[1] * phi[1](x) // // Here we have // // x = 2 * zeta' // phi[k](x) = sin(k * x) // alpha[k](x) = 2 * cos(x) // beta[k](x) = -1 // [ sin(A+B) - 2*cos(B)*sin(A) + sin(A-B) = 0, A = k*x, B = x ] // n = maxpow_ // a[k] = _alp[k] // S = b[1] * sin(x) // // For the derivative we have // // x = 2 * zeta' // phi[k](x) = cos(k * x) // alpha[k](x) = 2 * cos(x) // beta[k](x) = -1 // [ cos(A+B) - 2*cos(B)*cos(A) + cos(A-B) = 0, A = k*x, B = x ] // a[0] = 1; a[k] = 2*k*_alp[k] // S = (a[0] - b[2]) + b[1] * cos(x) // // Matrix formulation (not used here): // phi[k](x) = [sin(k * x); k * cos(k * x)] // alpha[k](x) = 2 * [cos(x), 0; -sin(x), cos(x)] // beta[k](x) = -1 * [1, 0; 0, 1] // a[k] = _alp[k] * [1, 0; 0, 1] // b[n+2] = b[n+1] = [0, 0; 0, 0] // b[k] = alpha[k](x) * b[k+1] + beta[k+1](x) * b[k+2] + a[k] // N.B., for all k: b[k](1,2) = 0; b[k](1,1) = b[k](2,2) // S = (a[0] + beta[1](x) * b[2]) * phi[0](x) + b[1] * phi[1](x) // phi[0](x) = [0; 0] // phi[1](x) = [sin(x); cos(x)] real c0 = cos(2 * xip), ch0 = cosh(2 * etap), s0 = sin(2 * xip), sh0 = sinh(2 * etap); complex a(2 * c0 * ch0, -2 * s0 * sh0); // 2 * cos(2*zeta') int n = maxpow_; complex y0(n & 1 ? _alp[n] : 0), y1, // default initializer is 0+i0 z0(n & 1 ? 2*n * _alp[n] : 0), z1; if (n & 1) --n; while (n) { y1 = a * y0 - y1 + _alp[n]; z1 = a * z0 - z1 + 2*n * _alp[n]; --n; y0 = a * y1 - y0 + _alp[n]; z0 = a * z1 - z0 + 2*n * _alp[n]; --n; } a /= real(2); // cos(2*zeta') z1 = real(1) - z1 + a * z0; a = complex(s0 * ch0, c0 * sh0); // sin(2*zeta') y1 = complex(xip, etap) + a * y0; // Fold in change in convergence and scale for Gauss-Schreiber TM to // Gauss-Krueger TM. gamma -= Math::atan2d(z1.imag(), z1.real()); k *= _b1 * abs(z1); real xi = y1.real(), eta = y1.imag(); y = _a1 * _k0 * (backside ? Math::pi() - xi : xi) * latsign; x = _a1 * _k0 * eta * lonsign; if (backside) gamma = Math::hd - gamma; gamma *= latsign * lonsign; gamma = Math::AngNormalize(gamma); k *= _k0; } void TransverseMercator::Reverse(real lon0, real x, real y, real& lat, real& lon, real& gamma, real& k) const { // This undoes the steps in Forward. The wrinkles are: (1) Use of the // reverted series to express zeta' in terms of zeta. (2) Newton's method // to solve for phi in terms of tan(phi). real xi = y / (_a1 * _k0), eta = x / (_a1 * _k0); // Explicitly enforce the parity int xisign = signbit(xi) ? -1 : 1, etasign = signbit(eta) ? -1 : 1; xi *= xisign; eta *= etasign; bool backside = xi > Math::pi()/2; if (backside) xi = Math::pi() - xi; real c0 = cos(2 * xi), ch0 = cosh(2 * eta), s0 = sin(2 * xi), sh0 = sinh(2 * eta); complex a(2 * c0 * ch0, -2 * s0 * sh0); // 2 * cos(2*zeta) int n = maxpow_; complex y0(n & 1 ? -_bet[n] : 0), y1, // default initializer is 0+i0 z0(n & 1 ? -2*n * _bet[n] : 0), z1; if (n & 1) --n; while (n) { y1 = a * y0 - y1 - _bet[n]; z1 = a * z0 - z1 - 2*n * _bet[n]; --n; y0 = a * y1 - y0 - _bet[n]; z0 = a * z1 - z0 - 2*n * _bet[n]; --n; } a /= real(2); // cos(2*zeta) z1 = real(1) - z1 + a * z0; a = complex(s0 * ch0, c0 * sh0); // sin(2*zeta) y1 = complex(xi, eta) + a * y0; // Convergence and scale for Gauss-Schreiber TM to Gauss-Krueger TM. gamma = Math::atan2d(z1.imag(), z1.real()); k = _b1 / abs(z1); // JHS 154 has // // phi' = asin(sin(xi') / cosh(eta')) (Krueger p 17 (25)) // lam = asin(tanh(eta') / cos(phi') // psi = asinh(tan(phi')) real xip = y1.real(), etap = y1.imag(), s = sinh(etap), c = fmax(real(0), cos(xip)), // cos(pi/2) might be negative r = hypot(s, c); if (r != 0) { lon = Math::atan2d(s, c); // Krueger p 17 (25) // Use Newton's method to solve for tau real sxip = sin(xip), tau = Math::tauf(sxip/r, _es); gamma += Math::atan2d(sxip * tanh(etap), c); // Krueger p 19 (31) lat = Math::atand(tau); // Note cos(phi') * cosh(eta') = r k *= sqrt(_e2m + _e2 / (1 + Math::sq(tau))) * hypot(real(1), tau) * r; } else { lat = Math::qd; lon = 0; k *= _c; } lat *= xisign; if (backside) lon = Math::hd - lon; lon *= etasign; lon = Math::AngNormalize(lon + lon0); if (backside) gamma = Math::hd - gamma; gamma *= xisign * etasign; gamma = Math::AngNormalize(gamma); k *= _k0; } } // namespace GeographicLib geosphere/src/a_util.c0000644000176200001440000000116114161543551014447 0ustar liggesusers#include #ifndef M_PI #define M_PI (3.1415926535897932384626433) #endif #ifndef M_2PI #define M_2PI (3.1415926535897932384626433 * 2.0) #endif #ifndef M_PI_2 #define M_PI_2 (3.1415926535897932384626433 / 2) #endif double mod(double x, double n) { return(x - n * floor(x/n)); } double normalizeLonDeg(double lon) { return( mod( (lon + 180), 360 ) - 180 ); } double normalizeLonRad(double lon) { return( mod( (lon + M_PI), M_2PI) - M_PI); } /* Convert degrees to radians */ double toRad(double deg) { return deg * 0.0174532925199433; } double toDeg(double rad) { return rad * 57.2957795130823 ; } geosphere/src/GeodesicExact.cpp0000644000176200001440000016340114323377375016260 0ustar liggesusers/** * \file GeodesicExact.cpp * \brief Implementation for GeographicLib::GeodesicExact class * * Copyright (c) Charles Karney (2012-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ * * This is a reformulation of the geodesic problem. The notation is as * follows: * - at a general point (no suffix or 1 or 2 as suffix) * - phi = latitude * - beta = latitude on auxiliary sphere * - omega = longitude on auxiliary sphere * - lambda = longitude * - alpha = azimuth of great circle * - sigma = arc length along great circle * - s = distance * - tau = scaled distance (= sigma at multiples of pi/2) * - at northwards equator crossing * - beta = phi = 0 * - omega = lambda = 0 * - alpha = alpha0 * - sigma = s = 0 * - a 12 suffix means a difference, e.g., s12 = s2 - s1. * - s and c prefixes mean sin and cos **********************************************************************/ #include "GeodesicExact.h" #include "GeodesicLineExact.h" #if defined(_MSC_VER) // Squelch warnings about potentially uninitialized local variables, // constant conditional and enum-float expressions and mixing enums # pragma warning (disable: 4701 4127 5055 5054) #endif namespace GeographicLib { using namespace std; GeodesicExact::GeodesicExact(real a, real f) : maxit2_(maxit1_ + Math::digits() + 10) // Underflow guard. We require // tiny_ * epsilon() > 0 // tiny_ + epsilon() == epsilon() , tiny_(sqrt(numeric_limits::min())) , tol0_(numeric_limits::epsilon()) // Increase multiplier in defn of tol1_ from 100 to 200 to fix inverse // case 52.784459512564 0 -52.784459512563990912 179.634407464943777557 // which otherwise failed for Visual Studio 10 (Release and Debug) , tol1_(200 * tol0_) , tol2_(sqrt(tol0_)) , tolb_(tol0_) // Check on bisection interval , xthresh_(1000 * tol2_) , _a(a) , _f(f) , _f1(1 - _f) , _e2(_f * (2 - _f)) , _ep2(_e2 / Math::sq(_f1)) // e2 / (1 - e2) , _n(_f / ( 2 - _f)) , _b(_a * _f1) // The Geodesic class substitutes atanh(sqrt(e2)) for asinh(sqrt(ep2)) in // the definition of _c2. The latter is more accurate for very oblate // ellipsoids (which the Geodesic class does not attempt to handle). , _c2((Math::sq(_a) + Math::sq(_b) * (_f == 0 ? 1 : (_f > 0 ? asinh(sqrt(_ep2)) : atan(sqrt(-_e2))) / sqrt(fabs(_e2))))/2) // authalic radius squared // The sig12 threshold for "really short". Using the auxiliary sphere // solution with dnm computed at (bet1 + bet2) / 2, the relative error in // the azimuth consistency check is sig12^2 * abs(f) * min(1, 1-f/2) / 2. // (Error measured for 1/100 < b/a < 100 and abs(f) >= 1/1000. For a // given f and sig12, the max error occurs for lines near the pole. If // the old rule for computing dnm = (dn1 + dn2)/2 is used, then the error // increases by a factor of 2.) Setting this equal to epsilon gives // sig12 = etol2. Here 0.1 is a safety factor (error decreased by 100) // and max(0.001, abs(f)) stops etol2 getting too large in the nearly // spherical case. , _etol2(real(0.1) * tol2_ / sqrt( fmax(real(0.001), fabs(_f)) * fmin(real(1), 1 - _f/2) / 2 )) { if (!(isfinite(_a) && _a > 0)) throw GeographicErr("Equatorial radius is not positive"); if (!(isfinite(_b) && _b > 0)) throw GeographicErr("Polar semi-axis is not positive"); // Required number of terms in DST for full accuracy for all precisions as // a function of n in [-0.99, 0.99]. Values determined by running // develop/AreaEst compiled with GEOGRAPHICLIB_PRECISION = 5. For // precision 4 and 5, GEOGRAPHICLIB_DIGITS was set to, resp., 384 and 768. // The error criterion is relative error less than or equal to epsilon/2 = // 0.5^digits, with digits = 24, 53, 64, 113, 256. The first 4 are the the // "standard" values for float, double, long double, and float128; the last // is the default for GeographicLib + mpfr. Also listed is the value of // alp0 resulting in the most error for the given N. // // float double long double quad mpfr // n N alp0 N alp0 N alp0 N alp0 N alp0 // -0.99 1024 0.09 3072 0.05 4096 0.04 8192 43.50 16384 22.01 // -0.98 512 0.18 1536 0.10 2048 0.09 4096 0.06 8192 0.04 // -0.97 384 0.25 1024 0.16 1536 0.13 3072 0.09 6144 0.06 // -0.96 256 0.36 768 0.21 1024 0.18 2048 0.13 4096 0.09 // -0.95 192 0.47 768 0.23 768 0.23 1536 0.17 4096 0.10 // -0.94 192 0.51 512 0.31 768 0.26 1536 0.18 3072 0.13 // -0.93 192 0.55 384 0.39 512 0.34 1024 0.24 3072 0.14 // -0.92 128 0.73 384 0.42 512 0.37 1024 0.26 2048 0.18 // -0.91 128 0.77 384 0.45 384 0.45 768 0.32 2048 0.19 // -0.90 96 0.94 256 0.58 384 0.47 768 0.34 2048 0.21 // -0.89 96 0.99 256 0.61 384 0.50 768 0.35 1536 0.25 // -0.88 96 1.04 256 0.64 384 0.52 768 0.37 1536 0.26 // -0.87 96 1.09 192 0.77 256 0.67 512 0.47 1536 0.27 // -0.86 64 1.38 192 0.80 256 0.69 512 0.49 1536 0.28 // -0.85 64 1.43 192 0.83 256 0.72 512 0.51 1024 0.36 // -0.84 64 1.49 192 0.86 256 0.75 384 0.61 1024 0.37 // -0.83 64 1.54 192 0.89 192 0.89 384 0.63 1024 0.39 // -0.82 48 1.82 192 0.92 192 0.92 384 0.65 1024 0.40 // -0.81 48 1.88 128 1.16 192 0.95 384 0.67 1024 0.41 // -0.80 48 1.94 128 1.19 192 0.97 384 0.69 768 0.49 // -0.79 48 1.99 128 1.23 192 1.00 384 0.71 768 0.50 // -0.78 48 2.04 128 1.26 192 1.03 384 0.73 768 0.51 // -0.77 48 2.10 128 1.29 192 1.05 256 0.91 768 0.53 // -0.76 48 2.15 128 1.32 128 1.32 256 0.93 768 0.54 // -0.75 48 2.20 96 1.56 128 1.35 256 0.96 768 0.55 // -0.74 32 2.74 96 1.60 128 1.38 256 0.98 768 0.57 // -0.73 32 2.81 96 1.63 128 1.41 256 1.00 768 0.58 // -0.72 32 2.87 96 1.67 128 1.44 256 1.02 512 0.72 // -0.71 32 2.93 96 1.70 128 1.47 192 1.20 512 0.74 // -0.70 32 2.99 96 1.73 96 1.73 192 1.23 512 0.75 // -0.69 32 3.05 96 1.77 96 1.77 192 1.25 512 0.77 // -0.68 32 3.11 96 1.80 96 1.80 192 1.28 512 0.78 // -0.67 24 3.64 96 1.84 96 1.84 192 1.30 512 0.80 // -0.66 24 3.71 96 1.87 96 1.87 192 1.32 512 0.81 // -0.65 24 3.77 64 2.33 96 1.90 192 1.35 384 0.95 // -0.64 24 3.84 64 2.37 96 1.93 192 1.37 384 0.97 // -0.63 24 3.90 64 2.41 96 1.97 192 1.39 384 0.98 // -0.62 24 3.97 64 2.45 96 2.00 192 1.42 384 1.00 // -0.61 24 4.04 64 2.49 96 2.03 192 1.44 384 1.02 // -0.60 24 4.10 64 2.53 96 2.06 192 1.46 384 1.03 // -0.59 24 4.16 64 2.57 64 2.57 128 1.82 384 1.05 // -0.58 24 4.23 64 2.60 64 2.60 128 1.84 384 1.07 // -0.57 24 4.29 48 3.05 64 2.64 128 1.87 384 1.08 // -0.56 24 4.36 48 3.10 64 2.68 128 1.90 384 1.10 // -0.55 16 5.38 48 3.14 64 2.72 128 1.93 384 1.11 // -0.54 16 5.46 48 3.19 64 2.76 128 1.96 384 1.13 // -0.53 16 5.54 48 3.23 64 2.80 128 1.98 256 1.40 // -0.52 16 5.61 48 3.27 64 2.84 128 2.01 256 1.42 // -0.51 16 5.69 48 3.32 64 2.88 128 2.04 256 1.44 // -0.50 16 5.77 48 3.36 64 2.92 96 2.38 256 1.46 // -0.49 16 5.85 48 3.41 48 3.41 96 2.42 256 1.48 // -0.48 16 5.92 48 3.45 48 3.45 96 2.45 256 1.50 // -0.47 16 6.00 48 3.50 48 3.50 96 2.48 256 1.52 // -0.46 16 6.08 48 3.54 48 3.54 96 2.51 256 1.54 // -0.45 12 7.06 48 3.59 48 3.59 96 2.54 256 1.56 // -0.44 12 7.15 48 3.63 48 3.63 96 2.57 256 1.58 // -0.43 12 7.24 32 4.49 48 3.68 96 2.61 256 1.60 // -0.42 12 7.33 32 4.55 48 3.72 96 2.64 192 1.87 // -0.41 12 7.42 32 4.60 48 3.77 96 2.67 192 1.89 // -0.40 12 7.51 32 4.66 48 3.81 96 2.70 192 1.91 // -0.39 12 7.60 32 4.71 48 3.86 96 2.73 192 1.94 // -0.38 12 7.69 32 4.77 48 3.90 96 2.77 192 1.96 // -0.37 12 7.77 32 4.82 48 3.95 96 2.80 192 1.98 // -0.36 12 7.86 32 4.88 48 3.99 96 2.83 192 2.00 // -0.35 12 7.95 32 4.94 32 4.94 64 3.50 192 2.03 // -0.34 12 8.04 32 4.99 32 4.99 64 3.54 192 2.05 // -0.33 12 8.13 24 5.81 32 5.05 64 3.58 192 2.07 // -0.32 12 8.22 24 5.88 32 5.10 64 3.62 192 2.10 // -0.31 12 8.31 24 5.94 32 5.16 64 3.66 192 2.12 // -0.30 8 10.16 24 6.01 32 5.22 64 3.70 192 2.14 // -0.29 8 10.27 24 6.07 32 5.27 64 3.74 192 2.17 // -0.28 8 10.38 24 6.14 32 5.33 64 3.78 128 2.68 // -0.27 8 10.49 24 6.20 32 5.39 64 3.82 128 2.71 // -0.26 8 10.60 24 6.27 32 5.45 64 3.87 128 2.74 // -0.25 8 10.72 24 6.34 32 5.50 48 4.51 128 2.77 // -0.24 8 10.83 24 6.40 24 6.40 48 4.55 128 2.80 // -0.23 8 10.94 24 6.47 24 6.47 48 4.60 128 2.83 // -0.22 8 11.05 24 6.54 24 6.54 48 4.65 128 2.86 // -0.21 6 12.72 24 6.60 24 6.60 48 4.70 128 2.89 // -0.20 6 12.85 24 6.67 24 6.67 48 4.75 128 2.92 // -0.19 6 12.97 16 8.21 24 6.74 48 4.80 128 2.95 // -0.18 6 13.10 16 8.29 24 6.81 48 4.85 96 3.44 // -0.17 6 13.23 16 8.37 24 6.88 48 4.89 96 3.47 // -0.16 6 13.36 16 8.46 24 6.95 48 4.94 96 3.51 // -0.15 6 13.49 16 8.54 24 7.02 48 5.00 96 3.54 // -0.14 6 13.62 16 8.62 24 7.09 48 5.05 96 3.58 // -0.13 6 13.75 16 8.71 24 7.16 48 5.10 96 3.62 // -0.12 6 13.88 16 8.80 16 8.80 32 6.28 96 3.65 // -0.11 6 14.01 12 10.19 16 8.88 32 6.35 96 3.69 // -0.10 4 16.85 12 10.28 16 8.97 32 6.41 96 3.73 // -0.09 4 17.01 12 10.38 16 9.06 32 6.47 96 3.76 // -0.08 4 17.17 12 10.48 16 9.14 32 6.54 96 3.80 // -0.07 4 17.32 12 10.58 16 9.23 32 6.60 64 4.69 // -0.06 4 17.48 12 10.69 12 10.69 24 7.67 64 4.74 // -0.05 4 17.64 12 10.79 12 10.79 24 7.75 64 4.79 // -0.04 4 17.80 12 10.89 12 10.89 24 7.82 64 4.84 // -0.03 4 17.96 8 13.26 12 10.99 24 7.90 48 5.63 // -0.02 4 18.11 8 13.38 12 11.10 24 7.97 48 5.68 // -0.01 4 18.27 6 15.36 8 13.51 16 9.78 48 5.74 // 0.00 4 1.00 4 1.00 4 1.00 4 1.00 4 1.00 // 0.01 4 18.57 6 15.62 8 13.75 16 9.96 48 5.85 // 0.02 4 18.70 8 13.86 12 11.51 24 8.28 48 5.91 // 0.03 4 18.83 8 13.97 12 11.61 24 8.36 48 5.97 // 0.04 4 18.96 12 11.71 12 11.71 24 8.44 64 5.23 // 0.05 4 19.09 12 11.81 12 11.81 24 8.52 64 5.28 // 0.06 4 19.22 12 11.92 12 11.92 24 8.60 64 5.33 // 0.07 4 19.36 12 12.02 16 10.52 32 7.55 64 5.39 // 0.08 4 19.49 12 12.13 16 10.61 32 7.63 64 5.44 // 0.09 4 19.62 12 12.23 16 10.71 32 7.70 96 4.50 // 0.10 4 19.76 12 12.34 16 10.80 32 7.77 96 4.54 // 0.11 4 19.89 12 12.45 16 10.90 32 7.85 96 4.59 // 0.12 6 17.01 16 11.00 16 11.00 32 7.92 96 4.63 // 0.13 6 17.14 16 11.10 16 11.10 32 8.00 96 4.68 // 0.14 6 17.27 16 11.20 24 9.26 48 6.64 96 4.73 // 0.15 6 17.40 16 11.30 24 9.35 48 6.70 96 4.77 // 0.16 6 17.53 16 11.40 24 9.44 48 6.77 96 4.82 // 0.17 6 17.67 16 11.51 24 9.53 48 6.84 96 4.87 // 0.18 6 17.80 16 11.61 24 9.62 48 6.90 96 4.92 // 0.19 6 17.94 16 11.72 24 9.71 48 6.97 128 4.31 // 0.20 6 18.07 16 11.83 24 9.80 48 7.04 128 4.36 // 0.21 6 18.21 24 9.90 24 9.90 48 7.11 128 4.40 // 0.22 6 18.35 24 9.99 24 9.99 48 7.18 128 4.45 // 0.23 6 18.49 24 10.09 24 10.09 48 7.26 128 4.49 // 0.24 6 18.63 24 10.19 24 10.19 48 7.33 128 4.54 // 0.25 6 18.77 24 10.28 24 10.28 48 7.41 128 4.59 // 0.26 6 18.92 24 10.39 24 10.39 48 7.48 128 4.64 // 0.27 8 17.00 24 10.49 32 9.17 64 6.58 128 4.69 // 0.28 8 17.14 24 10.59 32 9.26 64 6.65 128 4.74 // 0.29 8 17.28 24 10.69 32 9.35 64 6.72 192 3.92 // 0.30 8 17.43 24 10.80 32 9.45 64 6.79 192 3.96 // 0.31 8 17.57 24 10.91 32 9.54 64 6.86 192 4.01 // 0.32 8 17.72 24 11.02 32 9.64 64 6.93 192 4.05 // 0.33 8 17.87 24 11.13 32 9.74 64 7.01 192 4.09 // 0.34 8 18.02 24 11.24 32 9.84 64 7.08 192 4.14 // 0.35 8 18.17 24 11.36 32 9.95 64 7.16 192 4.19 // 0.36 8 18.32 24 11.47 32 10.05 64 7.24 192 4.23 // 0.37 8 18.48 32 10.16 32 10.16 64 7.32 192 4.28 // 0.38 8 18.63 32 10.27 32 10.27 96 6.08 192 4.33 // 0.39 8 18.79 32 10.38 48 8.58 96 6.15 192 4.38 // 0.40 8 18.95 32 10.49 48 8.68 96 6.22 192 4.43 // 0.41 8 19.11 32 10.60 48 8.78 96 6.30 192 4.49 // 0.42 12 16.45 32 10.72 48 8.88 96 6.37 192 4.54 // 0.43 12 16.61 32 10.84 48 8.98 96 6.45 192 4.59 // 0.44 12 16.77 32 10.96 48 9.08 96 6.52 256 4.04 // 0.45 12 16.93 32 11.09 48 9.19 96 6.60 256 4.09 // 0.46 12 17.10 32 11.21 48 9.30 96 6.68 256 4.14 // 0.47 12 17.26 32 11.34 48 9.41 96 6.77 256 4.19 // 0.48 12 17.44 32 11.47 48 9.52 96 6.85 256 4.24 // 0.49 12 17.61 48 9.64 48 9.64 96 6.94 256 4.30 // 0.50 12 17.79 48 9.76 48 9.76 96 7.03 256 4.35 // 0.51 12 17.97 48 9.88 48 9.88 96 7.12 256 4.41 // 0.52 12 18.15 48 10.00 48 10.00 96 7.21 256 4.47 // 0.53 12 18.34 48 10.13 48 10.13 128 6.36 256 4.53 // 0.54 12 18.53 48 10.26 48 10.26 128 6.45 256 4.59 // 0.55 12 18.72 48 10.40 64 9.10 128 6.53 384 3.82 // 0.56 12 18.92 48 10.53 64 9.22 128 6.63 384 3.87 // 0.57 12 19.12 48 10.68 64 9.35 128 6.72 384 3.93 // 0.58 12 19.33 48 10.82 64 9.48 128 6.82 384 3.98 // 0.59 12 19.54 48 10.97 64 9.61 128 6.92 384 4.05 // 0.60 12 19.75 48 11.13 64 9.75 128 7.02 384 4.11 // 0.61 12 19.97 48 11.28 64 9.89 128 7.13 384 4.17 // 0.62 12 20.20 48 11.45 64 10.04 128 7.24 384 4.24 // 0.63 16 18.39 48 11.62 64 10.19 192 6.05 384 4.31 // 0.64 16 18.62 64 10.35 64 10.35 192 6.15 384 4.38 // 0.65 16 18.86 64 10.51 96 8.71 192 6.25 384 4.45 // 0.66 16 19.10 64 10.68 96 8.85 192 6.36 384 4.53 // 0.67 16 19.35 64 10.86 96 9.00 192 6.47 512 4.00 // 0.68 16 19.60 64 11.04 96 9.16 192 6.58 512 4.08 // 0.69 16 19.87 64 11.23 96 9.32 192 6.70 512 4.15 // 0.70 16 20.14 64 11.43 96 9.49 192 6.83 512 4.23 // 0.71 16 20.42 64 11.63 96 9.67 192 6.96 512 4.32 // 0.72 16 20.71 64 11.85 96 9.85 192 7.10 512 4.40 // 0.73 16 21.01 96 10.04 96 10.04 192 7.25 512 4.50 // 0.74 16 21.32 96 10.25 96 10.25 256 6.44 768 3.76 // 0.75 16 21.65 96 10.46 96 10.46 256 6.58 768 3.84 // 0.76 16 21.99 96 10.68 128 9.36 256 6.73 768 3.93 // 0.77 24 19.41 96 10.92 128 9.57 256 6.89 768 4.03 // 0.78 24 19.76 96 11.17 128 9.79 256 7.06 768 4.13 // 0.79 24 20.13 96 11.44 128 10.03 256 7.24 768 4.24 // 0.80 24 20.51 96 11.72 128 10.29 384 6.11 768 4.35 // 0.81 24 20.92 96 12.02 128 10.56 384 6.28 768 4.48 // 0.82 24 21.35 96 12.34 192 8.99 384 6.46 1024 4.00 // 0.83 24 21.81 128 11.16 192 9.26 384 6.66 1024 4.13 // 0.84 24 22.29 128 11.50 192 9.55 384 6.88 1024 4.26 // 0.85 24 22.82 128 11.86 192 9.87 384 7.11 1024 4.41 // 0.86 24 23.38 128 12.26 192 10.21 384 7.37 1024 4.58 // 0.87 24 24.00 128 12.70 192 10.59 512 6.67 1536 3.90 // 0.88 24 24.67 192 11.01 192 11.01 512 6.95 1536 4.06 // 0.89 24 25.41 192 11.48 256 10.07 512 7.26 1536 4.25 // 0.90 24 26.24 192 12.00 256 10.54 768 6.27 1536 4.47 // 0.91 24 27.17 192 12.61 256 11.09 768 6.62 2048 4.10 // 0.92 24 28.23 192 13.30 384 9.74 768 7.02 2048 4.35 // 0.93 24 29.45 256 12.46 384 10.38 768 7.50 3072 3.82 // 0.94 24 30.86 256 13.36 384 11.16 1024 7.05 3072 4.13 // 0.95 24 32.53 384 12.14 512 10.67 1024 7.72 3072 4.53 // 0.96 24 34.51 384 13.42 512 11.83 1536 7.09 4096 4.40 // 0.97 24 36.88 512 13.45 768 11.24 2048 7.11 6144 4.16 // 0.98 16 41.78 768 13.48 1024 11.88 3072 7.12 8192 4.42 // 0.99 8 44.82 1024 16.00 1536 13.51 6144 7.14 16384 4.43 static const int ndiv = 100; // Encode N as small integer: 2,3,4,6,8,12... -> 0,1,2,3,4,5... // using this awk script // // { // n = $1; // if (n % 3 == 0) { // s = 1; // n = n/3; // } else { // s = 0; // n = n/2; // } // p = int( log(n)/log(2)+0.5 ); // printf "%d\n", 2*p+s; // } // // A couple of changes have been made: (1) the decrease in N for float and // n > 0.97 has been removed; (2) entrys of n=+/-1 have been included // (incrementing the previous code value by 1). #if GEOGRAPHICLIB_PRECISION == 1 static const unsigned char narr[2*ndiv+1] = { 19,18,16,15,14,13,13,13,12,12,11,11,11,11,10,10,10,10,9,9,9,9,9,9,9,9,8, 8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8 }; #elif GEOGRAPHICLIB_PRECISION == 2 static const unsigned char narr[2*ndiv+1] = { 22,21,19,18,17,17,16,15,15,15,14,14,14,13,13,13,13,13,13,12,12,12,12,12, 12,11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,7,7,7,7,7,6,6,6,6,6,6, 6,6,5,5,5,5,5,5,5,5,4,4,3,2,3,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,12,12, 12,12,12,13,13,13,13,13,14,14,15,15,16,17,18,19 }; #elif GEOGRAPHICLIB_PRECISION == 3 static const unsigned char narr[2*ndiv+1] = { 23,22,20,19,18,17,17,16,16,15,15,15,15,14,14,14,14,13,13,13,13,13,13,13, 12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10, 10,10,10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7, 7,7,7,7,7,6,6,6,6,6,6,5,5,5,5,5,4,2,4,5,5,5,5,5,6,6,6,6,6,6,6,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,12,12,12, 12,12,12,13,13,13,13,13,13,13,14,14,14,15,15,15,16,16,17,18,19,20 }; #elif GEOGRAPHICLIB_PRECISION == 4 static const unsigned char narr[2*ndiv+1] = { 25,24,22,21,20,19,19,18,18,17,17,17,17,16,16,16,15,15,15,15,15,15,15,14, 14,14,14,14,14,13,13,13,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12, 12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10, 10,10,10,9,9,9,9,9,9,9,9,9,9,9,9,9,8,8,8,8,8,8,7,7,7,7,7,6,2,6,7,7,7,7,7, 8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10, 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12, 12,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,15,15,15,15,15,15, 15,16,16,16,17,17,17,17,18,18,19,20,21,23,24 }; #elif GEOGRAPHICLIB_PRECISION == 5 static const unsigned char narr[2*ndiv+1] = { 27,26,24,23,22,22,21,21,20,20,20,19,19,19,19,18,18,18,18,18,17,17,17,17, 17,17,17,17,16,16,16,16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15,14, 14,14,14,14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13,13,13,13,13,13, 12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,10,10,10, 10,9,9,9,2,9,9,9,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,12,12,12, 12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14, 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16, 16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,19,19,19,19,20,20,21, 21,21,22,23,24,26,27 }; #else #error "Bad value for GEOGRAPHICLIB_PRECISION" #endif real n = ndiv * _n; // n in [-ndiv, ndiv] int j = ndiv + int(n < 0 ? floor(n) : ceil(n)); // j in [0, 2*ndiv] int N = int(narr[j]); // Decode 0,1,2,3,4,5... -> 2,3,4,6,8,12... N = (N % 2 == 0 ? 2 : 3) * (1 << (N/2)); #if GEOGRAPHICLIB_PRECISION == 5 if (Math::digits() > 256) { // Scale up N by the number of digits in the precision relative to // the number used for the test = 256. int M = (Math::digits() * N) / 256; while (N < M) N = N % 3 == 0 ? 4*N/3 : 3*N/2; } #endif _fft.reset(N); _nC4 = N; } const GeodesicExact& GeodesicExact::WGS84() { static const GeodesicExact wgs84(Constants::WGS84_a(), Constants::WGS84_f()); return wgs84; } GeodesicLineExact GeodesicExact::Line(real lat1, real lon1, real azi1, unsigned caps) const { return GeodesicLineExact(*this, lat1, lon1, azi1, caps); } Math::real GeodesicExact::GenDirect(real lat1, real lon1, real azi1, bool arcmode, real s12_a12, unsigned outmask, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21, real& S12) const { // Automatically supply DISTANCE_IN if necessary if (!arcmode) outmask |= DISTANCE_IN; return GeodesicLineExact(*this, lat1, lon1, azi1, outmask) . // Note the dot! GenPosition(arcmode, s12_a12, outmask, lat2, lon2, azi2, s12, m12, M12, M21, S12); } GeodesicLineExact GeodesicExact::GenDirectLine(real lat1, real lon1, real azi1, bool arcmode, real s12_a12, unsigned caps) const { azi1 = Math::AngNormalize(azi1); real salp1, calp1; // Guard against underflow in salp0. Also -0 is converted to +0. Math::sincosd(Math::AngRound(azi1), salp1, calp1); // Automatically supply DISTANCE_IN if necessary if (!arcmode) caps |= DISTANCE_IN; return GeodesicLineExact(*this, lat1, lon1, azi1, salp1, calp1, caps, arcmode, s12_a12); } GeodesicLineExact GeodesicExact::DirectLine(real lat1, real lon1, real azi1, real s12, unsigned caps) const { return GenDirectLine(lat1, lon1, azi1, false, s12, caps); } GeodesicLineExact GeodesicExact::ArcDirectLine(real lat1, real lon1, real azi1, real a12, unsigned caps) const { return GenDirectLine(lat1, lon1, azi1, true, a12, caps); } Math::real GeodesicExact::GenInverse(real lat1, real lon1, real lat2, real lon2, unsigned outmask, real& s12, real& salp1, real& calp1, real& salp2, real& calp2, real& m12, real& M12, real& M21, real& S12) const { // Compute longitude difference (AngDiff does this carefully). Result is // in [-180, 180] but -180 is only for west-going geodesics. 180 is for // east-going and meridional geodesics. using std::isnan; // Needed for Centos 7, ubuntu 14 real lon12s, lon12 = Math::AngDiff(lon1, lon2, lon12s); // Make longitude difference positive. int lonsign = signbit(lon12) ? -1 : 1; lon12 *= lonsign; lon12s *= lonsign; real lam12 = lon12 * Math::degree(), slam12, clam12; // Calculate sincos of lon12 + error (this applies AngRound internally). Math::sincosde(lon12, lon12s, slam12, clam12); // the supplementary longitude difference lon12s = (Math::hd - lon12) - lon12s; // If really close to the equator, treat as on equator. lat1 = Math::AngRound(Math::LatFix(lat1)); lat2 = Math::AngRound(Math::LatFix(lat2)); // Swap points so that point with higher (abs) latitude is point 1 // If one latitude is a nan, then it becomes lat1. int swapp = fabs(lat1) < fabs(lat2) || isnan(lat2) ? -1 : 1; if (swapp < 0) { lonsign *= -1; swap(lat1, lat2); } // Make lat1 <= -0 int latsign = signbit(lat1) ? 1 : -1; lat1 *= latsign; lat2 *= latsign; // Now we have // // 0 <= lon12 <= 180 // -90 <= lat1 <= -0 // lat1 <= lat2 <= -lat1 // // longsign, swapp, latsign register the transformation to bring the // coordinates to this canonical form. In all cases, 1 means no change was // made. We make these transformations so that there are few cases to // check, e.g., on verifying quadrants in atan2. In addition, this // enforces some symmetries in the results returned. real sbet1, cbet1, sbet2, cbet2, s12x, m12x; // Initialize for the meridian. No longitude calculation is done in this // case to let the parameter default to 0. EllipticFunction E(-_ep2); Math::sincosd(lat1, sbet1, cbet1); sbet1 *= _f1; // Ensure cbet1 = +epsilon at poles; doing the fix on beta means that sig12 // will be <= 2*tiny for two points at the same pole. Math::norm(sbet1, cbet1); cbet1 = fmax(tiny_, cbet1); Math::sincosd(lat2, sbet2, cbet2); sbet2 *= _f1; // Ensure cbet2 = +epsilon at poles Math::norm(sbet2, cbet2); cbet2 = fmax(tiny_, cbet2); // If cbet1 < -sbet1, then cbet2 - cbet1 is a sensitive measure of the // |bet1| - |bet2|. Alternatively (cbet1 >= -sbet1), abs(sbet2) + sbet1 is // a better measure. This logic is used in assigning calp2 in Lambda12. // Sometimes these quantities vanish and in that case we force bet2 = +/- // bet1 exactly. An example where is is necessary is the inverse problem // 48.522876735459 0 -48.52287673545898293 179.599720456223079643 // which failed with Visual Studio 10 (Release and Debug) if (cbet1 < -sbet1) { if (cbet2 == cbet1) sbet2 = copysign(sbet1, sbet2); } else { if (fabs(sbet2) == -sbet1) cbet2 = cbet1; } real dn1 = (_f >= 0 ? sqrt(1 + _ep2 * Math::sq(sbet1)) : sqrt(1 - _e2 * Math::sq(cbet1)) / _f1), dn2 = (_f >= 0 ? sqrt(1 + _ep2 * Math::sq(sbet2)) : sqrt(1 - _e2 * Math::sq(cbet2)) / _f1); real a12, sig12; bool meridian = lat1 == -Math::qd || slam12 == 0; if (meridian) { // Endpoints are on a single full meridian, so the geodesic might lie on // a meridian. calp1 = clam12; salp1 = slam12; // Head to the target longitude calp2 = 1; salp2 = 0; // At the target we're heading north real // tan(bet) = tan(sig) * cos(alp) ssig1 = sbet1, csig1 = calp1 * cbet1, ssig2 = sbet2, csig2 = calp2 * cbet2; // sig12 = sig2 - sig1 sig12 = atan2(fmax(real(0), csig1 * ssig2 - ssig1 * csig2), csig1 * csig2 + ssig1 * ssig2); { real dummy; Lengths(E, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2, outmask | REDUCEDLENGTH, s12x, m12x, dummy, M12, M21); } // Add the check for sig12 since zero length geodesics might yield m12 < // 0. Test case was // // echo 20.001 0 20.001 0 | GeodSolve -i // // In fact, we will have sig12 > pi/2 for meridional geodesic which is // not a shortest path. if (sig12 < 1 || m12x >= 0) { // Need at least 2, to handle 90 0 90 180 if (sig12 < 3 * tiny_ || // Prevent negative s12 or m12 for short lines (sig12 < tol0_ && (s12x < 0 || m12x < 0))) sig12 = m12x = s12x = 0; m12x *= _b; s12x *= _b; a12 = sig12 / Math::degree(); } else // m12 < 0, i.e., prolate and too close to anti-podal meridian = false; } // somg12 == 2 marks that it needs to be calculated real omg12 = 0, somg12 = 2, comg12 = 0; if (!meridian && sbet1 == 0 && // and sbet2 == 0 (_f <= 0 || lon12s >= _f * Math::hd)) { // Geodesic runs along equator calp1 = calp2 = 0; salp1 = salp2 = 1; s12x = _a * lam12; sig12 = omg12 = lam12 / _f1; m12x = _b * sin(sig12); if (outmask & GEODESICSCALE) M12 = M21 = cos(sig12); a12 = lon12 / _f1; } else if (!meridian) { // Now point1 and point2 belong within a hemisphere bounded by a // meridian and geodesic is neither meridional or equatorial. // Figure a starting point for Newton's method real dnm; sig12 = InverseStart(E, sbet1, cbet1, dn1, sbet2, cbet2, dn2, lam12, slam12, clam12, salp1, calp1, salp2, calp2, dnm); if (sig12 >= 0) { // Short lines (InverseStart sets salp2, calp2, dnm) s12x = sig12 * _b * dnm; m12x = Math::sq(dnm) * _b * sin(sig12 / dnm); if (outmask & GEODESICSCALE) M12 = M21 = cos(sig12 / dnm); a12 = sig12 / Math::degree(); omg12 = lam12 / (_f1 * dnm); } else { // Newton's method. This is a straightforward solution of f(alp1) = // lambda12(alp1) - lam12 = 0 with one wrinkle. f(alp) has exactly one // root in the interval (0, pi) and its derivative is positive at the // root. Thus f(alp) is positive for alp > alp1 and negative for alp < // alp1. During the course of the iteration, a range (alp1a, alp1b) is // maintained which brackets the root and with each evaluation of // f(alp) the range is shrunk, if possible. Newton's method is // restarted whenever the derivative of f is negative (because the new // value of alp1 is then further from the solution) or if the new // estimate of alp1 lies outside (0,pi); in this case, the new starting // guess is taken to be (alp1a + alp1b) / 2. // // initial values to suppress warnings (if loop is executed 0 times) real ssig1 = 0, csig1 = 0, ssig2 = 0, csig2 = 0, domg12 = 0; unsigned numit = 0; // Bracketing range real salp1a = tiny_, calp1a = 1, salp1b = tiny_, calp1b = -1; for (bool tripn = false, tripb = false;; ++numit) { // 1/4 meridian = 10e6 m and random input. max err is estimated max // error in nm (checking solution of inverse problem by direct // solution). iter is mean and sd of number of iterations // // max iter // log2(b/a) err mean sd // -7 387 5.33 3.68 // -6 345 5.19 3.43 // -5 269 5.00 3.05 // -4 210 4.76 2.44 // -3 115 4.55 1.87 // -2 69 4.35 1.38 // -1 36 4.05 1.03 // 0 15 0.01 0.13 // 1 25 5.10 1.53 // 2 96 5.61 2.09 // 3 318 6.02 2.74 // 4 985 6.24 3.22 // 5 2352 6.32 3.44 // 6 6008 6.30 3.45 // 7 19024 6.19 3.30 real dv; real v = Lambda12(sbet1, cbet1, dn1, sbet2, cbet2, dn2, salp1, calp1, slam12, clam12, salp2, calp2, sig12, ssig1, csig1, ssig2, csig2, E, domg12, numit < maxit1_, dv); if (tripb || // Reversed test to allow escape with NaNs !(fabs(v) >= (tripn ? 8 : 1) * tol0_) || // Enough bisections to get accurate result numit == maxit2_) break; // Update bracketing values if (v > 0 && (numit > maxit1_ || calp1/salp1 > calp1b/salp1b)) { salp1b = salp1; calp1b = calp1; } else if (v < 0 && (numit > maxit1_ || calp1/salp1 < calp1a/salp1a)) { salp1a = salp1; calp1a = calp1; } if (numit < maxit1_ && dv > 0) { real dalp1 = -v/dv; // |dalp1| < pi test moved earlier because GEOGRAPHICLIB_PRECISION // = 5 can result in dalp1 = 10^(10^8). Then sin(dalp1) takes ages // (because of the need to do accurate range reduction). if (fabs(dalp1) < Math::pi()) { real sdalp1 = sin(dalp1), cdalp1 = cos(dalp1), nsalp1 = salp1 * cdalp1 + calp1 * sdalp1; if (nsalp1 > 0) { calp1 = calp1 * cdalp1 - salp1 * sdalp1; salp1 = nsalp1; Math::norm(salp1, calp1); // In some regimes we don't get quadratic convergence because // slope -> 0. So use convergence conditions based on epsilon // instead of sqrt(epsilon). tripn = fabs(v) <= 16 * tol0_; continue; } } } // Either dv was not positive or updated value was outside legal // range. Use the midpoint of the bracket as the next estimate. // This mechanism is not needed for the WGS84 ellipsoid, but it does // catch problems with more eccentric ellipsoids. Its efficacy is // such for the WGS84 test set with the starting guess set to alp1 = // 90deg: // the WGS84 test set: mean = 5.21, sd = 3.93, max = 24 // WGS84 and random input: mean = 4.74, sd = 0.99 salp1 = (salp1a + salp1b)/2; calp1 = (calp1a + calp1b)/2; Math::norm(salp1, calp1); tripn = false; tripb = (fabs(salp1a - salp1) + (calp1a - calp1) < tolb_ || fabs(salp1 - salp1b) + (calp1 - calp1b) < tolb_); } { real dummy; Lengths(E, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2, outmask, s12x, m12x, dummy, M12, M21); } m12x *= _b; s12x *= _b; a12 = sig12 / Math::degree(); if (outmask & AREA) { // omg12 = lam12 - domg12 real sdomg12 = sin(domg12), cdomg12 = cos(domg12); somg12 = slam12 * cdomg12 - clam12 * sdomg12; comg12 = clam12 * cdomg12 + slam12 * sdomg12; } } } if (outmask & DISTANCE) s12 = real(0) + s12x; // Convert -0 to 0 if (outmask & REDUCEDLENGTH) m12 = real(0) + m12x; // Convert -0 to 0 if (outmask & AREA) { real // From Lambda12: sin(alp1) * cos(bet1) = sin(alp0) salp0 = salp1 * cbet1, calp0 = hypot(calp1, salp1 * sbet1); // calp0 > 0 real alp12, // Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0). A4 = Math::sq(_a) * calp0 * salp0 * _e2; if (A4 != 0) { real k2 = Math::sq(calp0) * _ep2, // From Lambda12: tan(bet) = tan(sig) * cos(alp) ssig1 = sbet1, csig1 = calp1 * cbet1, ssig2 = sbet2, csig2 = calp2 * cbet2; Math::norm(ssig1, csig1); Math::norm(ssig2, csig2); I4Integrand i4(_ep2, k2); vector C4a(_nC4); _fft.transform(i4, C4a.data()); real B41 = DST::integral(ssig1, csig1, C4a.data(), _nC4), B42 = DST::integral(ssig2, csig2, C4a.data(), _nC4); S12 = A4 * (B42 - B41); } else // Avoid problems with indeterminate sig1, sig2 on equator S12 = 0; if (!meridian && somg12 == 2) { somg12 = sin(omg12); comg12 = cos(omg12); } if (!meridian && // omg12 < 3/4 * pi comg12 > -real(0.7071) && // Long difference not too big sbet2 - sbet1 < real(1.75)) { // Lat difference not too big // Use tan(Gamma/2) = tan(omg12/2) // * (tan(bet1/2)+tan(bet2/2))/(1+tan(bet1/2)*tan(bet2/2)) // with tan(x/2) = sin(x)/(1+cos(x)) real domg12 = 1 + comg12, dbet1 = 1 + cbet1, dbet2 = 1 + cbet2; alp12 = 2 * atan2( somg12 * ( sbet1 * dbet2 + sbet2 * dbet1 ), domg12 * ( sbet1 * sbet2 + dbet1 * dbet2 ) ); } else { // alp12 = alp2 - alp1, used in atan2 so no need to normalize real salp12 = salp2 * calp1 - calp2 * salp1, calp12 = calp2 * calp1 + salp2 * salp1; // The right thing appears to happen if alp1 = +/-180 and alp2 = 0, viz // salp12 = -0 and alp12 = -180. However this depends on the sign // being attached to 0 correctly. The following ensures the correct // behavior. if (salp12 == 0 && calp12 < 0) { salp12 = tiny_ * calp1; calp12 = -1; } alp12 = atan2(salp12, calp12); } S12 += _c2 * alp12; S12 *= swapp * lonsign * latsign; // Convert -0 to 0 S12 += 0; } // Convert calp, salp to azimuth accounting for lonsign, swapp, latsign. if (swapp < 0) { swap(salp1, salp2); swap(calp1, calp2); if (outmask & GEODESICSCALE) swap(M12, M21); } salp1 *= swapp * lonsign; calp1 *= swapp * latsign; salp2 *= swapp * lonsign; calp2 *= swapp * latsign; // Returned value in [0, 180] return a12; } Math::real GeodesicExact::GenInverse(real lat1, real lon1, real lat2, real lon2, unsigned outmask, real& s12, real& azi1, real& azi2, real& m12, real& M12, real& M21, real& S12) const { outmask &= OUT_MASK; real salp1, calp1, salp2, calp2, a12 = GenInverse(lat1, lon1, lat2, lon2, outmask, s12, salp1, calp1, salp2, calp2, m12, M12, M21, S12); if (outmask & AZIMUTH) { azi1 = Math::atan2d(salp1, calp1); azi2 = Math::atan2d(salp2, calp2); } return a12; } GeodesicLineExact GeodesicExact::InverseLine(real lat1, real lon1, real lat2, real lon2, unsigned caps) const { real t, salp1, calp1, salp2, calp2, a12 = GenInverse(lat1, lon1, lat2, lon2, // No need to specify AZIMUTH here 0u, t, salp1, calp1, salp2, calp2, t, t, t, t), azi1 = Math::atan2d(salp1, calp1); // Ensure that a12 can be converted to a distance if (caps & (OUT_MASK & DISTANCE_IN)) caps |= DISTANCE; return GeodesicLineExact(*this, lat1, lon1, azi1, salp1, calp1, caps, true, a12); } void GeodesicExact::Lengths(const EllipticFunction& E, real sig12, real ssig1, real csig1, real dn1, real ssig2, real csig2, real dn2, real cbet1, real cbet2, unsigned outmask, real& s12b, real& m12b, real& m0, real& M12, real& M21) const { // Return m12b = (reduced length)/_b; also calculate s12b = distance/_b, // and m0 = coefficient of secular term in expression for reduced length. outmask &= OUT_ALL; // outmask & DISTANCE: set s12b // outmask & REDUCEDLENGTH: set m12b & m0 // outmask & GEODESICSCALE: set M12 & M21 // It's OK to have repeated dummy arguments, // e.g., s12b = m0 = M12 = M21 = dummy if (outmask & DISTANCE) // Missing a factor of _b s12b = E.E() / (Math::pi() / 2) * (sig12 + (E.deltaE(ssig2, csig2, dn2) - E.deltaE(ssig1, csig1, dn1))); if (outmask & (REDUCEDLENGTH | GEODESICSCALE)) { real m0x = - E.k2() * E.D() / (Math::pi() / 2), J12 = m0x * (sig12 + (E.deltaD(ssig2, csig2, dn2) - E.deltaD(ssig1, csig1, dn1))); if (outmask & REDUCEDLENGTH) { m0 = m0x; // Missing a factor of _b. Add parens around (csig1 * ssig2) and // (ssig1 * csig2) to ensure accurate cancellation in the case of // coincident points. m12b = dn2 * (csig1 * ssig2) - dn1 * (ssig1 * csig2) - csig1 * csig2 * J12; } if (outmask & GEODESICSCALE) { real csig12 = csig1 * csig2 + ssig1 * ssig2; real t = _ep2 * (cbet1 - cbet2) * (cbet1 + cbet2) / (dn1 + dn2); M12 = csig12 + (t * ssig2 - csig2 * J12) * ssig1 / dn1; M21 = csig12 - (t * ssig1 - csig1 * J12) * ssig2 / dn2; } } } Math::real GeodesicExact::Astroid(real x, real y) { // Solve k^4+2*k^3-(x^2+y^2-1)*k^2-2*y^2*k-y^2 = 0 for positive root k. // This solution is adapted from Geocentric::Reverse. real k; real p = Math::sq(x), q = Math::sq(y), r = (p + q - 1) / 6; if ( !(q == 0 && r <= 0) ) { real // Avoid possible division by zero when r = 0 by multiplying equations // for s and t by r^3 and r, resp. S = p * q / 4, // S = r^3 * s r2 = Math::sq(r), r3 = r * r2, // The discriminant of the quadratic equation for T3. This is zero on // the evolute curve p^(1/3)+q^(1/3) = 1 disc = S * (S + 2 * r3); real u = r; if (disc >= 0) { real T3 = S + r3; // Pick the sign on the sqrt to maximize abs(T3). This minimizes loss // of precision due to cancellation. The result is unchanged because // of the way the T is used in definition of u. T3 += T3 < 0 ? -sqrt(disc) : sqrt(disc); // T3 = (r * t)^3 // N.B. cbrt always returns the real root. cbrt(-8) = -2. real T = cbrt(T3); // T = r * t // T can be zero; but then r2 / T -> 0. u += T + (T != 0 ? r2 / T : 0); } else { // T is complex, but the way u is defined the result is real. real ang = atan2(sqrt(-disc), -(S + r3)); // There are three possible cube roots. We choose the root which // avoids cancellation. Note that disc < 0 implies that r < 0. u += 2 * r * cos(ang / 3); } real v = sqrt(Math::sq(u) + q), // guaranteed positive // Avoid loss of accuracy when u < 0. uv = u < 0 ? q / (v - u) : u + v, // u+v, guaranteed positive w = (uv - q) / (2 * v); // positive? // Rearrange expression for k to avoid loss of accuracy due to // subtraction. Division by 0 not possible because uv > 0, w >= 0. k = uv / (sqrt(uv + Math::sq(w)) + w); // guaranteed positive } else { // q == 0 && r <= 0 // y = 0 with |x| <= 1. Handle this case directly. // for y small, positive root is k = abs(y)/sqrt(1-x^2) k = 0; } return k; } Math::real GeodesicExact::InverseStart(EllipticFunction& E, real sbet1, real cbet1, real dn1, real sbet2, real cbet2, real dn2, real lam12, real slam12, real clam12, real& salp1, real& calp1, // Only updated if return val >= 0 real& salp2, real& calp2, // Only updated for short lines real& dnm) const { // Return a starting point for Newton's method in salp1 and calp1 (function // value is -1). If Newton's method doesn't need to be used, return also // salp2 and calp2 and function value is sig12. real sig12 = -1, // Return value // bet12 = bet2 - bet1 in [0, pi); bet12a = bet2 + bet1 in (-pi, 0] sbet12 = sbet2 * cbet1 - cbet2 * sbet1, cbet12 = cbet2 * cbet1 + sbet2 * sbet1; real sbet12a = sbet2 * cbet1 + cbet2 * sbet1; bool shortline = cbet12 >= 0 && sbet12 < real(0.5) && cbet2 * lam12 < real(0.5); real somg12, comg12; if (shortline) { real sbetm2 = Math::sq(sbet1 + sbet2); // sin((bet1+bet2)/2)^2 // = (sbet1 + sbet2)^2 / ((sbet1 + sbet2)^2 + (cbet1 + cbet2)^2) sbetm2 /= sbetm2 + Math::sq(cbet1 + cbet2); dnm = sqrt(1 + _ep2 * sbetm2); real omg12 = lam12 / (_f1 * dnm); somg12 = sin(omg12); comg12 = cos(omg12); } else { somg12 = slam12; comg12 = clam12; } salp1 = cbet2 * somg12; calp1 = comg12 >= 0 ? sbet12 + cbet2 * sbet1 * Math::sq(somg12) / (1 + comg12) : sbet12a - cbet2 * sbet1 * Math::sq(somg12) / (1 - comg12); real ssig12 = hypot(salp1, calp1), csig12 = sbet1 * sbet2 + cbet1 * cbet2 * comg12; if (shortline && ssig12 < _etol2) { // really short lines salp2 = cbet1 * somg12; calp2 = sbet12 - cbet1 * sbet2 * (comg12 >= 0 ? Math::sq(somg12) / (1 + comg12) : 1 - comg12); Math::norm(salp2, calp2); // Set return value sig12 = atan2(ssig12, csig12); } else if (fabs(_n) > real(0.1) || // Skip astroid calc if too eccentric csig12 >= 0 || ssig12 >= 6 * fabs(_n) * Math::pi() * Math::sq(cbet1)) { // Nothing to do, zeroth order spherical approximation is OK } else { // Scale lam12 and bet2 to x, y coordinate system where antipodal point // is at origin and singular point is at y = 0, x = -1. real x, y, lamscale, betscale; real lam12x = atan2(-slam12, -clam12); // lam12 - pi if (_f >= 0) { // In fact f == 0 does not get here // x = dlong, y = dlat { real k2 = Math::sq(sbet1) * _ep2; E.Reset(-k2, -_ep2, 1 + k2, 1 + _ep2); lamscale = _e2/_f1 * cbet1 * 2 * E.H(); } betscale = lamscale * cbet1; x = lam12x / lamscale; y = sbet12a / betscale; } else { // _f < 0 // x = dlat, y = dlong real cbet12a = cbet2 * cbet1 - sbet2 * sbet1, bet12a = atan2(sbet12a, cbet12a); real m12b, m0, dummy; // In the case of lon12 = 180, this repeats a calculation made in // Inverse. Lengths(E, Math::pi() + bet12a, sbet1, -cbet1, dn1, sbet2, cbet2, dn2, cbet1, cbet2, REDUCEDLENGTH, dummy, m12b, m0, dummy, dummy); x = -1 + m12b / (cbet1 * cbet2 * m0 * Math::pi()); betscale = x < -real(0.01) ? sbet12a / x : -_f * Math::sq(cbet1) * Math::pi(); lamscale = betscale / cbet1; y = lam12x / lamscale; } if (y > -tol1_ && x > -1 - xthresh_) { // strip near cut // Need real(x) here to cast away the volatility of x for min/max if (_f >= 0) { salp1 = fmin(real(1), -x); calp1 = - sqrt(1 - Math::sq(salp1)); } else { calp1 = fmax(real(x > -tol1_ ? 0 : -1), x); salp1 = sqrt(1 - Math::sq(calp1)); } } else { // Estimate alp1, by solving the astroid problem. // // Could estimate alpha1 = theta + pi/2, directly, i.e., // calp1 = y/k; salp1 = -x/(1+k); for _f >= 0 // calp1 = x/(1+k); salp1 = -y/k; for _f < 0 (need to check) // // However, it's better to estimate omg12 from astroid and use // spherical formula to compute alp1. This reduces the mean number of // Newton iterations for astroid cases from 2.24 (min 0, max 6) to 2.12 // (min 0 max 5). The changes in the number of iterations are as // follows: // // change percent // 1 5 // 0 78 // -1 16 // -2 0.6 // -3 0.04 // -4 0.002 // // The histogram of iterations is (m = number of iterations estimating // alp1 directly, n = number of iterations estimating via omg12, total // number of trials = 148605): // // iter m n // 0 148 186 // 1 13046 13845 // 2 93315 102225 // 3 36189 32341 // 4 5396 7 // 5 455 1 // 6 56 0 // // Because omg12 is near pi, estimate work with omg12a = pi - omg12 real k = Astroid(x, y); real omg12a = lamscale * ( _f >= 0 ? -x * k/(1 + k) : -y * (1 + k)/k ); somg12 = sin(omg12a); comg12 = -cos(omg12a); // Update spherical estimate of alp1 using omg12 instead of lam12 salp1 = cbet2 * somg12; calp1 = sbet12a - cbet2 * sbet1 * Math::sq(somg12) / (1 - comg12); } } // Sanity check on starting guess. Backwards check allows NaN through. if (!(salp1 <= 0)) Math::norm(salp1, calp1); else { salp1 = 1; calp1 = 0; } return sig12; } Math::real GeodesicExact::Lambda12(real sbet1, real cbet1, real dn1, real sbet2, real cbet2, real dn2, real salp1, real calp1, real slam120, real clam120, real& salp2, real& calp2, real& sig12, real& ssig1, real& csig1, real& ssig2, real& csig2, EllipticFunction& E, real& domg12, bool diffp, real& dlam12) const { if (sbet1 == 0 && calp1 == 0) // Break degeneracy of equatorial line. This case has already been // handled. calp1 = -tiny_; real // sin(alp1) * cos(bet1) = sin(alp0) salp0 = salp1 * cbet1, calp0 = hypot(calp1, salp1 * sbet1); // calp0 > 0 real somg1, comg1, somg2, comg2, somg12, comg12, cchi1, cchi2, lam12; // tan(bet1) = tan(sig1) * cos(alp1) // tan(omg1) = sin(alp0) * tan(sig1) = tan(omg1)=tan(alp1)*sin(bet1) ssig1 = sbet1; somg1 = salp0 * sbet1; csig1 = comg1 = calp1 * cbet1; // Without normalization we have schi1 = somg1. cchi1 = _f1 * dn1 * comg1; Math::norm(ssig1, csig1); // Math::norm(somg1, comg1); -- don't need to normalize! // Math::norm(schi1, cchi1); -- don't need to normalize! // Enforce symmetries in the case abs(bet2) = -bet1. Need to be careful // about this case, since this can yield singularities in the Newton // iteration. // sin(alp2) * cos(bet2) = sin(alp0) salp2 = cbet2 != cbet1 ? salp0 / cbet2 : salp1; // calp2 = sqrt(1 - sq(salp2)) // = sqrt(sq(calp0) - sq(sbet2)) / cbet2 // and subst for calp0 and rearrange to give (choose positive sqrt // to give alp2 in [0, pi/2]). calp2 = cbet2 != cbet1 || fabs(sbet2) != -sbet1 ? sqrt(Math::sq(calp1 * cbet1) + (cbet1 < -sbet1 ? (cbet2 - cbet1) * (cbet1 + cbet2) : (sbet1 - sbet2) * (sbet1 + sbet2))) / cbet2 : fabs(calp1); // tan(bet2) = tan(sig2) * cos(alp2) // tan(omg2) = sin(alp0) * tan(sig2). ssig2 = sbet2; somg2 = salp0 * sbet2; csig2 = comg2 = calp2 * cbet2; // Without normalization we have schi2 = somg2. cchi2 = _f1 * dn2 * comg2; Math::norm(ssig2, csig2); // Math::norm(somg2, comg2); -- don't need to normalize! // Math::norm(schi2, cchi2); -- don't need to normalize! // sig12 = sig2 - sig1, limit to [0, pi] sig12 = atan2(fmax(real(0), csig1 * ssig2 - ssig1 * csig2), csig1 * csig2 + ssig1 * ssig2); // omg12 = omg2 - omg1, limit to [0, pi] somg12 = fmax(real(0), comg1 * somg2 - somg1 * comg2); comg12 = comg1 * comg2 + somg1 * somg2; real k2 = Math::sq(calp0) * _ep2; E.Reset(-k2, -_ep2, 1 + k2, 1 + _ep2); // chi12 = chi2 - chi1, limit to [0, pi] real schi12 = fmax(real(0), cchi1 * somg2 - somg1 * cchi2), cchi12 = cchi1 * cchi2 + somg1 * somg2; // eta = chi12 - lam120 real eta = atan2(schi12 * clam120 - cchi12 * slam120, cchi12 * clam120 + schi12 * slam120); real deta12 = -_e2/_f1 * salp0 * E.H() / (Math::pi() / 2) * (sig12 + (E.deltaH(ssig2, csig2, dn2) - E.deltaH(ssig1, csig1, dn1))); lam12 = eta + deta12; // domg12 = deta12 + chi12 - omg12 domg12 = deta12 + atan2(schi12 * comg12 - cchi12 * somg12, cchi12 * comg12 + schi12 * somg12); if (diffp) { if (calp2 == 0) dlam12 = - 2 * _f1 * dn1 / sbet1; else { real dummy; Lengths(E, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2, REDUCEDLENGTH, dummy, dlam12, dummy, dummy, dummy); dlam12 *= _f1 / (calp2 * cbet2); } } return lam12; } Math::real GeodesicExact::I4Integrand::asinhsqrt(real x) { // return asinh(sqrt(x))/sqrt(x) using std::sqrt; using std::asinh; using std::asin; return x == 0 ? 1 : (x > 0 ? asinh(sqrt(x))/sqrt(x) : asin(sqrt(-x))/sqrt(-x)); // NaNs end up here } Math::real GeodesicExact::I4Integrand::t(real x) { // This differs by from t as defined following Eq 61 in Karney (2013) by // the final subtraction of 1. This changes nothing since Eq 61 uses the // difference of two evaluations of t and improves the accuracy(?). using std::sqrt; // Group terms to minimize roundoff // with x = ep2, this is the same as // e2/(1-e2) + (atanh(e)/e - 1) return x + (sqrt(1 + x) * asinhsqrt(x) - 1); } Math::real GeodesicExact::I4Integrand::td(real x) { // d t(x) / dx using std::sqrt; return x == 0 ? 4/real(3) : // Group terms to minimize roundoff 1 + (1 - asinhsqrt(x) / sqrt(1+x)) / (2*x); } // Math::real GeodesicExact::I4Integrand::Dt(real x, real y) { // // ( t(x) - t(y) ) / (x - y) // using std::sqrt; using std::fabs; using std::asinh; using std::asin; // if (x == y) return td(x); // if (x * y <= 0) return ( t(x) - t(y) ) / (x - y); // real // sx = sqrt(fabs(x)), sx1 = sqrt(1 + x), // sy = sqrt(fabs(y)), sy1 = sqrt(1 + y), // z = (x - y) / (sx * sy1 + sy * sx1), // d1 = 2 * sx * sy, // d2 = 2 * (x * sy * sy1 + y * sx * sx1); // return x > 0 ? // ( 1 + (asinh(z)/z) / d1 - (asinh(sx) + asinh(sy)) / d2 ) : // // NaNs fall through to here // ( 1 - (asin (z)/z) / d1 - (asin (sx) + asin (sy)) / d2 ); // } Math::real GeodesicExact::I4Integrand::DtX(real y) const { // idiot version: // return ( tX - t(y) ) / (X - y); using std::sqrt; using std::fabs; using std::asinh; using std::asin; if (X == y) return tdX; if (X * y <= 0) return ( tX - t(y) ) / (X - y); real sy = sqrt(fabs(y)), sy1 = sqrt(1 + y), z = (X - y) / (sX * sy1 + sy * sX1), d1 = 2 * sX * sy, d2 = 2 * (X * sy * sy1 + y * sXX1); return X > 0 ? ( 1 + (asinh(z)/z) / d1 - (asinhsX + asinh(sy)) / d2 ) : // NaNs fall through to here ( 1 - (asin (z)/z) / d1 - (asinhsX + asin (sy)) / d2 ); } GeodesicExact::I4Integrand::I4Integrand(real ep2, real k2) : X( ep2 ) , tX( t(X) ) , tdX( td(X) ) , _k2( k2 ) { using std::fabs; using std::sqrt; using std::asinh; using std::asin; sX = sqrt(fabs(X)); // ep sX1 = sqrt(1 + X); // 1/(1-f) sXX1 = sX * sX1; asinhsX = X > 0 ? asinh(sX) : asin(sX); // atanh(e) } Math::real GeodesicExact::I4Integrand::operator()(real sig) const { using std::sin; real ssig = sin(sig); return - DtX(_k2 * Math::sq(ssig)) * ssig/2; } } // namespace GeographicLib geosphere/src/GeodesicLine.h0000644000176200001440000007401414323377037015544 0ustar liggesusers/** * \file GeodesicLine.hpp * \brief Header for GeographicLib::GeodesicLine class * * Copyright (c) Charles Karney (2009-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_GEODESICLINE_HPP) #define GEOGRAPHICLIB_GEODESICLINE_HPP 1 #include "Constants.h" #include "Geodesic.h" namespace GeographicLib { /** * \brief A geodesic line * * GeodesicLine facilitates the determination of a series of points on a * single geodesic. The starting point (\e lat1, \e lon1) and the azimuth \e * azi1 are specified in the constructor; alternatively, the Geodesic::Line * method can be used to create a GeodesicLine. GeodesicLine.Position * returns the location of point 2 a distance \e s12 along the geodesic. In * addition, GeodesicLine.ArcPosition gives the position of point 2 an arc * length \e a12 along the geodesic. * * You can register the position of a reference point 3 a distance (arc * length), \e s13 (\e a13) along the geodesic with the * GeodesicLine.SetDistance (GeodesicLine.SetArc) functions. Points a * fractional distance along the line can be found by providing, for example, * 0.5 * Distance() as an argument to GeodesicLine.Position. The * Geodesic::InverseLine or Geodesic::DirectLine methods return GeodesicLine * objects with point 3 set to the point 2 of the corresponding geodesic * problem. GeodesicLine objects created with the public constructor or with * Geodesic::Line have \e s13 and \e a13 set to NaNs. * * The default copy constructor and assignment operators work with this * class. Similarly, a vector can be used to hold GeodesicLine objects. * * The calculations are accurate to better than 15 nm (15 nanometers). See * Sec. 9 of * arXiv:1102.1215v1 for * details. The algorithms used by this class are based on series expansions * using the flattening \e f as a small parameter. These are only accurate * for |f| < 0.02; however reasonably accurate results will be * obtained for |f| < 0.2. For very eccentric ellipsoids, use * GeodesicLineExact instead. * * The algorithms are described in * - C. F. F. Karney, * * Algorithms for geodesics, * J. Geodesy 87, 43--55 (2013); * DOI: * 10.1007/s00190-012-0578-z; * addenda: * * geod-addenda.html. * . * For more information on geodesics see \ref geodesic. * * Example of use: * \include example-GeodesicLine.cpp * * GeodSolve is a command-line utility * providing access to the functionality of Geodesic and GeodesicLine. **********************************************************************/ class GEOGRAPHICLIB_EXPORT GeodesicLine { private: typedef Math::real real; friend class Geodesic; static const int nC1_ = Geodesic::nC1_; static const int nC1p_ = Geodesic::nC1p_; static const int nC2_ = Geodesic::nC2_; static const int nC3_ = Geodesic::nC3_; static const int nC4_ = Geodesic::nC4_; real tiny_; real _lat1, _lon1, _azi1; real _a, _f, _b, _c2, _f1, _salp0, _calp0, _k2, _salp1, _calp1, _ssig1, _csig1, _dn1, _stau1, _ctau1, _somg1, _comg1, _aA1m1, _aA2m1, _aA3c, _bB11, _bB21, _bB31, _aA4, _bB41; real _a13, _s13; // index zero elements of _cC1a, _cC1pa, _cC2a, _cC3a are unused real _cC1a[nC1_ + 1], _cC1pa[nC1p_ + 1], _cC2a[nC2_ + 1], _cC3a[nC3_], _cC4a[nC4_]; // all the elements of _cC4a are used unsigned _caps; void LineInit(const Geodesic& g, real lat1, real lon1, real azi1, real salp1, real calp1, unsigned caps); GeodesicLine(const Geodesic& g, real lat1, real lon1, real azi1, real salp1, real calp1, unsigned caps, bool arcmode, real s13_a13); enum captype { CAP_NONE = Geodesic::CAP_NONE, CAP_C1 = Geodesic::CAP_C1, CAP_C1p = Geodesic::CAP_C1p, CAP_C2 = Geodesic::CAP_C2, CAP_C3 = Geodesic::CAP_C3, CAP_C4 = Geodesic::CAP_C4, CAP_ALL = Geodesic::CAP_ALL, CAP_MASK = Geodesic::CAP_MASK, OUT_ALL = Geodesic::OUT_ALL, OUT_MASK = Geodesic::OUT_MASK, }; public: /** * Bit masks for what calculations to do. They signify to the * GeodesicLine::GeodesicLine constructor and to Geodesic::Line what * capabilities should be included in the GeodesicLine object. This is * merely a duplication of Geodesic::mask. **********************************************************************/ enum mask { /** * No capabilities, no output. * @hideinitializer **********************************************************************/ NONE = Geodesic::NONE, /** * Calculate latitude \e lat2. (It's not necessary to include this as a * capability to GeodesicLine because this is included by default.) * @hideinitializer **********************************************************************/ LATITUDE = Geodesic::LATITUDE, /** * Calculate longitude \e lon2. * @hideinitializer **********************************************************************/ LONGITUDE = Geodesic::LONGITUDE, /** * Calculate azimuths \e azi1 and \e azi2. (It's not necessary to * include this as a capability to GeodesicLine because this is included * by default.) * @hideinitializer **********************************************************************/ AZIMUTH = Geodesic::AZIMUTH, /** * Calculate distance \e s12. * @hideinitializer **********************************************************************/ DISTANCE = Geodesic::DISTANCE, /** * A combination of the common capabilities: GeodesicLine::LATITUDE, * GeodesicLine::LONGITUDE, GeodesicLine::AZIMUTH, GeodesicLine::DISTANCE. * @hideinitializer **********************************************************************/ STANDARD = Geodesic::STANDARD, /** * Allow distance \e s12 to be used as input in the direct geodesic * problem. * @hideinitializer **********************************************************************/ DISTANCE_IN = Geodesic::DISTANCE_IN, /** * Calculate reduced length \e m12. * @hideinitializer **********************************************************************/ REDUCEDLENGTH = Geodesic::REDUCEDLENGTH, /** * Calculate geodesic scales \e M12 and \e M21. * @hideinitializer **********************************************************************/ GEODESICSCALE = Geodesic::GEODESICSCALE, /** * Calculate area \e S12. * @hideinitializer **********************************************************************/ AREA = Geodesic::AREA, /** * Unroll \e lon2 in the direct calculation. * @hideinitializer **********************************************************************/ LONG_UNROLL = Geodesic::LONG_UNROLL, /** * All capabilities, calculate everything. (GeodesicLine::LONG_UNROLL is * not included in this mask.) * @hideinitializer **********************************************************************/ ALL = Geodesic::ALL, }; /** \name Constructors **********************************************************************/ ///@{ /** * Constructor for a geodesic line staring at latitude \e lat1, longitude * \e lon1, and azimuth \e azi1 (all in degrees). * * @param[in] g A Geodesic object used to compute the necessary information * about the GeodesicLine. * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] caps bitor'ed combination of GeodesicLine::mask values * specifying the capabilities the GeodesicLine object should possess, * i.e., which quantities can be returned in calls to * GeodesicLine::Position. * * \e lat1 should be in the range [−90°, 90°]. * * The GeodesicLine::mask values are * - \e caps |= GeodesicLine::LATITUDE for the latitude \e lat2; this is * added automatically; * - \e caps |= GeodesicLine::LONGITUDE for the latitude \e lon2; * - \e caps |= GeodesicLine::AZIMUTH for the latitude \e azi2; this is * added automatically; * - \e caps |= GeodesicLine::DISTANCE for the distance \e s12; * - \e caps |= GeodesicLine::REDUCEDLENGTH for the reduced length \e m12; * - \e caps |= GeodesicLine::GEODESICSCALE for the geodesic scales \e M12 * and \e M21; * - \e caps |= GeodesicLine::AREA for the area \e S12; * - \e caps |= GeodesicLine::DISTANCE_IN permits the length of the * geodesic to be given in terms of \e s12; without this capability the * length can only be specified in terms of arc length; * - \e caps |= GeodesicLine::ALL for all of the above. * . * The default value of \e caps is GeodesicLine::ALL. * * If the point is at a pole, the azimuth is defined by keeping \e lon1 * fixed, writing \e lat1 = ±(90° − ε), and taking * the limit ε → 0+. **********************************************************************/ GeodesicLine(const Geodesic& g, real lat1, real lon1, real azi1, unsigned caps = ALL); /** * A default constructor. If GeodesicLine::Position is called on the * resulting object, it returns immediately (without doing any * calculations). The object can be set with a call to Geodesic::Line. * Use Init() to test whether object is still in this uninitialized state. **********************************************************************/ GeodesicLine() : _caps(0U) {} ///@} /** \name Position in terms of distance **********************************************************************/ ///@{ /** * Compute the position of point 2 which is a distance \e s12 (meters) from * point 1. * * @param[in] s12 distance from point 1 to point 2 (meters); it can be * negative. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees); requires that the * GeodesicLine object was constructed with \e caps |= * GeodesicLine::LONGITUDE. * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] m12 reduced length of geodesic (meters); requires that the * GeodesicLine object was constructed with \e caps |= * GeodesicLine::REDUCEDLENGTH. * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless); requires that the GeodesicLine object was constructed * with \e caps |= GeodesicLine::GEODESICSCALE. * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless); requires that the GeodesicLine object was constructed * with \e caps |= GeodesicLine::GEODESICSCALE. * @param[out] S12 area under the geodesic (meters2); requires * that the GeodesicLine object was constructed with \e caps |= * GeodesicLine::AREA. * @return \e a12 arc length from point 1 to point 2 (degrees). * * The values of \e lon2 and \e azi2 returned are in the range * [−180°, 180°]. * * The GeodesicLine object \e must have been constructed with \e caps |= * GeodesicLine::DISTANCE_IN; otherwise Math::NaN() is returned and no * parameters are set. Requesting a value which the GeodesicLine object is * not capable of computing is not an error; the corresponding argument * will not be altered. * * The following functions are overloaded versions of * GeodesicLine::Position which omit some of the output parameters. Note, * however, that the arc length is always computed and returned as the * function value. **********************************************************************/ Math::real Position(real s12, real& lat2, real& lon2, real& azi2, real& m12, real& M12, real& M21, real& S12) const { real t; return GenPosition(false, s12, LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH | GEODESICSCALE | AREA, lat2, lon2, azi2, t, m12, M12, M21, S12); } /** * See the documentation for GeodesicLine::Position. **********************************************************************/ Math::real Position(real s12, real& lat2, real& lon2) const { real t; return GenPosition(false, s12, LATITUDE | LONGITUDE, lat2, lon2, t, t, t, t, t, t); } /** * See the documentation for GeodesicLine::Position. **********************************************************************/ Math::real Position(real s12, real& lat2, real& lon2, real& azi2) const { real t; return GenPosition(false, s12, LATITUDE | LONGITUDE | AZIMUTH, lat2, lon2, azi2, t, t, t, t, t); } /** * See the documentation for GeodesicLine::Position. **********************************************************************/ Math::real Position(real s12, real& lat2, real& lon2, real& azi2, real& m12) const { real t; return GenPosition(false, s12, LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH, lat2, lon2, azi2, t, m12, t, t, t); } /** * See the documentation for GeodesicLine::Position. **********************************************************************/ Math::real Position(real s12, real& lat2, real& lon2, real& azi2, real& M12, real& M21) const { real t; return GenPosition(false, s12, LATITUDE | LONGITUDE | AZIMUTH | GEODESICSCALE, lat2, lon2, azi2, t, t, M12, M21, t); } /** * See the documentation for GeodesicLine::Position. **********************************************************************/ Math::real Position(real s12, real& lat2, real& lon2, real& azi2, real& m12, real& M12, real& M21) const { real t; return GenPosition(false, s12, LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH | GEODESICSCALE, lat2, lon2, azi2, t, m12, M12, M21, t); } ///@} /** \name Position in terms of arc length **********************************************************************/ ///@{ /** * Compute the position of point 2 which is an arc length \e a12 (degrees) * from point 1. * * @param[in] a12 arc length from point 1 to point 2 (degrees); it can * be negative. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees); requires that the * GeodesicLine object was constructed with \e caps |= * GeodesicLine::LONGITUDE. * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] s12 distance from point 1 to point 2 (meters); requires * that the GeodesicLine object was constructed with \e caps |= * GeodesicLine::DISTANCE. * @param[out] m12 reduced length of geodesic (meters); requires that the * GeodesicLine object was constructed with \e caps |= * GeodesicLine::REDUCEDLENGTH. * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless); requires that the GeodesicLine object was constructed * with \e caps |= GeodesicLine::GEODESICSCALE. * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless); requires that the GeodesicLine object was constructed * with \e caps |= GeodesicLine::GEODESICSCALE. * @param[out] S12 area under the geodesic (meters2); requires * that the GeodesicLine object was constructed with \e caps |= * GeodesicLine::AREA. * * The values of \e lon2 and \e azi2 returned are in the range * [−180°, 180°]. * * Requesting a value which the GeodesicLine object is not capable of * computing is not an error; the corresponding argument will not be * altered. * * The following functions are overloaded versions of * GeodesicLine::ArcPosition which omit some of the output parameters. **********************************************************************/ void ArcPosition(real a12, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21, real& S12) const { GenPosition(true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | REDUCEDLENGTH | GEODESICSCALE | AREA, lat2, lon2, azi2, s12, m12, M12, M21, S12); } /** * See the documentation for GeodesicLine::ArcPosition. **********************************************************************/ void ArcPosition(real a12, real& lat2, real& lon2) const { real t; GenPosition(true, a12, LATITUDE | LONGITUDE, lat2, lon2, t, t, t, t, t, t); } /** * See the documentation for GeodesicLine::ArcPosition. **********************************************************************/ void ArcPosition(real a12, real& lat2, real& lon2, real& azi2) const { real t; GenPosition(true, a12, LATITUDE | LONGITUDE | AZIMUTH, lat2, lon2, azi2, t, t, t, t, t); } /** * See the documentation for GeodesicLine::ArcPosition. **********************************************************************/ void ArcPosition(real a12, real& lat2, real& lon2, real& azi2, real& s12) const { real t; GenPosition(true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE, lat2, lon2, azi2, s12, t, t, t, t); } /** * See the documentation for GeodesicLine::ArcPosition. **********************************************************************/ void ArcPosition(real a12, real& lat2, real& lon2, real& azi2, real& s12, real& m12) const { real t; GenPosition(true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | REDUCEDLENGTH, lat2, lon2, azi2, s12, m12, t, t, t); } /** * See the documentation for GeodesicLine::ArcPosition. **********************************************************************/ void ArcPosition(real a12, real& lat2, real& lon2, real& azi2, real& s12, real& M12, real& M21) const { real t; GenPosition(true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | GEODESICSCALE, lat2, lon2, azi2, s12, t, M12, M21, t); } /** * See the documentation for GeodesicLine::ArcPosition. **********************************************************************/ void ArcPosition(real a12, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21) const { real t; GenPosition(true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | REDUCEDLENGTH | GEODESICSCALE, lat2, lon2, azi2, s12, m12, M12, M21, t); } ///@} /** \name The general position function. **********************************************************************/ ///@{ /** * The general position function. GeodesicLine::Position and * GeodesicLine::ArcPosition are defined in terms of this function. * * @param[in] arcmode boolean flag determining the meaning of the second * parameter; if \e arcmode is false, then the GeodesicLine object must * have been constructed with \e caps |= GeodesicLine::DISTANCE_IN. * @param[in] s12_a12 if \e arcmode is false, this is the distance between * point 1 and point 2 (meters); otherwise it is the arc length between * point 1 and point 2 (degrees); it can be negative. * @param[in] outmask a bitor'ed combination of GeodesicLine::mask values * specifying which of the following parameters should be set. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees); requires that the * GeodesicLine object was constructed with \e caps |= * GeodesicLine::LONGITUDE. * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] s12 distance from point 1 to point 2 (meters); requires * that the GeodesicLine object was constructed with \e caps |= * GeodesicLine::DISTANCE. * @param[out] m12 reduced length of geodesic (meters); requires that the * GeodesicLine object was constructed with \e caps |= * GeodesicLine::REDUCEDLENGTH. * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless); requires that the GeodesicLine object was constructed * with \e caps |= GeodesicLine::GEODESICSCALE. * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless); requires that the GeodesicLine object was constructed * with \e caps |= GeodesicLine::GEODESICSCALE. * @param[out] S12 area under the geodesic (meters2); requires * that the GeodesicLine object was constructed with \e caps |= * GeodesicLine::AREA. * @return \e a12 arc length from point 1 to point 2 (degrees). * * The GeodesicLine::mask values possible for \e outmask are * - \e outmask |= GeodesicLine::LATITUDE for the latitude \e lat2; * - \e outmask |= GeodesicLine::LONGITUDE for the latitude \e lon2; * - \e outmask |= GeodesicLine::AZIMUTH for the latitude \e azi2; * - \e outmask |= GeodesicLine::DISTANCE for the distance \e s12; * - \e outmask |= GeodesicLine::REDUCEDLENGTH for the reduced length \e * m12; * - \e outmask |= GeodesicLine::GEODESICSCALE for the geodesic scales \e * M12 and \e M21; * - \e outmask |= GeodesicLine::AREA for the area \e S12; * - \e outmask |= GeodesicLine::ALL for all of the above; * - \e outmask |= GeodesicLine::LONG_UNROLL to unroll \e lon2 instead of * reducing it into the range [−180°, 180°]. * . * Requesting a value which the GeodesicLine object is not capable of * computing is not an error; the corresponding argument will not be * altered. Note, however, that the arc length is always computed and * returned as the function value. * * With the GeodesicLine::LONG_UNROLL bit set, the quantity \e lon2 − * \e lon1 indicates how many times and in what sense the geodesic * encircles the ellipsoid. **********************************************************************/ Math::real GenPosition(bool arcmode, real s12_a12, unsigned outmask, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21, real& S12) const; ///@} /** \name Setting point 3 **********************************************************************/ ///@{ /** * Specify position of point 3 in terms of distance. * * @param[in] s13 the distance from point 1 to point 3 (meters); it * can be negative. * * This is only useful if the GeodesicLine object has been constructed * with \e caps |= GeodesicLine::DISTANCE_IN. **********************************************************************/ void SetDistance(real s13); /** * Specify position of point 3 in terms of arc length. * * @param[in] a13 the arc length from point 1 to point 3 (degrees); it * can be negative. * * The distance \e s13 is only set if the GeodesicLine object has been * constructed with \e caps |= GeodesicLine::DISTANCE. **********************************************************************/ void SetArc(real a13); /** * Specify position of point 3 in terms of either distance or arc length. * * @param[in] arcmode boolean flag determining the meaning of the second * parameter; if \e arcmode is false, then the GeodesicLine object must * have been constructed with \e caps |= GeodesicLine::DISTANCE_IN. * @param[in] s13_a13 if \e arcmode is false, this is the distance from * point 1 to point 3 (meters); otherwise it is the arc length from * point 1 to point 3 (degrees); it can be negative. **********************************************************************/ void GenSetDistance(bool arcmode, real s13_a13); ///@} /** \name Inspector functions **********************************************************************/ ///@{ /** * @return true if the object has been initialized. **********************************************************************/ bool Init() const { return _caps != 0U; } /** * @return \e lat1 the latitude of point 1 (degrees). **********************************************************************/ Math::real Latitude() const { return Init() ? _lat1 : Math::NaN(); } /** * @return \e lon1 the longitude of point 1 (degrees). **********************************************************************/ Math::real Longitude() const { return Init() ? _lon1 : Math::NaN(); } /** * @return \e azi1 the azimuth (degrees) of the geodesic line at point 1. **********************************************************************/ Math::real Azimuth() const { return Init() ? _azi1 : Math::NaN(); } /** * The sine and cosine of \e azi1. * * @param[out] sazi1 the sine of \e azi1. * @param[out] cazi1 the cosine of \e azi1. **********************************************************************/ void Azimuth(real& sazi1, real& cazi1) const { if (Init()) { sazi1 = _salp1; cazi1 = _calp1; } } /** * @return \e azi0 the azimuth (degrees) of the geodesic line as it crosses * the equator in a northward direction. * * The result lies in [−90°, 90°]. **********************************************************************/ Math::real EquatorialAzimuth() const { return Init() ? Math::atan2d(_salp0, _calp0) : Math::NaN(); } /** * The sine and cosine of \e azi0. * * @param[out] sazi0 the sine of \e azi0. * @param[out] cazi0 the cosine of \e azi0. **********************************************************************/ void EquatorialAzimuth(real& sazi0, real& cazi0) const { if (Init()) { sazi0 = _salp0; cazi0 = _calp0; } } /** * @return \e a1 the arc length (degrees) between the northward equatorial * crossing and point 1. * * The result lies in [−180°, 180°]. **********************************************************************/ Math::real EquatorialArc() const { return Init() ? Math::atan2d(_ssig1, _csig1) : Math::NaN(); } /** * @return \e a the equatorial radius of the ellipsoid (meters). This is * the value inherited from the Geodesic object used in the constructor. **********************************************************************/ Math::real EquatorialRadius() const { return Init() ? _a : Math::NaN(); } /** * @return \e f the flattening of the ellipsoid. This is the value * inherited from the Geodesic object used in the constructor. **********************************************************************/ Math::real Flattening() const { return Init() ? _f : Math::NaN(); } /** * @return \e caps the computational capabilities that this object was * constructed with. LATITUDE and AZIMUTH are always included. **********************************************************************/ unsigned Capabilities() const { return _caps; } /** * Test what capabilities are available. * * @param[in] testcaps a set of bitor'ed GeodesicLine::mask values. * @return true if the GeodesicLine object has all these capabilities. **********************************************************************/ bool Capabilities(unsigned testcaps) const { testcaps &= OUT_ALL; return (_caps & testcaps) == testcaps; } /** * The distance or arc length to point 3. * * @param[in] arcmode boolean flag determining the meaning of returned * value. * @return \e s13 if \e arcmode is false; \e a13 if \e arcmode is true. **********************************************************************/ Math::real GenDistance(bool arcmode) const { return Init() ? (arcmode ? _a13 : _s13) : Math::NaN(); } /** * @return \e s13, the distance to point 3 (meters). **********************************************************************/ Math::real Distance() const { return GenDistance(false); } /** * @return \e a13, the arc length to point 3 (degrees). **********************************************************************/ Math::real Arc() const { return GenDistance(true); } ///@} }; } // namespace GeographicLib #endif // GEOGRAPHICLIB_GEODESICLINE_HPP geosphere/src/Ellipsoid.cpp0000644000176200001440000001033614323376011015455 0ustar liggesusers/** * \file Ellipsoid.cpp * \brief Implementation for GeographicLib::Ellipsoid class * * Copyright (c) Charles Karney (2012-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #include "Ellipsoid.h" #if defined(_MSC_VER) // Squelch warnings about enum-float expressions # pragma warning (disable: 5055) #endif namespace GeographicLib { using namespace std; Ellipsoid::Ellipsoid(real a, real f) : stol_(real(0.01) * sqrt(numeric_limits::epsilon())) , _a(a) , _f(f) , _f1(1 - _f) , _f12(Math::sq(_f1)) , _e2(_f * (2 - _f)) , _es((_f < 0 ? -1 : 1) * sqrt(fabs(_e2))) , _e12(_e2 / (1 - _e2)) , _n(_f / (2 - _f)) , _b(_a * _f1) , _tm(_a, _f, real(1)) , _ell(-_e12) , _au(_a, _f, real(0), real(1), real(0), real(1), real(1)) {} const Ellipsoid& Ellipsoid::WGS84() { static const Ellipsoid wgs84(Constants::WGS84_a(), Constants::WGS84_f()); return wgs84; } Math::real Ellipsoid::QuarterMeridian() const { return _b * _ell.E(); } Math::real Ellipsoid::Area() const { return 4 * Math::pi() * ((Math::sq(_a) + Math::sq(_b) * (_e2 == 0 ? 1 : (_e2 > 0 ? atanh(sqrt(_e2)) : atan(sqrt(-_e2))) / sqrt(fabs(_e2))))/2); } Math::real Ellipsoid::ParametricLatitude(real phi) const { return Math::atand(_f1 * Math::tand(Math::LatFix(phi))); } Math::real Ellipsoid::InverseParametricLatitude(real beta) const { return Math::atand(Math::tand(Math::LatFix(beta)) / _f1); } Math::real Ellipsoid::GeocentricLatitude(real phi) const { return Math::atand(_f12 * Math::tand(Math::LatFix(phi))); } Math::real Ellipsoid::InverseGeocentricLatitude(real theta) const { return Math::atand(Math::tand(Math::LatFix(theta)) / _f12); } Math::real Ellipsoid::RectifyingLatitude(real phi) const { return fabs(phi) == Math::qd ? phi: Math::qd * MeridianDistance(phi) / QuarterMeridian(); } Math::real Ellipsoid::InverseRectifyingLatitude(real mu) const { if (fabs(mu) == Math::qd) return mu; return InverseParametricLatitude(_ell.Einv(mu * _ell.E() / Math::qd) / Math::degree()); } Math::real Ellipsoid::AuthalicLatitude(real phi) const { return Math::atand(_au.txif(Math::tand(Math::LatFix(phi)))); } Math::real Ellipsoid::InverseAuthalicLatitude(real xi) const { return Math::atand(_au.tphif(Math::tand(Math::LatFix(xi)))); } Math::real Ellipsoid::ConformalLatitude(real phi) const { return Math::atand(Math::taupf(Math::tand(Math::LatFix(phi)), _es)); } Math::real Ellipsoid::InverseConformalLatitude(real chi) const { return Math::atand(Math::tauf(Math::tand(Math::LatFix(chi)), _es)); } Math::real Ellipsoid::IsometricLatitude(real phi) const { return asinh(Math::taupf(Math::tand(Math::LatFix(phi)), _es)) / Math::degree(); } Math::real Ellipsoid::InverseIsometricLatitude(real psi) const { return Math::atand(Math::tauf(sinh(psi * Math::degree()), _es)); } Math::real Ellipsoid::CircleRadius(real phi) const { return fabs(phi) == Math::qd ? 0 : // a * cos(beta) _a / hypot(real(1), _f1 * Math::tand(Math::LatFix(phi))); } Math::real Ellipsoid::CircleHeight(real phi) const { real tbeta = _f1 * Math::tand(phi); // b * sin(beta) return _b * tbeta / hypot(real(1), _f1 * Math::tand(Math::LatFix(phi))); } Math::real Ellipsoid::MeridianDistance(real phi) const { return _b * _ell.Ed( ParametricLatitude(phi) ); } Math::real Ellipsoid::MeridionalCurvatureRadius(real phi) const { real v = 1 - _e2 * Math::sq(Math::sind(Math::LatFix(phi))); return _a * (1 - _e2) / (v * sqrt(v)); } Math::real Ellipsoid::TransverseCurvatureRadius(real phi) const { real v = 1 - _e2 * Math::sq(Math::sind(Math::LatFix(phi))); return _a / sqrt(v); } Math::real Ellipsoid::NormalCurvatureRadius(real phi, real azi) const { real calp, salp, v = 1 - _e2 * Math::sq(Math::sind(Math::LatFix(phi))); Math::sincosd(azi, salp, calp); return _a / (sqrt(v) * (Math::sq(calp) * v / (1 - _e2) + Math::sq(salp))); } } // namespace GeographicLib geosphere/src/PolygonArea.h0000644000176200001440000003234014323377037015426 0ustar liggesusers/** * \file PolygonArea.hpp * \brief Header for GeographicLib::PolygonAreaT class * * Copyright (c) Charles Karney (2010-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_POLYGONAREA_HPP) #define GEOGRAPHICLIB_POLYGONAREA_HPP 1 #include "Geodesic.h" #include "GeodesicExact.h" #include "Rhumb.h" #include "Accumulator.h" namespace GeographicLib { /** * \brief Polygon areas * * This computes the area of a polygon whose edges are geodesics using the * method given in Section 6 of * - C. F. F. Karney, * * Algorithms for geodesics, * J. Geodesy 87, 43--55 (2013); * DOI: * 10.1007/s00190-012-0578-z; * addenda: * * geod-addenda.html. * * Arbitrarily complex polygons are allowed. In the case self-intersecting * of polygons the area is accumulated "algebraically", e.g., the areas of * the 2 loops in a figure-8 polygon will partially cancel. * * This class lets you add vertices and edges one at a time to the polygon. * The sequence must start with a vertex and thereafter vertices and edges * can be added in any order. Any vertex after the first creates a new edge * which is the \e shortest geodesic from the previous vertex. In some * cases there may be two or many such shortest geodesics and the area is * then not uniquely defined. In this case, either add an intermediate * vertex or add the edge \e as an edge (by defining its direction and * length). * * The area and perimeter are accumulated at two times the standard floating * point precision to guard against the loss of accuracy with many-sided * polygons. At any point you can ask for the perimeter and area so far. * There's an option to treat the points as defining a polyline instead of a * polygon; in that case, only the perimeter is computed. * * This is a templated class to allow it to be used with Geodesic, * GeodesicExact, and Rhumb. GeographicLib::PolygonArea, * GeographicLib::PolygonAreaExact, and GeographicLib::PolygonAreaRhumb are * typedefs for these cases. * * For GeographicLib::PolygonArea (edges defined by Geodesic), an upper bound * on the error is about 0.1 m2 per vertex. However this is a * wildly pessimistic estimate in most cases. A more realistic estimate of * the error is given by a test involving 107 approximately * regular polygons on the WGS84 ellipsoid. The centers and the orientations * of the polygons were uniformly distributed, the number of vertices was * log-uniformly distributed in [3, 300], and the center to vertex distance * log-uniformly distributed in [0.1 m, 9000 km]. * * Using double precision (the standard precision for GeographicLib), the * maximum error in the perimeter was 200 nm, and the maximum error in the * area was
   *     0.0013 m^2 for perimeter < 10 km
   *     0.0070 m^2 for perimeter < 100 km
   *     0.070 m^2 for perimeter < 1000 km
   *     0.11 m^2 for all perimeters
   * 
* The errors are given in terms of the perimeter, because it is expected * that the errors depend mainly on the number of edges and the edge lengths. * * Using long doubles (GEOGRPAHICLIB_PRECISION = 3), the maximum error in the * perimeter was 200 pm, and the maximum error in the area was
   *     0.7 mm^2 for perim < 10 km
   *     3.2 mm^2 for perimeter < 100 km
   *     21 mm^2 for perimeter < 1000 km
   *     45 mm^2 for all perimeters
   * 
* * @tparam GeodType the geodesic class to use. * * Example of use: * \include example-PolygonArea.cpp * * Planimeter is a command-line utility * providing access to the functionality of PolygonAreaT. **********************************************************************/ template class PolygonAreaT { private: typedef Math::real real; GeodType _earth; real _area0; // Full ellipsoid area bool _polyline; // Assume polyline (don't close and skip area) unsigned _mask; unsigned _num; int _crossings; Accumulator<> _areasum, _perimetersum; real _lat0, _lon0, _lat1, _lon1; static int transit(real lon1, real lon2); // an alternate version of transit to deal with longitudes in the direct // problem. static int transitdirect(real lon1, real lon2); void Remainder(Accumulator<>& a) const { a.remainder(_area0); } void Remainder(real& a) const { using std::remainder; a = remainder(a, _area0); } template void AreaReduce(T& area, int crossings, bool reverse, bool sign) const; public: /** * Constructor for PolygonAreaT. * * @param[in] earth the Geodesic object to use for geodesic calculations. * @param[in] polyline if true that treat the points as defining a polyline * instead of a polygon (default = false). **********************************************************************/ PolygonAreaT(const GeodType& earth, bool polyline = false) : _earth(earth) , _area0(_earth.EllipsoidArea()) , _polyline(polyline) , _mask(GeodType::LATITUDE | GeodType::LONGITUDE | GeodType::DISTANCE | (_polyline ? GeodType::NONE : GeodType::AREA | GeodType::LONG_UNROLL)) { Clear(); } /** * Clear PolygonAreaT, allowing a new polygon to be started. **********************************************************************/ void Clear() { _num = 0; _crossings = 0; _areasum = 0; _perimetersum = 0; _lat0 = _lon0 = _lat1 = _lon1 = Math::NaN(); } /** * Add a point to the polygon or polyline. * * @param[in] lat the latitude of the point (degrees). * @param[in] lon the longitude of the point (degrees). * * \e lat should be in the range [−90°, 90°]. **********************************************************************/ void AddPoint(real lat, real lon); /** * Add an edge to the polygon or polyline. * * @param[in] azi azimuth at current point (degrees). * @param[in] s distance from current point to next point (meters). * * This does nothing if no points have been added yet. Use * PolygonAreaT::CurrentPoint to determine the position of the new vertex. **********************************************************************/ void AddEdge(real azi, real s); /** * Return the results so far. * * @param[in] reverse if true then clockwise (instead of counter-clockwise) * traversal counts as a positive area. * @param[in] sign if true then return a signed result for the area if * the polygon is traversed in the "wrong" direction instead of returning * the area for the rest of the earth. * @param[out] perimeter the perimeter of the polygon or length of the * polyline (meters). * @param[out] area the area of the polygon (meters2); only set * if \e polyline is false in the constructor. * @return the number of points. * * More points can be added to the polygon after this call. **********************************************************************/ unsigned Compute(bool reverse, bool sign, real& perimeter, real& area) const; /** * Return the results assuming a tentative final test point is added; * however, the data for the test point is not saved. This lets you report * a running result for the perimeter and area as the user moves the mouse * cursor. Ordinary floating point arithmetic is used to accumulate the * data for the test point; thus the area and perimeter returned are less * accurate than if PolygonAreaT::AddPoint and PolygonAreaT::Compute are * used. * * @param[in] lat the latitude of the test point (degrees). * @param[in] lon the longitude of the test point (degrees). * @param[in] reverse if true then clockwise (instead of counter-clockwise) * traversal counts as a positive area. * @param[in] sign if true then return a signed result for the area if * the polygon is traversed in the "wrong" direction instead of returning * the area for the rest of the earth. * @param[out] perimeter the approximate perimeter of the polygon or length * of the polyline (meters). * @param[out] area the approximate area of the polygon * (meters2); only set if polyline is false in the * constructor. * @return the number of points. * * \e lat should be in the range [−90°, 90°]. **********************************************************************/ unsigned TestPoint(real lat, real lon, bool reverse, bool sign, real& perimeter, real& area) const; /** * Return the results assuming a tentative final test point is added via an * azimuth and distance; however, the data for the test point is not saved. * This lets you report a running result for the perimeter and area as the * user moves the mouse cursor. Ordinary floating point arithmetic is used * to accumulate the data for the test point; thus the area and perimeter * returned are less accurate than if PolygonAreaT::AddEdge and * PolygonAreaT::Compute are used. * * @param[in] azi azimuth at current point (degrees). * @param[in] s distance from current point to final test point (meters). * @param[in] reverse if true then clockwise (instead of counter-clockwise) * traversal counts as a positive area. * @param[in] sign if true then return a signed result for the area if * the polygon is traversed in the "wrong" direction instead of returning * the area for the rest of the earth. * @param[out] perimeter the approximate perimeter of the polygon or length * of the polyline (meters). * @param[out] area the approximate area of the polygon * (meters2); only set if polyline is false in the * constructor. * @return the number of points. **********************************************************************/ unsigned TestEdge(real azi, real s, bool reverse, bool sign, real& perimeter, real& area) const; /** \name Inspector functions **********************************************************************/ ///@{ /** * @return \e a the equatorial radius of the ellipsoid (meters). This is * the value inherited from the Geodesic object used in the constructor. **********************************************************************/ Math::real EquatorialRadius() const { return _earth.EquatorialRadius(); } /** * @return \e f the flattening of the ellipsoid. This is the value * inherited from the Geodesic object used in the constructor. **********************************************************************/ Math::real Flattening() const { return _earth.Flattening(); } /** * Report the previous vertex added to the polygon or polyline. * * @param[out] lat the latitude of the point (degrees). * @param[out] lon the longitude of the point (degrees). * * If no points have been added, then NaNs are returned. Otherwise, \e lon * will be in the range [−180°, 180°]. **********************************************************************/ void CurrentPoint(real& lat, real& lon) const { lat = _lat1; lon = _lon1; } /** * Report the number of points currently in the polygon or polyline. * * @return the number of points. * * If no points have been added, then 0 is returned. **********************************************************************/ unsigned NumberPoints() const { return _num; } /** * Report whether the current object is a polygon or a polyline. * * @return true if the object is a polyline. **********************************************************************/ bool Polyline() const { return _polyline; } ///@} }; /** * @relates PolygonAreaT * * Polygon areas using Geodesic. This should be used if the flattening is * small. **********************************************************************/ typedef PolygonAreaT PolygonArea; /** * @relates PolygonAreaT * * Polygon areas using GeodesicExact. (But note that the implementation of * areas in GeodesicExact uses a high order series and this is only accurate * for modest flattenings.) **********************************************************************/ typedef PolygonAreaT PolygonAreaExact; /** * @relates PolygonAreaT * * Polygon areas using Rhumb. **********************************************************************/ typedef PolygonAreaT PolygonAreaRhumb; } // namespace GeographicLib #endif // GEOGRAPHICLIB_POLYGONAREA_HPP geosphere/src/PolygonArea.cpp0000644000176200001440000001672214323376012015757 0ustar liggesusers/** * \file PolygonArea.cpp * \brief Implementation for GeographicLib::PolygonAreaT class * * Copyright (c) Charles Karney (2010-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #include "PolygonArea.h" #if defined(_MSC_VER) // Squelch warnings about enum-float expressions # pragma warning (disable: 5055) #endif namespace GeographicLib { using namespace std; template int PolygonAreaT::transit(real lon1, real lon2) { // Return 1 or -1 if crossing prime meridian in east or west direction. // Otherwise return zero. longitude = +/-0 considered to be positive. // This is (should be?) compatible with transitdirect which computes // exactly the parity of // int(floor((lon1 + lon12) / 360)) - int(floor(lon1 / 360))) real lon12 = Math::AngDiff(lon1, lon2); lon1 = Math::AngNormalize(lon1); lon2 = Math::AngNormalize(lon2); // N.B. lon12 == 0 gives cross = 0 return // edge case lon1 = 180, lon2 = 360->0, lon12 = 180 to give 1 lon12 > 0 && ((lon1 < 0 && lon2 >= 0) || // lon12 > 0 && lon1 > 0 && lon2 == 0 implies lon1 == 180 (lon1 > 0 && lon2 == 0)) ? 1 : // non edge case lon1 = -180, lon2 = -360->-0, lon12 = -180 (lon12 < 0 && lon1 >= 0 && lon2 < 0 ? -1 : 0); // This was the old method (treating +/- 0 as negative). However, with the // new scheme for handling longitude differences this fails on: // lon1 = -180, lon2 = -360->-0, lon12 = -180 gives 0 not -1. // return // lon1 <= 0 && lon2 > 0 && lon12 > 0 ? 1 : // (lon2 <= 0 && lon1 > 0 && lon12 < 0 ? -1 : 0); } // an alternate version of transit to deal with longitudes in the direct // problem. template int PolygonAreaT::transitdirect(real lon1, real lon2) { // Compute exactly the parity of // int(floor(lon2 / 360)) - int(floor(lon1 / 360)) using std::remainder; // C++ C remainder -> [-360, 360] // Java % -> (-720, 720) switch to IEEEremainder -> [-360, 360] // JS % -> (-720, 720) // Python fmod -> (-720, 720) swith to Math.remainder // Fortran, Octave skip // If mod function gives result in [-360, 360] // [0, 360) -> 0; [-360, 0) or 360 -> 1 // If mod function gives result in (-720, 720) // [0, 360) or [-inf, -360) -> 0; [-360, 0) or [360, inf) -> 1 lon1 = remainder(lon1, real(2 * Math::td)); lon2 = remainder(lon2, real(2 * Math::td)); return ( (lon2 >= 0 && lon2 < Math::td ? 0 : 1) - (lon1 >= 0 && lon1 < Math::td ? 0 : 1) ); } template void PolygonAreaT::AddPoint(real lat, real lon) { if (_num == 0) { _lat0 = _lat1 = lat; _lon0 = _lon1 = lon; } else { real s12, S12, t; _earth.GenInverse(_lat1, _lon1, lat, lon, _mask, s12, t, t, t, t, t, S12); _perimetersum += s12; if (!_polyline) { _areasum += S12; _crossings += transit(_lon1, lon); } _lat1 = lat; _lon1 = lon; } ++_num; } template void PolygonAreaT::AddEdge(real azi, real s) { if (_num) { // Do nothing if _num is zero real lat, lon, S12, t; _earth.GenDirect(_lat1, _lon1, azi, false, s, _mask, lat, lon, t, t, t, t, t, S12); _perimetersum += s; if (!_polyline) { _areasum += S12; _crossings += transitdirect(_lon1, lon); } _lat1 = lat; _lon1 = lon; ++_num; } } template unsigned PolygonAreaT::Compute(bool reverse, bool sign, real& perimeter, real& area) const { real s12, S12, t; if (_num < 2) { perimeter = 0; if (!_polyline) area = 0; return _num; } if (_polyline) { perimeter = _perimetersum(); return _num; } _earth.GenInverse(_lat1, _lon1, _lat0, _lon0, _mask, s12, t, t, t, t, t, S12); perimeter = _perimetersum(s12); Accumulator<> tempsum(_areasum); tempsum += S12; int crossings = _crossings + transit(_lon1, _lon0); AreaReduce(tempsum, crossings, reverse, sign); area = real(0) + tempsum(); return _num; } template unsigned PolygonAreaT::TestPoint(real lat, real lon, bool reverse, bool sign, real& perimeter, real& area) const { if (_num == 0) { perimeter = 0; if (!_polyline) area = 0; return 1; } perimeter = _perimetersum(); real tempsum = _polyline ? 0 : _areasum(); int crossings = _crossings; unsigned num = _num + 1; for (int i = 0; i < (_polyline ? 1 : 2); ++i) { real s12, S12, t; _earth.GenInverse(i == 0 ? _lat1 : lat, i == 0 ? _lon1 : lon, i != 0 ? _lat0 : lat, i != 0 ? _lon0 : lon, _mask, s12, t, t, t, t, t, S12); perimeter += s12; if (!_polyline) { tempsum += S12; crossings += transit(i == 0 ? _lon1 : lon, i != 0 ? _lon0 : lon); } } if (_polyline) return num; AreaReduce(tempsum, crossings, reverse, sign); area = real(0) + tempsum; return num; } template unsigned PolygonAreaT::TestEdge(real azi, real s, bool reverse, bool sign, real& perimeter, real& area) const { if (_num == 0) { // we don't have a starting point! perimeter = Math::NaN(); if (!_polyline) area = Math::NaN(); return 0; } unsigned num = _num + 1; perimeter = _perimetersum() + s; if (_polyline) return num; real tempsum = _areasum(); int crossings = _crossings; { real lat, lon, s12, S12, t; _earth.GenDirect(_lat1, _lon1, azi, false, s, _mask, lat, lon, t, t, t, t, t, S12); tempsum += S12; crossings += transitdirect(_lon1, lon); _earth.GenInverse(lat, lon, _lat0, _lon0, _mask, s12, t, t, t, t, t, S12); perimeter += s12; tempsum += S12; crossings += transit(lon, _lon0); } AreaReduce(tempsum, crossings, reverse, sign); area = real(0) + tempsum; return num; } template template void PolygonAreaT::AreaReduce(T& area, int crossings, bool reverse, bool sign) const { Remainder(area); if (crossings & 1) area += (area < 0 ? 1 : -1) * _area0/2; // area is with the clockwise sense. If !reverse convert to // counter-clockwise convention. if (!reverse) area *= -1; // If sign put area in (-_area0/2, _area0/2], else put area in [0, _area0) if (sign) { if (area > _area0/2) area -= _area0; else if (area <= -_area0/2) area += _area0; } else { if (area >= _area0) area -= _area0; else if (area < 0) area += _area0; } } template class GEOGRAPHICLIB_EXPORT PolygonAreaT; template class GEOGRAPHICLIB_EXPORT PolygonAreaT; template class GEOGRAPHICLIB_EXPORT PolygonAreaT; } // namespace GeographicLib geosphere/src/TransverseMercator.h0000644000176200001440000002140014323377037017032 0ustar liggesusers/** * \file TransverseMercator.hpp * \brief Header for GeographicLib::TransverseMercator class * * Copyright (c) Charles Karney (2008-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_TRANSVERSEMERCATOR_HPP) #define GEOGRAPHICLIB_TRANSVERSEMERCATOR_HPP 1 #include "Constants.h" #if !defined(GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER) /** * The order of the series approximation used in TransverseMercator. * GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER can be set to any integer in [4, 8]. **********************************************************************/ # define GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER \ (GEOGRAPHICLIB_PRECISION == 2 ? 6 : \ (GEOGRAPHICLIB_PRECISION == 1 ? 4 : 8)) #endif namespace GeographicLib { /** * \brief Transverse Mercator projection * * This uses Krüger's method which evaluates the projection and its * inverse in terms of a series. See * - L. Krüger, * Konforme * Abbildung des Erdellipsoids in der Ebene (Conformal mapping of the * ellipsoidal earth to the plane), Royal Prussian Geodetic Institute, New * Series 52, 172 pp. (1912). * - C. F. F. Karney, * * Transverse Mercator with an accuracy of a few nanometers, * J. Geodesy 85(8), 475--485 (Aug. 2011); * preprint * arXiv:1002.1417. * * Krüger's method has been extended from 4th to 6th order. The maximum * error is 5 nm (5 nanometers), ground distance, for all positions within 35 * degrees of the central meridian. The error in the convergence is 2 * × 10−15" and the relative error in the scale * is 6 × 10−12%%. See Sec. 4 of * arXiv:1002.1417 for details. * The speed penalty in going to 6th order is only about 1%. * * There's a singularity in the projection at φ = 0°, λ * − λ0 = ±(1 − \e e)90° (≈ * ±82.6° for the WGS84 ellipsoid), where \e e is the * eccentricity. Beyond this point, the series ceases to converge and the * results from this method will be garbage. To be on the safe side, don't * use this method if the angular distance from the central meridian exceeds * (1 − 2e)90° (≈ 75° for the WGS84 ellipsoid) * * TransverseMercatorExact is an alternative implementation of the projection * using exact formulas which yield accurate (to 8 nm) results over the * entire ellipsoid. * * The ellipsoid parameters and the central scale are set in the constructor. * The central meridian (which is a trivial shift of the longitude) is * specified as the \e lon0 argument of the TransverseMercator::Forward and * TransverseMercator::Reverse functions. The latitude of origin is taken to * be the equator. There is no provision in this class for specifying a * false easting or false northing or a different latitude of origin. * However these are can be simply included by the calling function. For * example, the UTMUPS class applies the false easting and false northing for * the UTM projections. A more complicated example is the British National * Grid ( * EPSG:7405) which requires the use of a latitude of origin. This is * implemented by the GeographicLib::OSGB class. * * This class also returns the meridian convergence \e gamma and scale \e k. * The meridian convergence is the bearing of grid north (the \e y axis) * measured clockwise from true north. * * See TransverseMercator.cpp for more information on the implementation. * * See \ref transversemercator for a discussion of this projection. * * Example of use: * \include example-TransverseMercator.cpp * * TransverseMercatorProj is a * command-line utility providing access to the functionality of * TransverseMercator and TransverseMercatorExact. **********************************************************************/ class GEOGRAPHICLIB_EXPORT TransverseMercator { private: typedef Math::real real; static const int maxpow_ = GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER; static const int numit_ = 5; real _a, _f, _k0, _e2, _es, _e2m, _c, _n; // _alp[0] and _bet[0] unused real _a1, _b1, _alp[maxpow_ + 1], _bet[maxpow_ + 1]; friend class Ellipsoid; // For access to taupf, tauf. public: /** * Constructor for an ellipsoid with * * @param[in] a equatorial radius (meters). * @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere. * Negative \e f gives a prolate ellipsoid. * @param[in] k0 central scale factor. * @exception GeographicErr if \e a, (1 − \e f) \e a, or \e k0 is * not positive. **********************************************************************/ TransverseMercator(real a, real f, real k0); /** * Forward projection, from geographic to transverse Mercator. * * @param[in] lon0 central meridian of the projection (degrees). * @param[in] lat latitude of point (degrees). * @param[in] lon longitude of point (degrees). * @param[out] x easting of point (meters). * @param[out] y northing of point (meters). * @param[out] gamma meridian convergence at point (degrees). * @param[out] k scale of projection at point. * * No false easting or northing is added. \e lat should be in the range * [−90°, 90°]. **********************************************************************/ void Forward(real lon0, real lat, real lon, real& x, real& y, real& gamma, real& k) const; /** * Reverse projection, from transverse Mercator to geographic. * * @param[in] lon0 central meridian of the projection (degrees). * @param[in] x easting of point (meters). * @param[in] y northing of point (meters). * @param[out] lat latitude of point (degrees). * @param[out] lon longitude of point (degrees). * @param[out] gamma meridian convergence at point (degrees). * @param[out] k scale of projection at point. * * No false easting or northing is added. The value of \e lon returned is * in the range [−180°, 180°]. **********************************************************************/ void Reverse(real lon0, real x, real y, real& lat, real& lon, real& gamma, real& k) const; /** * TransverseMercator::Forward without returning the convergence and scale. **********************************************************************/ void Forward(real lon0, real lat, real lon, real& x, real& y) const { real gamma, k; Forward(lon0, lat, lon, x, y, gamma, k); } /** * TransverseMercator::Reverse without returning the convergence and scale. **********************************************************************/ void Reverse(real lon0, real x, real y, real& lat, real& lon) const { real gamma, k; Reverse(lon0, x, y, lat, lon, gamma, k); } /** \name Inspector functions **********************************************************************/ ///@{ /** * @return \e a the equatorial radius of the ellipsoid (meters). This is * the value used in the constructor. **********************************************************************/ Math::real EquatorialRadius() const { return _a; } /** * @return \e f the flattening of the ellipsoid. This is the value used in * the constructor. **********************************************************************/ Math::real Flattening() const { return _f; } /** * @return \e k0 central scale for the projection. This is the value of \e * k0 used in the constructor and is the scale on the central meridian. **********************************************************************/ Math::real CentralScale() const { return _k0; } ///@} /** * A global instantiation of TransverseMercator with the WGS84 ellipsoid * and the UTM scale factor. However, unlike UTM, no false easting or * northing is added. **********************************************************************/ static const TransverseMercator& UTM(); }; } // namespace GeographicLib #endif // GEOGRAPHICLIB_TRANSVERSEMERCATOR_HPP geosphere/src/Geodesic.cpp0000644000176200001440000022103514323376011015253 0ustar liggesusers/** * \file Geodesic.cpp * \brief Implementation for GeographicLib::Geodesic class * * Copyright (c) Charles Karney (2009-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ * * This is a reformulation of the geodesic problem. The notation is as * follows: * - at a general point (no suffix or 1 or 2 as suffix) * - phi = latitude * - beta = latitude on auxiliary sphere * - omega = longitude on auxiliary sphere * - lambda = longitude * - alpha = azimuth of great circle * - sigma = arc length along great circle * - s = distance * - tau = scaled distance (= sigma at multiples of pi/2) * - at northwards equator crossing * - beta = phi = 0 * - omega = lambda = 0 * - alpha = alpha0 * - sigma = s = 0 * - a 12 suffix means a difference, e.g., s12 = s2 - s1. * - s and c prefixes mean sin and cos **********************************************************************/ #include "Geodesic.h" #include "GeodesicLine.h" #if defined(_MSC_VER) // Squelch warnings about potentially uninitialized local variables, // constant conditional and enum-float expressions and mixing enums # pragma warning (disable: 4701 4127 5055 5054) #endif namespace GeographicLib { using namespace std; Geodesic::Geodesic(real a, real f) : maxit2_(maxit1_ + Math::digits() + 10) // Underflow guard. We require // tiny_ * epsilon() > 0 // tiny_ + epsilon() == epsilon() , tiny_(sqrt(numeric_limits::min())) , tol0_(numeric_limits::epsilon()) // Increase multiplier in defn of tol1_ from 100 to 200 to fix inverse // case 52.784459512564 0 -52.784459512563990912 179.634407464943777557 // which otherwise failed for Visual Studio 10 (Release and Debug) , tol1_(200 * tol0_) , tol2_(sqrt(tol0_)) , tolb_(tol0_) // Check on bisection interval , xthresh_(1000 * tol2_) , _a(a) , _f(f) , _f1(1 - _f) , _e2(_f * (2 - _f)) , _ep2(_e2 / Math::sq(_f1)) // e2 / (1 - e2) , _n(_f / ( 2 - _f)) , _b(_a * _f1) , _c2((Math::sq(_a) + Math::sq(_b) * (_e2 == 0 ? 1 : Math::eatanhe(real(1), (_f < 0 ? -1 : 1) * sqrt(fabs(_e2))) / _e2)) / 2) // authalic radius squared // The sig12 threshold for "really short". Using the auxiliary sphere // solution with dnm computed at (bet1 + bet2) / 2, the relative error in // the azimuth consistency check is sig12^2 * abs(f) * min(1, 1-f/2) / 2. // (Error measured for 1/100 < b/a < 100 and abs(f) >= 1/1000. For a // given f and sig12, the max error occurs for lines near the pole. If // the old rule for computing dnm = (dn1 + dn2)/2 is used, then the error // increases by a factor of 2.) Setting this equal to epsilon gives // sig12 = etol2. Here 0.1 is a safety factor (error decreased by 100) // and max(0.001, abs(f)) stops etol2 getting too large in the nearly // spherical case. , _etol2(real(0.1) * tol2_ / sqrt( fmax(real(0.001), fabs(_f)) * fmin(real(1), 1 - _f/2) / 2 )) { if (!(isfinite(_a) && _a > 0)) throw GeographicErr("Equatorial radius is not positive"); if (!(isfinite(_b) && _b > 0)) throw GeographicErr("Polar semi-axis is not positive"); A3coeff(); C3coeff(); C4coeff(); } const Geodesic& Geodesic::WGS84() { static const Geodesic wgs84(Constants::WGS84_a(), Constants::WGS84_f()); return wgs84; } Math::real Geodesic::SinCosSeries(bool sinp, real sinx, real cosx, const real c[], int n) { // Evaluate // y = sinp ? sum(c[i] * sin( 2*i * x), i, 1, n) : // sum(c[i] * cos((2*i+1) * x), i, 0, n-1) // using Clenshaw summation. N.B. c[0] is unused for sin series // Approx operation count = (n + 5) mult and (2 * n + 2) add c += (n + sinp); // Point to one beyond last element real ar = 2 * (cosx - sinx) * (cosx + sinx), // 2 * cos(2 * x) y0 = n & 1 ? *--c : 0, y1 = 0; // accumulators for sum // Now n is even n /= 2; while (n--) { // Unroll loop x 2, so accumulators return to their original role y1 = ar * y0 - y1 + *--c; y0 = ar * y1 - y0 + *--c; } return sinp ? 2 * sinx * cosx * y0 // sin(2 * x) * y0 : cosx * (y0 - y1); // cos(x) * (y0 - y1) } GeodesicLine Geodesic::Line(real lat1, real lon1, real azi1, unsigned caps) const { return GeodesicLine(*this, lat1, lon1, azi1, caps); } Math::real Geodesic::GenDirect(real lat1, real lon1, real azi1, bool arcmode, real s12_a12, unsigned outmask, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21, real& S12) const { // Automatically supply DISTANCE_IN if necessary if (!arcmode) outmask |= DISTANCE_IN; return GeodesicLine(*this, lat1, lon1, azi1, outmask) . // Note the dot! GenPosition(arcmode, s12_a12, outmask, lat2, lon2, azi2, s12, m12, M12, M21, S12); } GeodesicLine Geodesic::GenDirectLine(real lat1, real lon1, real azi1, bool arcmode, real s12_a12, unsigned caps) const { azi1 = Math::AngNormalize(azi1); real salp1, calp1; // Guard against underflow in salp0. Also -0 is converted to +0. Math::sincosd(Math::AngRound(azi1), salp1, calp1); // Automatically supply DISTANCE_IN if necessary if (!arcmode) caps |= DISTANCE_IN; return GeodesicLine(*this, lat1, lon1, azi1, salp1, calp1, caps, arcmode, s12_a12); } GeodesicLine Geodesic::DirectLine(real lat1, real lon1, real azi1, real s12, unsigned caps) const { return GenDirectLine(lat1, lon1, azi1, false, s12, caps); } GeodesicLine Geodesic::ArcDirectLine(real lat1, real lon1, real azi1, real a12, unsigned caps) const { return GenDirectLine(lat1, lon1, azi1, true, a12, caps); } Math::real Geodesic::GenInverse(real lat1, real lon1, real lat2, real lon2, unsigned outmask, real& s12, real& salp1, real& calp1, real& salp2, real& calp2, real& m12, real& M12, real& M21, real& S12) const { // Compute longitude difference (AngDiff does this carefully). using std::isnan; // Needed for Centos 7, ubuntu 14 real lon12s, lon12 = Math::AngDiff(lon1, lon2, lon12s); // Make longitude difference positive. int lonsign = signbit(lon12) ? -1 : 1; lon12 *= lonsign; lon12s *= lonsign; real lam12 = lon12 * Math::degree(), slam12, clam12; // Calculate sincos of lon12 + error (this applies AngRound internally). Math::sincosde(lon12, lon12s, slam12, clam12); // the supplementary longitude difference lon12s = (Math::hd - lon12) - lon12s; // If really close to the equator, treat as on equator. lat1 = Math::AngRound(Math::LatFix(lat1)); lat2 = Math::AngRound(Math::LatFix(lat2)); // Swap points so that point with higher (abs) latitude is point 1. // If one latitude is a nan, then it becomes lat1. int swapp = fabs(lat1) < fabs(lat2) || isnan(lat2) ? -1 : 1; if (swapp < 0) { lonsign *= -1; swap(lat1, lat2); } // Make lat1 <= -0 int latsign = signbit(lat1) ? 1 : -1; lat1 *= latsign; lat2 *= latsign; // Now we have // // 0 <= lon12 <= 180 // -90 <= lat1 <= -0 // lat1 <= lat2 <= -lat1 // // longsign, swapp, latsign register the transformation to bring the // coordinates to this canonical form. In all cases, 1 means no change was // made. We make these transformations so that there are few cases to // check, e.g., on verifying quadrants in atan2. In addition, this // enforces some symmetries in the results returned. real sbet1, cbet1, sbet2, cbet2, s12x, m12x; Math::sincosd(lat1, sbet1, cbet1); sbet1 *= _f1; // Ensure cbet1 = +epsilon at poles; doing the fix on beta means that sig12 // will be <= 2*tiny for two points at the same pole. Math::norm(sbet1, cbet1); cbet1 = fmax(tiny_, cbet1); Math::sincosd(lat2, sbet2, cbet2); sbet2 *= _f1; // Ensure cbet2 = +epsilon at poles Math::norm(sbet2, cbet2); cbet2 = fmax(tiny_, cbet2); // If cbet1 < -sbet1, then cbet2 - cbet1 is a sensitive measure of the // |bet1| - |bet2|. Alternatively (cbet1 >= -sbet1), abs(sbet2) + sbet1 is // a better measure. This logic is used in assigning calp2 in Lambda12. // Sometimes these quantities vanish and in that case we force bet2 = +/- // bet1 exactly. An example where is is necessary is the inverse problem // 48.522876735459 0 -48.52287673545898293 179.599720456223079643 // which failed with Visual Studio 10 (Release and Debug) if (cbet1 < -sbet1) { if (cbet2 == cbet1) sbet2 = copysign(sbet1, sbet2); } else { if (fabs(sbet2) == -sbet1) cbet2 = cbet1; } real dn1 = sqrt(1 + _ep2 * Math::sq(sbet1)), dn2 = sqrt(1 + _ep2 * Math::sq(sbet2)); real a12, sig12; // index zero element of this array is unused real Ca[nC_]; bool meridian = lat1 == -Math::qd || slam12 == 0; if (meridian) { // Endpoints are on a single full meridian, so the geodesic might lie on // a meridian. calp1 = clam12; salp1 = slam12; // Head to the target longitude calp2 = 1; salp2 = 0; // At the target we're heading north real // tan(bet) = tan(sig) * cos(alp) ssig1 = sbet1, csig1 = calp1 * cbet1, ssig2 = sbet2, csig2 = calp2 * cbet2; // sig12 = sig2 - sig1 sig12 = atan2(fmax(real(0), csig1 * ssig2 - ssig1 * csig2) + real(0), csig1 * csig2 + ssig1 * ssig2); { real dummy; Lengths(_n, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2, outmask | DISTANCE | REDUCEDLENGTH, s12x, m12x, dummy, M12, M21, Ca); } // Add the check for sig12 since zero length geodesics might yield m12 < // 0. Test case was // // echo 20.001 0 20.001 0 | GeodSolve -i // // In fact, we will have sig12 > pi/2 for meridional geodesic which is // not a shortest path. // TODO: investigate m12 < 0 result for aarch/ppc (with -f -p 20) // 20.001000000000001 0.000000000000000 180.000000000000000 // 20.001000000000001 0.000000000000000 180.000000000000000 // 0.0000000002 0.000000000000001 -0.0000000001 // 0.99999999999999989 0.99999999999999989 0.000 if (sig12 < 1 || m12x >= 0) { // Need at least 2, to handle 90 0 90 180 if (sig12 < 3 * tiny_ || // Prevent negative s12 or m12 for short lines (sig12 < tol0_ && (s12x < 0 || m12x < 0))) sig12 = m12x = s12x = 0; m12x *= _b; s12x *= _b; a12 = sig12 / Math::degree(); } else // m12 < 0, i.e., prolate and too close to anti-podal meridian = false; } // somg12 == 2 marks that it needs to be calculated real omg12 = 0, somg12 = 2, comg12 = 0; if (!meridian && sbet1 == 0 && // and sbet2 == 0 (_f <= 0 || lon12s >= _f * Math::hd)) { // Geodesic runs along equator calp1 = calp2 = 0; salp1 = salp2 = 1; s12x = _a * lam12; sig12 = omg12 = lam12 / _f1; m12x = _b * sin(sig12); if (outmask & GEODESICSCALE) M12 = M21 = cos(sig12); a12 = lon12 / _f1; } else if (!meridian) { // Now point1 and point2 belong within a hemisphere bounded by a // meridian and geodesic is neither meridional or equatorial. // Figure a starting point for Newton's method real dnm; sig12 = InverseStart(sbet1, cbet1, dn1, sbet2, cbet2, dn2, lam12, slam12, clam12, salp1, calp1, salp2, calp2, dnm, Ca); if (sig12 >= 0) { // Short lines (InverseStart sets salp2, calp2, dnm) s12x = sig12 * _b * dnm; m12x = Math::sq(dnm) * _b * sin(sig12 / dnm); if (outmask & GEODESICSCALE) M12 = M21 = cos(sig12 / dnm); a12 = sig12 / Math::degree(); omg12 = lam12 / (_f1 * dnm); } else { // Newton's method. This is a straightforward solution of f(alp1) = // lambda12(alp1) - lam12 = 0 with one wrinkle. f(alp) has exactly one // root in the interval (0, pi) and its derivative is positive at the // root. Thus f(alp) is positive for alp > alp1 and negative for alp < // alp1. During the course of the iteration, a range (alp1a, alp1b) is // maintained which brackets the root and with each evaluation of // f(alp) the range is shrunk, if possible. Newton's method is // restarted whenever the derivative of f is negative (because the new // value of alp1 is then further from the solution) or if the new // estimate of alp1 lies outside (0,pi); in this case, the new starting // guess is taken to be (alp1a + alp1b) / 2. // // initial values to suppress warnings (if loop is executed 0 times) real ssig1 = 0, csig1 = 0, ssig2 = 0, csig2 = 0, eps = 0, domg12 = 0; unsigned numit = 0; // Bracketing range real salp1a = tiny_, calp1a = 1, salp1b = tiny_, calp1b = -1; for (bool tripn = false, tripb = false;; ++numit) { // the WGS84 test set: mean = 1.47, sd = 1.25, max = 16 // WGS84 and random input: mean = 2.85, sd = 0.60 real dv; real v = Lambda12(sbet1, cbet1, dn1, sbet2, cbet2, dn2, salp1, calp1, slam12, clam12, salp2, calp2, sig12, ssig1, csig1, ssig2, csig2, eps, domg12, numit < maxit1_, dv, Ca); if (tripb || // Reversed test to allow escape with NaNs !(fabs(v) >= (tripn ? 8 : 1) * tol0_) || // Enough bisections to get accurate result numit == maxit2_) break; // Update bracketing values if (v > 0 && (numit > maxit1_ || calp1/salp1 > calp1b/salp1b)) { salp1b = salp1; calp1b = calp1; } else if (v < 0 && (numit > maxit1_ || calp1/salp1 < calp1a/salp1a)) { salp1a = salp1; calp1a = calp1; } if (numit < maxit1_ && dv > 0) { real dalp1 = -v/dv; // |dalp1| < pi test moved earlier because GEOGRAPHICLIB_PRECISION // = 5 can result in dalp1 = 10^(10^8). Then sin(dalp1) takes ages // (because of the need to do accurate range reduction). if (fabs(dalp1) < Math::pi()) { real sdalp1 = sin(dalp1), cdalp1 = cos(dalp1), nsalp1 = salp1 * cdalp1 + calp1 * sdalp1; if (nsalp1 > 0) { calp1 = calp1 * cdalp1 - salp1 * sdalp1; salp1 = nsalp1; Math::norm(salp1, calp1); // In some regimes we don't get quadratic convergence because // slope -> 0. So use convergence conditions based on epsilon // instead of sqrt(epsilon). tripn = fabs(v) <= 16 * tol0_; continue; } } } // Either dv was not positive or updated value was outside legal // range. Use the midpoint of the bracket as the next estimate. // This mechanism is not needed for the WGS84 ellipsoid, but it does // catch problems with more eccentric ellipsoids. Its efficacy is // such for the WGS84 test set with the starting guess set to alp1 = // 90deg: // the WGS84 test set: mean = 5.21, sd = 3.93, max = 24 // WGS84 and random input: mean = 4.74, sd = 0.99 salp1 = (salp1a + salp1b)/2; calp1 = (calp1a + calp1b)/2; Math::norm(salp1, calp1); tripn = false; tripb = (fabs(salp1a - salp1) + (calp1a - calp1) < tolb_ || fabs(salp1 - salp1b) + (calp1 - calp1b) < tolb_); } { real dummy; // Ensure that the reduced length and geodesic scale are computed in // a "canonical" way, with the I2 integral. unsigned lengthmask = outmask | (outmask & (REDUCEDLENGTH | GEODESICSCALE) ? DISTANCE : NONE); Lengths(eps, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2, lengthmask, s12x, m12x, dummy, M12, M21, Ca); } m12x *= _b; s12x *= _b; a12 = sig12 / Math::degree(); if (outmask & AREA) { // omg12 = lam12 - domg12 real sdomg12 = sin(domg12), cdomg12 = cos(domg12); somg12 = slam12 * cdomg12 - clam12 * sdomg12; comg12 = clam12 * cdomg12 + slam12 * sdomg12; } } } if (outmask & DISTANCE) s12 = real(0) + s12x; // Convert -0 to 0 if (outmask & REDUCEDLENGTH) m12 = real(0) + m12x; // Convert -0 to 0 if (outmask & AREA) { real // From Lambda12: sin(alp1) * cos(bet1) = sin(alp0) salp0 = salp1 * cbet1, calp0 = hypot(calp1, salp1 * sbet1); // calp0 > 0 real alp12; if (calp0 != 0 && salp0 != 0) { real // From Lambda12: tan(bet) = tan(sig) * cos(alp) ssig1 = sbet1, csig1 = calp1 * cbet1, ssig2 = sbet2, csig2 = calp2 * cbet2, k2 = Math::sq(calp0) * _ep2, eps = k2 / (2 * (1 + sqrt(1 + k2)) + k2), // Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0). A4 = Math::sq(_a) * calp0 * salp0 * _e2; Math::norm(ssig1, csig1); Math::norm(ssig2, csig2); C4f(eps, Ca); real B41 = SinCosSeries(false, ssig1, csig1, Ca, nC4_), B42 = SinCosSeries(false, ssig2, csig2, Ca, nC4_); S12 = A4 * (B42 - B41); } else // Avoid problems with indeterminate sig1, sig2 on equator S12 = 0; if (!meridian && somg12 == 2) { somg12 = sin(omg12); comg12 = cos(omg12); } if (!meridian && // omg12 < 3/4 * pi comg12 > -real(0.7071) && // Long difference not too big sbet2 - sbet1 < real(1.75)) { // Lat difference not too big // Use tan(Gamma/2) = tan(omg12/2) // * (tan(bet1/2)+tan(bet2/2))/(1+tan(bet1/2)*tan(bet2/2)) // with tan(x/2) = sin(x)/(1+cos(x)) real domg12 = 1 + comg12, dbet1 = 1 + cbet1, dbet2 = 1 + cbet2; alp12 = 2 * atan2( somg12 * ( sbet1 * dbet2 + sbet2 * dbet1 ), domg12 * ( sbet1 * sbet2 + dbet1 * dbet2 ) ); } else { // alp12 = alp2 - alp1, used in atan2 so no need to normalize real salp12 = salp2 * calp1 - calp2 * salp1, calp12 = calp2 * calp1 + salp2 * salp1; // The right thing appears to happen if alp1 = +/-180 and alp2 = 0, viz // salp12 = -0 and alp12 = -180. However this depends on the sign // being attached to 0 correctly. The following ensures the correct // behavior. if (salp12 == 0 && calp12 < 0) { salp12 = tiny_ * calp1; calp12 = -1; } alp12 = atan2(salp12, calp12); } S12 += _c2 * alp12; S12 *= swapp * lonsign * latsign; // Convert -0 to 0 S12 += 0; } // Convert calp, salp to azimuth accounting for lonsign, swapp, latsign. if (swapp < 0) { swap(salp1, salp2); swap(calp1, calp2); if (outmask & GEODESICSCALE) swap(M12, M21); } salp1 *= swapp * lonsign; calp1 *= swapp * latsign; salp2 *= swapp * lonsign; calp2 *= swapp * latsign; // Returned value in [0, 180] return a12; } Math::real Geodesic::GenInverse(real lat1, real lon1, real lat2, real lon2, unsigned outmask, real& s12, real& azi1, real& azi2, real& m12, real& M12, real& M21, real& S12) const { outmask &= OUT_MASK; real salp1, calp1, salp2, calp2, a12 = GenInverse(lat1, lon1, lat2, lon2, outmask, s12, salp1, calp1, salp2, calp2, m12, M12, M21, S12); if (outmask & AZIMUTH) { azi1 = Math::atan2d(salp1, calp1); azi2 = Math::atan2d(salp2, calp2); } return a12; } GeodesicLine Geodesic::InverseLine(real lat1, real lon1, real lat2, real lon2, unsigned caps) const { real t, salp1, calp1, salp2, calp2, a12 = GenInverse(lat1, lon1, lat2, lon2, // No need to specify AZIMUTH here 0u, t, salp1, calp1, salp2, calp2, t, t, t, t), azi1 = Math::atan2d(salp1, calp1); // Ensure that a12 can be converted to a distance if (caps & (OUT_MASK & DISTANCE_IN)) caps |= DISTANCE; return GeodesicLine(*this, lat1, lon1, azi1, salp1, calp1, caps, true, a12); } void Geodesic::Lengths(real eps, real sig12, real ssig1, real csig1, real dn1, real ssig2, real csig2, real dn2, real cbet1, real cbet2, unsigned outmask, real& s12b, real& m12b, real& m0, real& M12, real& M21, // Scratch area of the right size real Ca[]) const { // Return m12b = (reduced length)/_b; also calculate s12b = distance/_b, // and m0 = coefficient of secular term in expression for reduced length. outmask &= OUT_MASK; // outmask & DISTANCE: set s12b // outmask & REDUCEDLENGTH: set m12b & m0 // outmask & GEODESICSCALE: set M12 & M21 real m0x = 0, J12 = 0, A1 = 0, A2 = 0; real Cb[nC2_ + 1]; if (outmask & (DISTANCE | REDUCEDLENGTH | GEODESICSCALE)) { A1 = A1m1f(eps); C1f(eps, Ca); if (outmask & (REDUCEDLENGTH | GEODESICSCALE)) { A2 = A2m1f(eps); C2f(eps, Cb); m0x = A1 - A2; A2 = 1 + A2; } A1 = 1 + A1; } if (outmask & DISTANCE) { real B1 = SinCosSeries(true, ssig2, csig2, Ca, nC1_) - SinCosSeries(true, ssig1, csig1, Ca, nC1_); // Missing a factor of _b s12b = A1 * (sig12 + B1); if (outmask & (REDUCEDLENGTH | GEODESICSCALE)) { real B2 = SinCosSeries(true, ssig2, csig2, Cb, nC2_) - SinCosSeries(true, ssig1, csig1, Cb, nC2_); J12 = m0x * sig12 + (A1 * B1 - A2 * B2); } } else if (outmask & (REDUCEDLENGTH | GEODESICSCALE)) { // Assume here that nC1_ >= nC2_ for (int l = 1; l <= nC2_; ++l) Cb[l] = A1 * Ca[l] - A2 * Cb[l]; J12 = m0x * sig12 + (SinCosSeries(true, ssig2, csig2, Cb, nC2_) - SinCosSeries(true, ssig1, csig1, Cb, nC2_)); } if (outmask & REDUCEDLENGTH) { m0 = m0x; // Missing a factor of _b. // Add parens around (csig1 * ssig2) and (ssig1 * csig2) to ensure // accurate cancellation in the case of coincident points. m12b = dn2 * (csig1 * ssig2) - dn1 * (ssig1 * csig2) - csig1 * csig2 * J12; } if (outmask & GEODESICSCALE) { real csig12 = csig1 * csig2 + ssig1 * ssig2; real t = _ep2 * (cbet1 - cbet2) * (cbet1 + cbet2) / (dn1 + dn2); M12 = csig12 + (t * ssig2 - csig2 * J12) * ssig1 / dn1; M21 = csig12 - (t * ssig1 - csig1 * J12) * ssig2 / dn2; } } Math::real Geodesic::Astroid(real x, real y) { // Solve k^4+2*k^3-(x^2+y^2-1)*k^2-2*y^2*k-y^2 = 0 for positive root k. // This solution is adapted from Geocentric::Reverse. real k; real p = Math::sq(x), q = Math::sq(y), r = (p + q - 1) / 6; if ( !(q == 0 && r <= 0) ) { real // Avoid possible division by zero when r = 0 by multiplying equations // for s and t by r^3 and r, resp. S = p * q / 4, // S = r^3 * s r2 = Math::sq(r), r3 = r * r2, // The discriminant of the quadratic equation for T3. This is zero on // the evolute curve p^(1/3)+q^(1/3) = 1 disc = S * (S + 2 * r3); real u = r; if (disc >= 0) { real T3 = S + r3; // Pick the sign on the sqrt to maximize abs(T3). This minimizes loss // of precision due to cancellation. The result is unchanged because // of the way the T is used in definition of u. T3 += T3 < 0 ? -sqrt(disc) : sqrt(disc); // T3 = (r * t)^3 // N.B. cbrt always returns the real root. cbrt(-8) = -2. real T = cbrt(T3); // T = r * t // T can be zero; but then r2 / T -> 0. u += T + (T != 0 ? r2 / T : 0); } else { // T is complex, but the way u is defined the result is real. real ang = atan2(sqrt(-disc), -(S + r3)); // There are three possible cube roots. We choose the root which // avoids cancellation. Note that disc < 0 implies that r < 0. u += 2 * r * cos(ang / 3); } real v = sqrt(Math::sq(u) + q), // guaranteed positive // Avoid loss of accuracy when u < 0. uv = u < 0 ? q / (v - u) : u + v, // u+v, guaranteed positive w = (uv - q) / (2 * v); // positive? // Rearrange expression for k to avoid loss of accuracy due to // subtraction. Division by 0 not possible because uv > 0, w >= 0. k = uv / (sqrt(uv + Math::sq(w)) + w); // guaranteed positive } else { // q == 0 && r <= 0 // y = 0 with |x| <= 1. Handle this case directly. // for y small, positive root is k = abs(y)/sqrt(1-x^2) k = 0; } return k; } Math::real Geodesic::InverseStart(real sbet1, real cbet1, real dn1, real sbet2, real cbet2, real dn2, real lam12, real slam12, real clam12, real& salp1, real& calp1, // Only updated if return val >= 0 real& salp2, real& calp2, // Only updated for short lines real& dnm, // Scratch area of the right size real Ca[]) const { // Return a starting point for Newton's method in salp1 and calp1 (function // value is -1). If Newton's method doesn't need to be used, return also // salp2 and calp2 and function value is sig12. real sig12 = -1, // Return value // bet12 = bet2 - bet1 in [0, pi); bet12a = bet2 + bet1 in (-pi, 0] sbet12 = sbet2 * cbet1 - cbet2 * sbet1, cbet12 = cbet2 * cbet1 + sbet2 * sbet1; real sbet12a = sbet2 * cbet1 + cbet2 * sbet1; bool shortline = cbet12 >= 0 && sbet12 < real(0.5) && cbet2 * lam12 < real(0.5); real somg12, comg12; if (shortline) { real sbetm2 = Math::sq(sbet1 + sbet2); // sin((bet1+bet2)/2)^2 // = (sbet1 + sbet2)^2 / ((sbet1 + sbet2)^2 + (cbet1 + cbet2)^2) sbetm2 /= sbetm2 + Math::sq(cbet1 + cbet2); dnm = sqrt(1 + _ep2 * sbetm2); real omg12 = lam12 / (_f1 * dnm); somg12 = sin(omg12); comg12 = cos(omg12); } else { somg12 = slam12; comg12 = clam12; } salp1 = cbet2 * somg12; calp1 = comg12 >= 0 ? sbet12 + cbet2 * sbet1 * Math::sq(somg12) / (1 + comg12) : sbet12a - cbet2 * sbet1 * Math::sq(somg12) / (1 - comg12); real ssig12 = hypot(salp1, calp1), csig12 = sbet1 * sbet2 + cbet1 * cbet2 * comg12; if (shortline && ssig12 < _etol2) { // really short lines salp2 = cbet1 * somg12; calp2 = sbet12 - cbet1 * sbet2 * (comg12 >= 0 ? Math::sq(somg12) / (1 + comg12) : 1 - comg12); Math::norm(salp2, calp2); // Set return value sig12 = atan2(ssig12, csig12); } else if (fabs(_n) > real(0.1) || // Skip astroid calc if too eccentric csig12 >= 0 || ssig12 >= 6 * fabs(_n) * Math::pi() * Math::sq(cbet1)) { // Nothing to do, zeroth order spherical approximation is OK } else { // Scale lam12 and bet2 to x, y coordinate system where antipodal point // is at origin and singular point is at y = 0, x = -1. real x, y, lamscale, betscale; real lam12x = atan2(-slam12, -clam12); // lam12 - pi if (_f >= 0) { // In fact f == 0 does not get here // x = dlong, y = dlat { real k2 = Math::sq(sbet1) * _ep2, eps = k2 / (2 * (1 + sqrt(1 + k2)) + k2); lamscale = _f * cbet1 * A3f(eps) * Math::pi(); } betscale = lamscale * cbet1; x = lam12x / lamscale; y = sbet12a / betscale; } else { // _f < 0 // x = dlat, y = dlong real cbet12a = cbet2 * cbet1 - sbet2 * sbet1, bet12a = atan2(sbet12a, cbet12a); real m12b, m0, dummy; // In the case of lon12 = 180, this repeats a calculation made in // Inverse. Lengths(_n, Math::pi() + bet12a, sbet1, -cbet1, dn1, sbet2, cbet2, dn2, cbet1, cbet2, REDUCEDLENGTH, dummy, m12b, m0, dummy, dummy, Ca); x = -1 + m12b / (cbet1 * cbet2 * m0 * Math::pi()); betscale = x < -real(0.01) ? sbet12a / x : -_f * Math::sq(cbet1) * Math::pi(); lamscale = betscale / cbet1; y = lam12x / lamscale; } if (y > -tol1_ && x > -1 - xthresh_) { // strip near cut // Need real(x) here to cast away the volatility of x for min/max if (_f >= 0) { salp1 = fmin(real(1), -x); calp1 = - sqrt(1 - Math::sq(salp1)); } else { calp1 = fmax(real(x > -tol1_ ? 0 : -1), x); salp1 = sqrt(1 - Math::sq(calp1)); } } else { // Estimate alp1, by solving the astroid problem. // // Could estimate alpha1 = theta + pi/2, directly, i.e., // calp1 = y/k; salp1 = -x/(1+k); for _f >= 0 // calp1 = x/(1+k); salp1 = -y/k; for _f < 0 (need to check) // // However, it's better to estimate omg12 from astroid and use // spherical formula to compute alp1. This reduces the mean number of // Newton iterations for astroid cases from 2.24 (min 0, max 6) to 2.12 // (min 0 max 5). The changes in the number of iterations are as // follows: // // change percent // 1 5 // 0 78 // -1 16 // -2 0.6 // -3 0.04 // -4 0.002 // // The histogram of iterations is (m = number of iterations estimating // alp1 directly, n = number of iterations estimating via omg12, total // number of trials = 148605): // // iter m n // 0 148 186 // 1 13046 13845 // 2 93315 102225 // 3 36189 32341 // 4 5396 7 // 5 455 1 // 6 56 0 // // Because omg12 is near pi, estimate work with omg12a = pi - omg12 real k = Astroid(x, y); real omg12a = lamscale * ( _f >= 0 ? -x * k/(1 + k) : -y * (1 + k)/k ); somg12 = sin(omg12a); comg12 = -cos(omg12a); // Update spherical estimate of alp1 using omg12 instead of lam12 salp1 = cbet2 * somg12; calp1 = sbet12a - cbet2 * sbet1 * Math::sq(somg12) / (1 - comg12); } } // Sanity check on starting guess. Backwards check allows NaN through. if (!(salp1 <= 0)) Math::norm(salp1, calp1); else { salp1 = 1; calp1 = 0; } return sig12; } Math::real Geodesic::Lambda12(real sbet1, real cbet1, real dn1, real sbet2, real cbet2, real dn2, real salp1, real calp1, real slam120, real clam120, real& salp2, real& calp2, real& sig12, real& ssig1, real& csig1, real& ssig2, real& csig2, real& eps, real& domg12, bool diffp, real& dlam12, // Scratch area of the right size real Ca[]) const { if (sbet1 == 0 && calp1 == 0) // Break degeneracy of equatorial line. This case has already been // handled. calp1 = -tiny_; real // sin(alp1) * cos(bet1) = sin(alp0) salp0 = salp1 * cbet1, calp0 = hypot(calp1, salp1 * sbet1); // calp0 > 0 real somg1, comg1, somg2, comg2, somg12, comg12, lam12; // tan(bet1) = tan(sig1) * cos(alp1) // tan(omg1) = sin(alp0) * tan(sig1) = tan(omg1)=tan(alp1)*sin(bet1) ssig1 = sbet1; somg1 = salp0 * sbet1; csig1 = comg1 = calp1 * cbet1; Math::norm(ssig1, csig1); // Math::norm(somg1, comg1); -- don't need to normalize! // Enforce symmetries in the case abs(bet2) = -bet1. Need to be careful // about this case, since this can yield singularities in the Newton // iteration. // sin(alp2) * cos(bet2) = sin(alp0) salp2 = cbet2 != cbet1 ? salp0 / cbet2 : salp1; // calp2 = sqrt(1 - sq(salp2)) // = sqrt(sq(calp0) - sq(sbet2)) / cbet2 // and subst for calp0 and rearrange to give (choose positive sqrt // to give alp2 in [0, pi/2]). calp2 = cbet2 != cbet1 || fabs(sbet2) != -sbet1 ? sqrt(Math::sq(calp1 * cbet1) + (cbet1 < -sbet1 ? (cbet2 - cbet1) * (cbet1 + cbet2) : (sbet1 - sbet2) * (sbet1 + sbet2))) / cbet2 : fabs(calp1); // tan(bet2) = tan(sig2) * cos(alp2) // tan(omg2) = sin(alp0) * tan(sig2). ssig2 = sbet2; somg2 = salp0 * sbet2; csig2 = comg2 = calp2 * cbet2; Math::norm(ssig2, csig2); // Math::norm(somg2, comg2); -- don't need to normalize! // sig12 = sig2 - sig1, limit to [0, pi] sig12 = atan2(fmax(real(0), csig1 * ssig2 - ssig1 * csig2) + real(0), csig1 * csig2 + ssig1 * ssig2); // omg12 = omg2 - omg1, limit to [0, pi] somg12 = fmax(real(0), comg1 * somg2 - somg1 * comg2) + real(0); comg12 = comg1 * comg2 + somg1 * somg2; // eta = omg12 - lam120 real eta = atan2(somg12 * clam120 - comg12 * slam120, comg12 * clam120 + somg12 * slam120); real B312; real k2 = Math::sq(calp0) * _ep2; eps = k2 / (2 * (1 + sqrt(1 + k2)) + k2); C3f(eps, Ca); B312 = (SinCosSeries(true, ssig2, csig2, Ca, nC3_-1) - SinCosSeries(true, ssig1, csig1, Ca, nC3_-1)); domg12 = -_f * A3f(eps) * salp0 * (sig12 + B312); lam12 = eta + domg12; if (diffp) { if (calp2 == 0) dlam12 = - 2 * _f1 * dn1 / sbet1; else { real dummy; Lengths(eps, sig12, ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2, REDUCEDLENGTH, dummy, dlam12, dummy, dummy, dummy, Ca); dlam12 *= _f1 / (calp2 * cbet2); } } return lam12; } Math::real Geodesic::A3f(real eps) const { // Evaluate A3 return Math::polyval(nA3_ - 1, _aA3x, eps); } void Geodesic::C3f(real eps, real c[]) const { // Evaluate C3 coeffs // Elements c[1] thru c[nC3_ - 1] are set real mult = 1; int o = 0; for (int l = 1; l < nC3_; ++l) { // l is index of C3[l] int m = nC3_ - l - 1; // order of polynomial in eps mult *= eps; c[l] = mult * Math::polyval(m, _cC3x + o, eps); o += m + 1; } // Post condition: o == nC3x_ } void Geodesic::C4f(real eps, real c[]) const { // Evaluate C4 coeffs // Elements c[0] thru c[nC4_ - 1] are set real mult = 1; int o = 0; for (int l = 0; l < nC4_; ++l) { // l is index of C4[l] int m = nC4_ - l - 1; // order of polynomial in eps c[l] = mult * Math::polyval(m, _cC4x + o, eps); o += m + 1; mult *= eps; } // Post condition: o == nC4x_ } // The static const coefficient arrays in the following functions are // generated by Maxima and give the coefficients of the Taylor expansions for // the geodesics. The convention on the order of these coefficients is as // follows: // // ascending order in the trigonometric expansion, // then powers of eps in descending order, // finally powers of n in descending order. // // (For some expansions, only a subset of levels occur.) For each polynomial // of order n at the lowest level, the (n+1) coefficients of the polynomial // are followed by a divisor which is applied to the whole polynomial. In // this way, the coefficients are expressible with no round off error. The // sizes of the coefficient arrays are: // // A1m1f, A2m1f = floor(N/2) + 2 // C1f, C1pf, C2f, A3coeff = (N^2 + 7*N - 2*floor(N/2)) / 4 // C3coeff = (N - 1) * (N^2 + 7*N - 2*floor(N/2)) / 8 // C4coeff = N * (N + 1) * (N + 5) / 6 // // where N = GEOGRAPHICLIB_GEODESIC_ORDER // = nA1 = nA2 = nC1 = nC1p = nA3 = nC4 // The scale factor A1-1 = mean value of (d/dsigma)I1 - 1 Math::real Geodesic::A1m1f(real eps) { // Generated by Maxima on 2015-05-05 18:08:12-04:00 #if GEOGRAPHICLIB_GEODESIC_ORDER/2 == 1 static const real coeff[] = { // (1-eps)*A1-1, polynomial in eps2 of order 1 1, 0, 4, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER/2 == 2 static const real coeff[] = { // (1-eps)*A1-1, polynomial in eps2 of order 2 1, 16, 0, 64, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER/2 == 3 static const real coeff[] = { // (1-eps)*A1-1, polynomial in eps2 of order 3 1, 4, 64, 0, 256, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER/2 == 4 static const real coeff[] = { // (1-eps)*A1-1, polynomial in eps2 of order 4 25, 64, 256, 4096, 0, 16384, }; #else #error "Bad value for GEOGRAPHICLIB_GEODESIC_ORDER" #endif static_assert(sizeof(coeff) / sizeof(real) == nA1_/2 + 2, "Coefficient array size mismatch in A1m1f"); int m = nA1_/2; real t = Math::polyval(m, coeff, Math::sq(eps)) / coeff[m + 1]; return (t + eps) / (1 - eps); } // The coefficients C1[l] in the Fourier expansion of B1 void Geodesic::C1f(real eps, real c[]) { // Generated by Maxima on 2015-05-05 18:08:12-04:00 #if GEOGRAPHICLIB_GEODESIC_ORDER == 3 static const real coeff[] = { // C1[1]/eps^1, polynomial in eps2 of order 1 3, -8, 16, // C1[2]/eps^2, polynomial in eps2 of order 0 -1, 16, // C1[3]/eps^3, polynomial in eps2 of order 0 -1, 48, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 4 static const real coeff[] = { // C1[1]/eps^1, polynomial in eps2 of order 1 3, -8, 16, // C1[2]/eps^2, polynomial in eps2 of order 1 1, -2, 32, // C1[3]/eps^3, polynomial in eps2 of order 0 -1, 48, // C1[4]/eps^4, polynomial in eps2 of order 0 -5, 512, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 5 static const real coeff[] = { // C1[1]/eps^1, polynomial in eps2 of order 2 -1, 6, -16, 32, // C1[2]/eps^2, polynomial in eps2 of order 1 1, -2, 32, // C1[3]/eps^3, polynomial in eps2 of order 1 9, -16, 768, // C1[4]/eps^4, polynomial in eps2 of order 0 -5, 512, // C1[5]/eps^5, polynomial in eps2 of order 0 -7, 1280, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 6 static const real coeff[] = { // C1[1]/eps^1, polynomial in eps2 of order 2 -1, 6, -16, 32, // C1[2]/eps^2, polynomial in eps2 of order 2 -9, 64, -128, 2048, // C1[3]/eps^3, polynomial in eps2 of order 1 9, -16, 768, // C1[4]/eps^4, polynomial in eps2 of order 1 3, -5, 512, // C1[5]/eps^5, polynomial in eps2 of order 0 -7, 1280, // C1[6]/eps^6, polynomial in eps2 of order 0 -7, 2048, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 7 static const real coeff[] = { // C1[1]/eps^1, polynomial in eps2 of order 3 19, -64, 384, -1024, 2048, // C1[2]/eps^2, polynomial in eps2 of order 2 -9, 64, -128, 2048, // C1[3]/eps^3, polynomial in eps2 of order 2 -9, 72, -128, 6144, // C1[4]/eps^4, polynomial in eps2 of order 1 3, -5, 512, // C1[5]/eps^5, polynomial in eps2 of order 1 35, -56, 10240, // C1[6]/eps^6, polynomial in eps2 of order 0 -7, 2048, // C1[7]/eps^7, polynomial in eps2 of order 0 -33, 14336, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 8 static const real coeff[] = { // C1[1]/eps^1, polynomial in eps2 of order 3 19, -64, 384, -1024, 2048, // C1[2]/eps^2, polynomial in eps2 of order 3 7, -18, 128, -256, 4096, // C1[3]/eps^3, polynomial in eps2 of order 2 -9, 72, -128, 6144, // C1[4]/eps^4, polynomial in eps2 of order 2 -11, 96, -160, 16384, // C1[5]/eps^5, polynomial in eps2 of order 1 35, -56, 10240, // C1[6]/eps^6, polynomial in eps2 of order 1 9, -14, 4096, // C1[7]/eps^7, polynomial in eps2 of order 0 -33, 14336, // C1[8]/eps^8, polynomial in eps2 of order 0 -429, 262144, }; #else #error "Bad value for GEOGRAPHICLIB_GEODESIC_ORDER" #endif static_assert(sizeof(coeff) / sizeof(real) == (nC1_*nC1_ + 7*nC1_ - 2*(nC1_/2)) / 4, "Coefficient array size mismatch in C1f"); real eps2 = Math::sq(eps), d = eps; int o = 0; for (int l = 1; l <= nC1_; ++l) { // l is index of C1p[l] int m = (nC1_ - l) / 2; // order of polynomial in eps^2 c[l] = d * Math::polyval(m, coeff + o, eps2) / coeff[o + m + 1]; o += m + 2; d *= eps; } // Post condition: o == sizeof(coeff) / sizeof(real) } // The coefficients C1p[l] in the Fourier expansion of B1p void Geodesic::C1pf(real eps, real c[]) { // Generated by Maxima on 2015-05-05 18:08:12-04:00 #if GEOGRAPHICLIB_GEODESIC_ORDER == 3 static const real coeff[] = { // C1p[1]/eps^1, polynomial in eps2 of order 1 -9, 16, 32, // C1p[2]/eps^2, polynomial in eps2 of order 0 5, 16, // C1p[3]/eps^3, polynomial in eps2 of order 0 29, 96, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 4 static const real coeff[] = { // C1p[1]/eps^1, polynomial in eps2 of order 1 -9, 16, 32, // C1p[2]/eps^2, polynomial in eps2 of order 1 -37, 30, 96, // C1p[3]/eps^3, polynomial in eps2 of order 0 29, 96, // C1p[4]/eps^4, polynomial in eps2 of order 0 539, 1536, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 5 static const real coeff[] = { // C1p[1]/eps^1, polynomial in eps2 of order 2 205, -432, 768, 1536, // C1p[2]/eps^2, polynomial in eps2 of order 1 -37, 30, 96, // C1p[3]/eps^3, polynomial in eps2 of order 1 -225, 116, 384, // C1p[4]/eps^4, polynomial in eps2 of order 0 539, 1536, // C1p[5]/eps^5, polynomial in eps2 of order 0 3467, 7680, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 6 static const real coeff[] = { // C1p[1]/eps^1, polynomial in eps2 of order 2 205, -432, 768, 1536, // C1p[2]/eps^2, polynomial in eps2 of order 2 4005, -4736, 3840, 12288, // C1p[3]/eps^3, polynomial in eps2 of order 1 -225, 116, 384, // C1p[4]/eps^4, polynomial in eps2 of order 1 -7173, 2695, 7680, // C1p[5]/eps^5, polynomial in eps2 of order 0 3467, 7680, // C1p[6]/eps^6, polynomial in eps2 of order 0 38081, 61440, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 7 static const real coeff[] = { // C1p[1]/eps^1, polynomial in eps2 of order 3 -4879, 9840, -20736, 36864, 73728, // C1p[2]/eps^2, polynomial in eps2 of order 2 4005, -4736, 3840, 12288, // C1p[3]/eps^3, polynomial in eps2 of order 2 8703, -7200, 3712, 12288, // C1p[4]/eps^4, polynomial in eps2 of order 1 -7173, 2695, 7680, // C1p[5]/eps^5, polynomial in eps2 of order 1 -141115, 41604, 92160, // C1p[6]/eps^6, polynomial in eps2 of order 0 38081, 61440, // C1p[7]/eps^7, polynomial in eps2 of order 0 459485, 516096, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 8 static const real coeff[] = { // C1p[1]/eps^1, polynomial in eps2 of order 3 -4879, 9840, -20736, 36864, 73728, // C1p[2]/eps^2, polynomial in eps2 of order 3 -86171, 120150, -142080, 115200, 368640, // C1p[3]/eps^3, polynomial in eps2 of order 2 8703, -7200, 3712, 12288, // C1p[4]/eps^4, polynomial in eps2 of order 2 1082857, -688608, 258720, 737280, // C1p[5]/eps^5, polynomial in eps2 of order 1 -141115, 41604, 92160, // C1p[6]/eps^6, polynomial in eps2 of order 1 -2200311, 533134, 860160, // C1p[7]/eps^7, polynomial in eps2 of order 0 459485, 516096, // C1p[8]/eps^8, polynomial in eps2 of order 0 109167851, 82575360, }; #else #error "Bad value for GEOGRAPHICLIB_GEODESIC_ORDER" #endif static_assert(sizeof(coeff) / sizeof(real) == (nC1p_*nC1p_ + 7*nC1p_ - 2*(nC1p_/2)) / 4, "Coefficient array size mismatch in C1pf"); real eps2 = Math::sq(eps), d = eps; int o = 0; for (int l = 1; l <= nC1p_; ++l) { // l is index of C1p[l] int m = (nC1p_ - l) / 2; // order of polynomial in eps^2 c[l] = d * Math::polyval(m, coeff + o, eps2) / coeff[o + m + 1]; o += m + 2; d *= eps; } // Post condition: o == sizeof(coeff) / sizeof(real) } // The scale factor A2-1 = mean value of (d/dsigma)I2 - 1 Math::real Geodesic::A2m1f(real eps) { // Generated by Maxima on 2015-05-29 08:09:47-04:00 #if GEOGRAPHICLIB_GEODESIC_ORDER/2 == 1 static const real coeff[] = { // (eps+1)*A2-1, polynomial in eps2 of order 1 -3, 0, 4, }; // count = 3 #elif GEOGRAPHICLIB_GEODESIC_ORDER/2 == 2 static const real coeff[] = { // (eps+1)*A2-1, polynomial in eps2 of order 2 -7, -48, 0, 64, }; // count = 4 #elif GEOGRAPHICLIB_GEODESIC_ORDER/2 == 3 static const real coeff[] = { // (eps+1)*A2-1, polynomial in eps2 of order 3 -11, -28, -192, 0, 256, }; // count = 5 #elif GEOGRAPHICLIB_GEODESIC_ORDER/2 == 4 static const real coeff[] = { // (eps+1)*A2-1, polynomial in eps2 of order 4 -375, -704, -1792, -12288, 0, 16384, }; // count = 6 #else #error "Bad value for GEOGRAPHICLIB_GEODESIC_ORDER" #endif static_assert(sizeof(coeff) / sizeof(real) == nA2_/2 + 2, "Coefficient array size mismatch in A2m1f"); int m = nA2_/2; real t = Math::polyval(m, coeff, Math::sq(eps)) / coeff[m + 1]; return (t - eps) / (1 + eps); } // The coefficients C2[l] in the Fourier expansion of B2 void Geodesic::C2f(real eps, real c[]) { // Generated by Maxima on 2015-05-05 18:08:12-04:00 #if GEOGRAPHICLIB_GEODESIC_ORDER == 3 static const real coeff[] = { // C2[1]/eps^1, polynomial in eps2 of order 1 1, 8, 16, // C2[2]/eps^2, polynomial in eps2 of order 0 3, 16, // C2[3]/eps^3, polynomial in eps2 of order 0 5, 48, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 4 static const real coeff[] = { // C2[1]/eps^1, polynomial in eps2 of order 1 1, 8, 16, // C2[2]/eps^2, polynomial in eps2 of order 1 1, 6, 32, // C2[3]/eps^3, polynomial in eps2 of order 0 5, 48, // C2[4]/eps^4, polynomial in eps2 of order 0 35, 512, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 5 static const real coeff[] = { // C2[1]/eps^1, polynomial in eps2 of order 2 1, 2, 16, 32, // C2[2]/eps^2, polynomial in eps2 of order 1 1, 6, 32, // C2[3]/eps^3, polynomial in eps2 of order 1 15, 80, 768, // C2[4]/eps^4, polynomial in eps2 of order 0 35, 512, // C2[5]/eps^5, polynomial in eps2 of order 0 63, 1280, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 6 static const real coeff[] = { // C2[1]/eps^1, polynomial in eps2 of order 2 1, 2, 16, 32, // C2[2]/eps^2, polynomial in eps2 of order 2 35, 64, 384, 2048, // C2[3]/eps^3, polynomial in eps2 of order 1 15, 80, 768, // C2[4]/eps^4, polynomial in eps2 of order 1 7, 35, 512, // C2[5]/eps^5, polynomial in eps2 of order 0 63, 1280, // C2[6]/eps^6, polynomial in eps2 of order 0 77, 2048, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 7 static const real coeff[] = { // C2[1]/eps^1, polynomial in eps2 of order 3 41, 64, 128, 1024, 2048, // C2[2]/eps^2, polynomial in eps2 of order 2 35, 64, 384, 2048, // C2[3]/eps^3, polynomial in eps2 of order 2 69, 120, 640, 6144, // C2[4]/eps^4, polynomial in eps2 of order 1 7, 35, 512, // C2[5]/eps^5, polynomial in eps2 of order 1 105, 504, 10240, // C2[6]/eps^6, polynomial in eps2 of order 0 77, 2048, // C2[7]/eps^7, polynomial in eps2 of order 0 429, 14336, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 8 static const real coeff[] = { // C2[1]/eps^1, polynomial in eps2 of order 3 41, 64, 128, 1024, 2048, // C2[2]/eps^2, polynomial in eps2 of order 3 47, 70, 128, 768, 4096, // C2[3]/eps^3, polynomial in eps2 of order 2 69, 120, 640, 6144, // C2[4]/eps^4, polynomial in eps2 of order 2 133, 224, 1120, 16384, // C2[5]/eps^5, polynomial in eps2 of order 1 105, 504, 10240, // C2[6]/eps^6, polynomial in eps2 of order 1 33, 154, 4096, // C2[7]/eps^7, polynomial in eps2 of order 0 429, 14336, // C2[8]/eps^8, polynomial in eps2 of order 0 6435, 262144, }; #else #error "Bad value for GEOGRAPHICLIB_GEODESIC_ORDER" #endif static_assert(sizeof(coeff) / sizeof(real) == (nC2_*nC2_ + 7*nC2_ - 2*(nC2_/2)) / 4, "Coefficient array size mismatch in C2f"); real eps2 = Math::sq(eps), d = eps; int o = 0; for (int l = 1; l <= nC2_; ++l) { // l is index of C2[l] int m = (nC2_ - l) / 2; // order of polynomial in eps^2 c[l] = d * Math::polyval(m, coeff + o, eps2) / coeff[o + m + 1]; o += m + 2; d *= eps; } // Post condition: o == sizeof(coeff) / sizeof(real) } // The scale factor A3 = mean value of (d/dsigma)I3 void Geodesic::A3coeff() { // Generated by Maxima on 2015-05-05 18:08:13-04:00 #if GEOGRAPHICLIB_GEODESIC_ORDER == 3 static const real coeff[] = { // A3, coeff of eps^2, polynomial in n of order 0 -1, 4, // A3, coeff of eps^1, polynomial in n of order 1 1, -1, 2, // A3, coeff of eps^0, polynomial in n of order 0 1, 1, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 4 static const real coeff[] = { // A3, coeff of eps^3, polynomial in n of order 0 -1, 16, // A3, coeff of eps^2, polynomial in n of order 1 -1, -2, 8, // A3, coeff of eps^1, polynomial in n of order 1 1, -1, 2, // A3, coeff of eps^0, polynomial in n of order 0 1, 1, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 5 static const real coeff[] = { // A3, coeff of eps^4, polynomial in n of order 0 -3, 64, // A3, coeff of eps^3, polynomial in n of order 1 -3, -1, 16, // A3, coeff of eps^2, polynomial in n of order 2 3, -1, -2, 8, // A3, coeff of eps^1, polynomial in n of order 1 1, -1, 2, // A3, coeff of eps^0, polynomial in n of order 0 1, 1, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 6 static const real coeff[] = { // A3, coeff of eps^5, polynomial in n of order 0 -3, 128, // A3, coeff of eps^4, polynomial in n of order 1 -2, -3, 64, // A3, coeff of eps^3, polynomial in n of order 2 -1, -3, -1, 16, // A3, coeff of eps^2, polynomial in n of order 2 3, -1, -2, 8, // A3, coeff of eps^1, polynomial in n of order 1 1, -1, 2, // A3, coeff of eps^0, polynomial in n of order 0 1, 1, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 7 static const real coeff[] = { // A3, coeff of eps^6, polynomial in n of order 0 -5, 256, // A3, coeff of eps^5, polynomial in n of order 1 -5, -3, 128, // A3, coeff of eps^4, polynomial in n of order 2 -10, -2, -3, 64, // A3, coeff of eps^3, polynomial in n of order 3 5, -1, -3, -1, 16, // A3, coeff of eps^2, polynomial in n of order 2 3, -1, -2, 8, // A3, coeff of eps^1, polynomial in n of order 1 1, -1, 2, // A3, coeff of eps^0, polynomial in n of order 0 1, 1, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 8 static const real coeff[] = { // A3, coeff of eps^7, polynomial in n of order 0 -25, 2048, // A3, coeff of eps^6, polynomial in n of order 1 -15, -20, 1024, // A3, coeff of eps^5, polynomial in n of order 2 -5, -10, -6, 256, // A3, coeff of eps^4, polynomial in n of order 3 -5, -20, -4, -6, 128, // A3, coeff of eps^3, polynomial in n of order 3 5, -1, -3, -1, 16, // A3, coeff of eps^2, polynomial in n of order 2 3, -1, -2, 8, // A3, coeff of eps^1, polynomial in n of order 1 1, -1, 2, // A3, coeff of eps^0, polynomial in n of order 0 1, 1, }; #else #error "Bad value for GEOGRAPHICLIB_GEODESIC_ORDER" #endif static_assert(sizeof(coeff) / sizeof(real) == (nA3_*nA3_ + 7*nA3_ - 2*(nA3_/2)) / 4, "Coefficient array size mismatch in A3f"); int o = 0, k = 0; for (int j = nA3_ - 1; j >= 0; --j) { // coeff of eps^j int m = min(nA3_ - j - 1, j); // order of polynomial in n _aA3x[k++] = Math::polyval(m, coeff + o, _n) / coeff[o + m + 1]; o += m + 2; } // Post condition: o == sizeof(coeff) / sizeof(real) && k == nA3x_ } // The coefficients C3[l] in the Fourier expansion of B3 void Geodesic::C3coeff() { // Generated by Maxima on 2015-05-05 18:08:13-04:00 #if GEOGRAPHICLIB_GEODESIC_ORDER == 3 static const real coeff[] = { // C3[1], coeff of eps^2, polynomial in n of order 0 1, 8, // C3[1], coeff of eps^1, polynomial in n of order 1 -1, 1, 4, // C3[2], coeff of eps^2, polynomial in n of order 0 1, 16, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 4 static const real coeff[] = { // C3[1], coeff of eps^3, polynomial in n of order 0 3, 64, // C3[1], coeff of eps^2, polynomial in n of order 1 // This is a case where a leading 0 term has been inserted to maintain the // pattern in the orders of the polynomials. 0, 1, 8, // C3[1], coeff of eps^1, polynomial in n of order 1 -1, 1, 4, // C3[2], coeff of eps^3, polynomial in n of order 0 3, 64, // C3[2], coeff of eps^2, polynomial in n of order 1 -3, 2, 32, // C3[3], coeff of eps^3, polynomial in n of order 0 5, 192, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 5 static const real coeff[] = { // C3[1], coeff of eps^4, polynomial in n of order 0 5, 128, // C3[1], coeff of eps^3, polynomial in n of order 1 3, 3, 64, // C3[1], coeff of eps^2, polynomial in n of order 2 -1, 0, 1, 8, // C3[1], coeff of eps^1, polynomial in n of order 1 -1, 1, 4, // C3[2], coeff of eps^4, polynomial in n of order 0 3, 128, // C3[2], coeff of eps^3, polynomial in n of order 1 -2, 3, 64, // C3[2], coeff of eps^2, polynomial in n of order 2 1, -3, 2, 32, // C3[3], coeff of eps^4, polynomial in n of order 0 3, 128, // C3[3], coeff of eps^3, polynomial in n of order 1 -9, 5, 192, // C3[4], coeff of eps^4, polynomial in n of order 0 7, 512, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 6 static const real coeff[] = { // C3[1], coeff of eps^5, polynomial in n of order 0 3, 128, // C3[1], coeff of eps^4, polynomial in n of order 1 2, 5, 128, // C3[1], coeff of eps^3, polynomial in n of order 2 -1, 3, 3, 64, // C3[1], coeff of eps^2, polynomial in n of order 2 -1, 0, 1, 8, // C3[1], coeff of eps^1, polynomial in n of order 1 -1, 1, 4, // C3[2], coeff of eps^5, polynomial in n of order 0 5, 256, // C3[2], coeff of eps^4, polynomial in n of order 1 1, 3, 128, // C3[2], coeff of eps^3, polynomial in n of order 2 -3, -2, 3, 64, // C3[2], coeff of eps^2, polynomial in n of order 2 1, -3, 2, 32, // C3[3], coeff of eps^5, polynomial in n of order 0 7, 512, // C3[3], coeff of eps^4, polynomial in n of order 1 -10, 9, 384, // C3[3], coeff of eps^3, polynomial in n of order 2 5, -9, 5, 192, // C3[4], coeff of eps^5, polynomial in n of order 0 7, 512, // C3[4], coeff of eps^4, polynomial in n of order 1 -14, 7, 512, // C3[5], coeff of eps^5, polynomial in n of order 0 21, 2560, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 7 static const real coeff[] = { // C3[1], coeff of eps^6, polynomial in n of order 0 21, 1024, // C3[1], coeff of eps^5, polynomial in n of order 1 11, 12, 512, // C3[1], coeff of eps^4, polynomial in n of order 2 2, 2, 5, 128, // C3[1], coeff of eps^3, polynomial in n of order 3 -5, -1, 3, 3, 64, // C3[1], coeff of eps^2, polynomial in n of order 2 -1, 0, 1, 8, // C3[1], coeff of eps^1, polynomial in n of order 1 -1, 1, 4, // C3[2], coeff of eps^6, polynomial in n of order 0 27, 2048, // C3[2], coeff of eps^5, polynomial in n of order 1 1, 5, 256, // C3[2], coeff of eps^4, polynomial in n of order 2 -9, 2, 6, 256, // C3[2], coeff of eps^3, polynomial in n of order 3 2, -3, -2, 3, 64, // C3[2], coeff of eps^2, polynomial in n of order 2 1, -3, 2, 32, // C3[3], coeff of eps^6, polynomial in n of order 0 3, 256, // C3[3], coeff of eps^5, polynomial in n of order 1 -4, 21, 1536, // C3[3], coeff of eps^4, polynomial in n of order 2 -6, -10, 9, 384, // C3[3], coeff of eps^3, polynomial in n of order 3 -1, 5, -9, 5, 192, // C3[4], coeff of eps^6, polynomial in n of order 0 9, 1024, // C3[4], coeff of eps^5, polynomial in n of order 1 -10, 7, 512, // C3[4], coeff of eps^4, polynomial in n of order 2 10, -14, 7, 512, // C3[5], coeff of eps^6, polynomial in n of order 0 9, 1024, // C3[5], coeff of eps^5, polynomial in n of order 1 -45, 21, 2560, // C3[6], coeff of eps^6, polynomial in n of order 0 11, 2048, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 8 static const real coeff[] = { // C3[1], coeff of eps^7, polynomial in n of order 0 243, 16384, // C3[1], coeff of eps^6, polynomial in n of order 1 10, 21, 1024, // C3[1], coeff of eps^5, polynomial in n of order 2 3, 11, 12, 512, // C3[1], coeff of eps^4, polynomial in n of order 3 -2, 2, 2, 5, 128, // C3[1], coeff of eps^3, polynomial in n of order 3 -5, -1, 3, 3, 64, // C3[1], coeff of eps^2, polynomial in n of order 2 -1, 0, 1, 8, // C3[1], coeff of eps^1, polynomial in n of order 1 -1, 1, 4, // C3[2], coeff of eps^7, polynomial in n of order 0 187, 16384, // C3[2], coeff of eps^6, polynomial in n of order 1 69, 108, 8192, // C3[2], coeff of eps^5, polynomial in n of order 2 -2, 1, 5, 256, // C3[2], coeff of eps^4, polynomial in n of order 3 -6, -9, 2, 6, 256, // C3[2], coeff of eps^3, polynomial in n of order 3 2, -3, -2, 3, 64, // C3[2], coeff of eps^2, polynomial in n of order 2 1, -3, 2, 32, // C3[3], coeff of eps^7, polynomial in n of order 0 139, 16384, // C3[3], coeff of eps^6, polynomial in n of order 1 -1, 12, 1024, // C3[3], coeff of eps^5, polynomial in n of order 2 -77, -8, 42, 3072, // C3[3], coeff of eps^4, polynomial in n of order 3 10, -6, -10, 9, 384, // C3[3], coeff of eps^3, polynomial in n of order 3 -1, 5, -9, 5, 192, // C3[4], coeff of eps^7, polynomial in n of order 0 127, 16384, // C3[4], coeff of eps^6, polynomial in n of order 1 -43, 72, 8192, // C3[4], coeff of eps^5, polynomial in n of order 2 -7, -40, 28, 2048, // C3[4], coeff of eps^4, polynomial in n of order 3 -7, 20, -28, 14, 1024, // C3[5], coeff of eps^7, polynomial in n of order 0 99, 16384, // C3[5], coeff of eps^6, polynomial in n of order 1 -15, 9, 1024, // C3[5], coeff of eps^5, polynomial in n of order 2 75, -90, 42, 5120, // C3[6], coeff of eps^7, polynomial in n of order 0 99, 16384, // C3[6], coeff of eps^6, polynomial in n of order 1 -99, 44, 8192, // C3[7], coeff of eps^7, polynomial in n of order 0 429, 114688, }; #else #error "Bad value for GEOGRAPHICLIB_GEODESIC_ORDER" #endif static_assert(sizeof(coeff) / sizeof(real) == ((nC3_-1)*(nC3_*nC3_ + 7*nC3_ - 2*(nC3_/2)))/8, "Coefficient array size mismatch in C3coeff"); int o = 0, k = 0; for (int l = 1; l < nC3_; ++l) { // l is index of C3[l] for (int j = nC3_ - 1; j >= l; --j) { // coeff of eps^j int m = min(nC3_ - j - 1, j); // order of polynomial in n _cC3x[k++] = Math::polyval(m, coeff + o, _n) / coeff[o + m + 1]; o += m + 2; } } // Post condition: o == sizeof(coeff) / sizeof(real) && k == nC3x_ } void Geodesic::C4coeff() { // Generated by Maxima on 2015-05-05 18:08:13-04:00 #if GEOGRAPHICLIB_GEODESIC_ORDER == 3 static const real coeff[] = { // C4[0], coeff of eps^2, polynomial in n of order 0 -2, 105, // C4[0], coeff of eps^1, polynomial in n of order 1 16, -7, 35, // C4[0], coeff of eps^0, polynomial in n of order 2 8, -28, 70, 105, // C4[1], coeff of eps^2, polynomial in n of order 0 -2, 105, // C4[1], coeff of eps^1, polynomial in n of order 1 -16, 7, 315, // C4[2], coeff of eps^2, polynomial in n of order 0 4, 525, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 4 static const real coeff[] = { // C4[0], coeff of eps^3, polynomial in n of order 0 11, 315, // C4[0], coeff of eps^2, polynomial in n of order 1 -32, -6, 315, // C4[0], coeff of eps^1, polynomial in n of order 2 -32, 48, -21, 105, // C4[0], coeff of eps^0, polynomial in n of order 3 4, 24, -84, 210, 315, // C4[1], coeff of eps^3, polynomial in n of order 0 -1, 105, // C4[1], coeff of eps^2, polynomial in n of order 1 64, -18, 945, // C4[1], coeff of eps^1, polynomial in n of order 2 32, -48, 21, 945, // C4[2], coeff of eps^3, polynomial in n of order 0 -8, 1575, // C4[2], coeff of eps^2, polynomial in n of order 1 -32, 12, 1575, // C4[3], coeff of eps^3, polynomial in n of order 0 8, 2205, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 5 static const real coeff[] = { // C4[0], coeff of eps^4, polynomial in n of order 0 4, 1155, // C4[0], coeff of eps^3, polynomial in n of order 1 -368, 121, 3465, // C4[0], coeff of eps^2, polynomial in n of order 2 1088, -352, -66, 3465, // C4[0], coeff of eps^1, polynomial in n of order 3 48, -352, 528, -231, 1155, // C4[0], coeff of eps^0, polynomial in n of order 4 16, 44, 264, -924, 2310, 3465, // C4[1], coeff of eps^4, polynomial in n of order 0 4, 1155, // C4[1], coeff of eps^3, polynomial in n of order 1 80, -99, 10395, // C4[1], coeff of eps^2, polynomial in n of order 2 -896, 704, -198, 10395, // C4[1], coeff of eps^1, polynomial in n of order 3 -48, 352, -528, 231, 10395, // C4[2], coeff of eps^4, polynomial in n of order 0 -8, 1925, // C4[2], coeff of eps^3, polynomial in n of order 1 384, -88, 17325, // C4[2], coeff of eps^2, polynomial in n of order 2 320, -352, 132, 17325, // C4[3], coeff of eps^4, polynomial in n of order 0 -16, 8085, // C4[3], coeff of eps^3, polynomial in n of order 1 -256, 88, 24255, // C4[4], coeff of eps^4, polynomial in n of order 0 64, 31185, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 6 static const real coeff[] = { // C4[0], coeff of eps^5, polynomial in n of order 0 97, 15015, // C4[0], coeff of eps^4, polynomial in n of order 1 1088, 156, 45045, // C4[0], coeff of eps^3, polynomial in n of order 2 -224, -4784, 1573, 45045, // C4[0], coeff of eps^2, polynomial in n of order 3 -10656, 14144, -4576, -858, 45045, // C4[0], coeff of eps^1, polynomial in n of order 4 64, 624, -4576, 6864, -3003, 15015, // C4[0], coeff of eps^0, polynomial in n of order 5 100, 208, 572, 3432, -12012, 30030, 45045, // C4[1], coeff of eps^5, polynomial in n of order 0 1, 9009, // C4[1], coeff of eps^4, polynomial in n of order 1 -2944, 468, 135135, // C4[1], coeff of eps^3, polynomial in n of order 2 5792, 1040, -1287, 135135, // C4[1], coeff of eps^2, polynomial in n of order 3 5952, -11648, 9152, -2574, 135135, // C4[1], coeff of eps^1, polynomial in n of order 4 -64, -624, 4576, -6864, 3003, 135135, // C4[2], coeff of eps^5, polynomial in n of order 0 8, 10725, // C4[2], coeff of eps^4, polynomial in n of order 1 1856, -936, 225225, // C4[2], coeff of eps^3, polynomial in n of order 2 -8448, 4992, -1144, 225225, // C4[2], coeff of eps^2, polynomial in n of order 3 -1440, 4160, -4576, 1716, 225225, // C4[3], coeff of eps^5, polynomial in n of order 0 -136, 63063, // C4[3], coeff of eps^4, polynomial in n of order 1 1024, -208, 105105, // C4[3], coeff of eps^3, polynomial in n of order 2 3584, -3328, 1144, 315315, // C4[4], coeff of eps^5, polynomial in n of order 0 -128, 135135, // C4[4], coeff of eps^4, polynomial in n of order 1 -2560, 832, 405405, // C4[5], coeff of eps^5, polynomial in n of order 0 128, 99099, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 7 static const real coeff[] = { // C4[0], coeff of eps^6, polynomial in n of order 0 10, 9009, // C4[0], coeff of eps^5, polynomial in n of order 1 -464, 291, 45045, // C4[0], coeff of eps^4, polynomial in n of order 2 -4480, 1088, 156, 45045, // C4[0], coeff of eps^3, polynomial in n of order 3 10736, -224, -4784, 1573, 45045, // C4[0], coeff of eps^2, polynomial in n of order 4 1664, -10656, 14144, -4576, -858, 45045, // C4[0], coeff of eps^1, polynomial in n of order 5 16, 64, 624, -4576, 6864, -3003, 15015, // C4[0], coeff of eps^0, polynomial in n of order 6 56, 100, 208, 572, 3432, -12012, 30030, 45045, // C4[1], coeff of eps^6, polynomial in n of order 0 10, 9009, // C4[1], coeff of eps^5, polynomial in n of order 1 112, 15, 135135, // C4[1], coeff of eps^4, polynomial in n of order 2 3840, -2944, 468, 135135, // C4[1], coeff of eps^3, polynomial in n of order 3 -10704, 5792, 1040, -1287, 135135, // C4[1], coeff of eps^2, polynomial in n of order 4 -768, 5952, -11648, 9152, -2574, 135135, // C4[1], coeff of eps^1, polynomial in n of order 5 -16, -64, -624, 4576, -6864, 3003, 135135, // C4[2], coeff of eps^6, polynomial in n of order 0 -4, 25025, // C4[2], coeff of eps^5, polynomial in n of order 1 -1664, 168, 225225, // C4[2], coeff of eps^4, polynomial in n of order 2 1664, 1856, -936, 225225, // C4[2], coeff of eps^3, polynomial in n of order 3 6784, -8448, 4992, -1144, 225225, // C4[2], coeff of eps^2, polynomial in n of order 4 128, -1440, 4160, -4576, 1716, 225225, // C4[3], coeff of eps^6, polynomial in n of order 0 64, 315315, // C4[3], coeff of eps^5, polynomial in n of order 1 1792, -680, 315315, // C4[3], coeff of eps^4, polynomial in n of order 2 -2048, 1024, -208, 105105, // C4[3], coeff of eps^3, polynomial in n of order 3 -1792, 3584, -3328, 1144, 315315, // C4[4], coeff of eps^6, polynomial in n of order 0 -512, 405405, // C4[4], coeff of eps^5, polynomial in n of order 1 2048, -384, 405405, // C4[4], coeff of eps^4, polynomial in n of order 2 3072, -2560, 832, 405405, // C4[5], coeff of eps^6, polynomial in n of order 0 -256, 495495, // C4[5], coeff of eps^5, polynomial in n of order 1 -2048, 640, 495495, // C4[6], coeff of eps^6, polynomial in n of order 0 512, 585585, }; #elif GEOGRAPHICLIB_GEODESIC_ORDER == 8 static const real coeff[] = { // C4[0], coeff of eps^7, polynomial in n of order 0 193, 85085, // C4[0], coeff of eps^6, polynomial in n of order 1 4192, 850, 765765, // C4[0], coeff of eps^5, polynomial in n of order 2 20960, -7888, 4947, 765765, // C4[0], coeff of eps^4, polynomial in n of order 3 12480, -76160, 18496, 2652, 765765, // C4[0], coeff of eps^3, polynomial in n of order 4 -154048, 182512, -3808, -81328, 26741, 765765, // C4[0], coeff of eps^2, polynomial in n of order 5 3232, 28288, -181152, 240448, -77792, -14586, 765765, // C4[0], coeff of eps^1, polynomial in n of order 6 96, 272, 1088, 10608, -77792, 116688, -51051, 255255, // C4[0], coeff of eps^0, polynomial in n of order 7 588, 952, 1700, 3536, 9724, 58344, -204204, 510510, 765765, // C4[1], coeff of eps^7, polynomial in n of order 0 349, 2297295, // C4[1], coeff of eps^6, polynomial in n of order 1 -1472, 510, 459459, // C4[1], coeff of eps^5, polynomial in n of order 2 -39840, 1904, 255, 2297295, // C4[1], coeff of eps^4, polynomial in n of order 3 52608, 65280, -50048, 7956, 2297295, // C4[1], coeff of eps^3, polynomial in n of order 4 103744, -181968, 98464, 17680, -21879, 2297295, // C4[1], coeff of eps^2, polynomial in n of order 5 -1344, -13056, 101184, -198016, 155584, -43758, 2297295, // C4[1], coeff of eps^1, polynomial in n of order 6 -96, -272, -1088, -10608, 77792, -116688, 51051, 2297295, // C4[2], coeff of eps^7, polynomial in n of order 0 464, 1276275, // C4[2], coeff of eps^6, polynomial in n of order 1 -928, -612, 3828825, // C4[2], coeff of eps^5, polynomial in n of order 2 64256, -28288, 2856, 3828825, // C4[2], coeff of eps^4, polynomial in n of order 3 -126528, 28288, 31552, -15912, 3828825, // C4[2], coeff of eps^3, polynomial in n of order 4 -41472, 115328, -143616, 84864, -19448, 3828825, // C4[2], coeff of eps^2, polynomial in n of order 5 160, 2176, -24480, 70720, -77792, 29172, 3828825, // C4[3], coeff of eps^7, polynomial in n of order 0 -16, 97461, // C4[3], coeff of eps^6, polynomial in n of order 1 -16384, 1088, 5360355, // C4[3], coeff of eps^5, polynomial in n of order 2 -2560, 30464, -11560, 5360355, // C4[3], coeff of eps^4, polynomial in n of order 3 35840, -34816, 17408, -3536, 1786785, // C4[3], coeff of eps^3, polynomial in n of order 4 7168, -30464, 60928, -56576, 19448, 5360355, // C4[4], coeff of eps^7, polynomial in n of order 0 128, 2297295, // C4[4], coeff of eps^6, polynomial in n of order 1 26624, -8704, 6891885, // C4[4], coeff of eps^5, polynomial in n of order 2 -77824, 34816, -6528, 6891885, // C4[4], coeff of eps^4, polynomial in n of order 3 -32256, 52224, -43520, 14144, 6891885, // C4[5], coeff of eps^7, polynomial in n of order 0 -6784, 8423415, // C4[5], coeff of eps^6, polynomial in n of order 1 24576, -4352, 8423415, // C4[5], coeff of eps^5, polynomial in n of order 2 45056, -34816, 10880, 8423415, // C4[6], coeff of eps^7, polynomial in n of order 0 -1024, 3318315, // C4[6], coeff of eps^6, polynomial in n of order 1 -28672, 8704, 9954945, // C4[7], coeff of eps^7, polynomial in n of order 0 1024, 1640925, }; #else #error "Bad value for GEOGRAPHICLIB_GEODESIC_ORDER" #endif static_assert(sizeof(coeff) / sizeof(real) == (nC4_ * (nC4_ + 1) * (nC4_ + 5)) / 6, "Coefficient array size mismatch in C4coeff"); int o = 0, k = 0; for (int l = 0; l < nC4_; ++l) { // l is index of C4[l] for (int j = nC4_ - 1; j >= l; --j) { // coeff of eps^j int m = nC4_ - j - 1; // order of polynomial in n _cC4x[k++] = Math::polyval(m, coeff + o, _n) / coeff[o + m + 1]; o += m + 2; } } // Post condition: o == sizeof(coeff) / sizeof(real) && k == nC4x_ } } // namespace GeographicLib geosphere/src/EllipticFunction.h0000644000176200001440000006570614323377037016475 0ustar liggesusers/** * \file EllipticFunction.hpp * \brief Header for GeographicLib::EllipticFunction class * * Copyright (c) Charles Karney (2008-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_ELLIPTICFUNCTION_HPP) #define GEOGRAPHICLIB_ELLIPTICFUNCTION_HPP 1 #include "Constants.h" namespace GeographicLib { /** * \brief Elliptic integrals and functions * * This provides the elliptic functions and integrals needed for Ellipsoid, * GeodesicExact, and TransverseMercatorExact. Two categories of function * are provided: * - \e static functions to compute symmetric elliptic integrals * (https://dlmf.nist.gov/19.16.i) * - \e member functions to compute Legrendre's elliptic * integrals (https://dlmf.nist.gov/19.2.ii) and the * Jacobi elliptic functions (https://dlmf.nist.gov/22.2). * . * In the latter case, an object is constructed giving the modulus \e k (and * optionally the parameter α2). The modulus is always * passed as its square k2 which allows \e k to be pure * imaginary (k2 < 0). (Confusingly, Abramowitz and * Stegun call \e m = k2 the "parameter" and \e n = * α2 the "characteristic".) * * In geodesic applications, it is convenient to separate the incomplete * integrals into secular and periodic components, e.g., * \f[ * E(\phi, k) = (2 E(k) / \pi) [ \phi + \delta E(\phi, k) ] * \f] * where δ\e E(φ, \e k) is an odd periodic function with period * π. * * The computation of the elliptic integrals uses the algorithms given in * - B. C. Carlson, * Computation of real or * complex elliptic integrals, Numerical Algorithms 10, 13--26 (1995); * preprint. * . * with the additional optimizations given in https://dlmf.nist.gov/19.36.i. * The computation of the Jacobi elliptic functions uses the algorithm given * in * - R. Bulirsch, * Numerical Calculation of * Elliptic Integrals and Elliptic Functions, Numericshe Mathematik 7, * 78--90 (1965). * . * The notation follows https://dlmf.nist.gov/19 and https://dlmf.nist.gov/22 * * Example of use: * \include example-EllipticFunction.cpp **********************************************************************/ class GEOGRAPHICLIB_EXPORT EllipticFunction { private: typedef Math::real real; enum { num_ = 13 }; // Max depth required for sncndn; probably 5 is enough. real _k2, _kp2, _alpha2, _alphap2, _eps; real _kKc, _eEc, _dDc, _pPic, _gGc, _hHc; public: /** \name Constructor **********************************************************************/ ///@{ /** * Constructor specifying the modulus and parameter. * * @param[in] k2 the square of the modulus k2. * k2 must lie in (−∞, 1]. * @param[in] alpha2 the parameter α2. * α2 must lie in (−∞, 1]. * @exception GeographicErr if \e k2 or \e alpha2 is out of its legal * range. * * If only elliptic integrals of the first and second kinds are needed, * then set α2 = 0 (the default value); in this case, we * have Π(φ, 0, \e k) = \e F(φ, \e k), \e G(φ, 0, \e k) = \e * E(φ, \e k), and \e H(φ, 0, \e k) = \e F(φ, \e k) - \e * D(φ, \e k). **********************************************************************/ EllipticFunction(real k2 = 0, real alpha2 = 0) { Reset(k2, alpha2); } /** * Constructor specifying the modulus and parameter and their complements. * * @param[in] k2 the square of the modulus k2. * k2 must lie in (−∞, 1]. * @param[in] alpha2 the parameter α2. * α2 must lie in (−∞, 1]. * @param[in] kp2 the complementary modulus squared k'2 = * 1 − k2. This must lie in [0, ∞). * @param[in] alphap2 the complementary parameter α'2 = 1 * − α2. This must lie in [0, ∞). * @exception GeographicErr if \e k2, \e alpha2, \e kp2, or \e alphap2 is * out of its legal range. * * The arguments must satisfy \e k2 + \e kp2 = 1 and \e alpha2 + \e alphap2 * = 1. (No checking is done that these conditions are met.) This * constructor is provided to enable accuracy to be maintained, e.g., when * \e k is very close to unity. **********************************************************************/ EllipticFunction(real k2, real alpha2, real kp2, real alphap2) { Reset(k2, alpha2, kp2, alphap2); } /** * Reset the modulus and parameter. * * @param[in] k2 the new value of square of the modulus * k2 which must lie in (−∞, ]. * done.) * @param[in] alpha2 the new value of parameter α2. * α2 must lie in (−∞, 1]. * @exception GeographicErr if \e k2 or \e alpha2 is out of its legal * range. **********************************************************************/ void Reset(real k2 = 0, real alpha2 = 0) { Reset(k2, alpha2, 1 - k2, 1 - alpha2); } /** * Reset the modulus and parameter supplying also their complements. * * @param[in] k2 the square of the modulus k2. * k2 must lie in (−∞, 1]. * @param[in] alpha2 the parameter α2. * α2 must lie in (−∞, 1]. * @param[in] kp2 the complementary modulus squared k'2 = * 1 − k2. This must lie in [0, ∞). * @param[in] alphap2 the complementary parameter α'2 = 1 * − α2. This must lie in [0, ∞). * @exception GeographicErr if \e k2, \e alpha2, \e kp2, or \e alphap2 is * out of its legal range. * * The arguments must satisfy \e k2 + \e kp2 = 1 and \e alpha2 + \e alphap2 * = 1. (No checking is done that these conditions are met.) This * constructor is provided to enable accuracy to be maintained, e.g., when * is very small. **********************************************************************/ void Reset(real k2, real alpha2, real kp2, real alphap2); ///@} /** \name Inspector functions. **********************************************************************/ ///@{ /** * @return the square of the modulus k2. **********************************************************************/ Math::real k2() const { return _k2; } /** * @return the square of the complementary modulus k'2 = * 1 − k2. **********************************************************************/ Math::real kp2() const { return _kp2; } /** * @return the parameter α2. **********************************************************************/ Math::real alpha2() const { return _alpha2; } /** * @return the complementary parameter α'2 = 1 − * α2. **********************************************************************/ Math::real alphap2() const { return _alphap2; } ///@} /** \name Complete elliptic integrals. **********************************************************************/ ///@{ /** * The complete integral of the first kind. * * @return \e K(\e k). * * \e K(\e k) is defined in https://dlmf.nist.gov/19.2.E4 * \f[ * K(k) = \int_0^{\pi/2} \frac1{\sqrt{1-k^2\sin^2\phi}}\,d\phi. * \f] **********************************************************************/ Math::real K() const { return _kKc; } /** * The complete integral of the second kind. * * @return \e E(\e k). * * \e E(\e k) is defined in https://dlmf.nist.gov/19.2.E5 * \f[ * E(k) = \int_0^{\pi/2} \sqrt{1-k^2\sin^2\phi}\,d\phi. * \f] **********************************************************************/ Math::real E() const { return _eEc; } /** * Jahnke's complete integral. * * @return \e D(\e k). * * \e D(\e k) is defined in https://dlmf.nist.gov/19.2.E6 * \f[ * D(k) = * \int_0^{\pi/2} \frac{\sin^2\phi}{\sqrt{1-k^2\sin^2\phi}}\,d\phi. * \f] **********************************************************************/ Math::real D() const { return _dDc; } /** * The difference between the complete integrals of the first and second * kinds. * * @return \e K(\e k) − \e E(\e k). **********************************************************************/ Math::real KE() const { return _k2 * _dDc; } /** * The complete integral of the third kind. * * @return Π(α2, \e k). * * Π(α2, \e k) is defined in * https://dlmf.nist.gov/19.2.E7 * \f[ * \Pi(\alpha^2, k) = \int_0^{\pi/2} * \frac1{\sqrt{1-k^2\sin^2\phi}(1 - \alpha^2\sin^2\phi)}\,d\phi. * \f] **********************************************************************/ Math::real Pi() const { return _pPic; } /** * Legendre's complete geodesic longitude integral. * * @return \e G(α2, \e k). * * \e G(α2, \e k) is given by * \f[ * G(\alpha^2, k) = \int_0^{\pi/2} * \frac{\sqrt{1-k^2\sin^2\phi}}{1 - \alpha^2\sin^2\phi}\,d\phi. * \f] **********************************************************************/ Math::real G() const { return _gGc; } /** * Cayley's complete geodesic longitude difference integral. * * @return \e H(α2, \e k). * * \e H(α2, \e k) is given by * \f[ * H(\alpha^2, k) = \int_0^{\pi/2} * \frac{\cos^2\phi}{(1-\alpha^2\sin^2\phi)\sqrt{1-k^2\sin^2\phi}} * \,d\phi. * \f] **********************************************************************/ Math::real H() const { return _hHc; } ///@} /** \name Incomplete elliptic integrals. **********************************************************************/ ///@{ /** * The incomplete integral of the first kind. * * @param[in] phi * @return \e F(φ, \e k). * * \e F(φ, \e k) is defined in https://dlmf.nist.gov/19.2.E4 * \f[ * F(\phi, k) = \int_0^\phi \frac1{\sqrt{1-k^2\sin^2\theta}}\,d\theta. * \f] **********************************************************************/ Math::real F(real phi) const; /** * The incomplete integral of the second kind. * * @param[in] phi * @return \e E(φ, \e k). * * \e E(φ, \e k) is defined in https://dlmf.nist.gov/19.2.E5 * \f[ * E(\phi, k) = \int_0^\phi \sqrt{1-k^2\sin^2\theta}\,d\theta. * \f] **********************************************************************/ Math::real E(real phi) const; /** * The incomplete integral of the second kind with the argument given in * degrees. * * @param[in] ang in degrees. * @return \e E(π ang/180, \e k). **********************************************************************/ Math::real Ed(real ang) const; /** * The inverse of the incomplete integral of the second kind. * * @param[in] x * @return φ = E−1(\e x, \e k); i.e., the * solution of such that \e E(φ, \e k) = \e x. **********************************************************************/ Math::real Einv(real x) const; /** * The incomplete integral of the third kind. * * @param[in] phi * @return Π(φ, α2, \e k). * * Π(φ, α2, \e k) is defined in * https://dlmf.nist.gov/19.2.E7 * \f[ * \Pi(\phi, \alpha^2, k) = \int_0^\phi * \frac1{\sqrt{1-k^2\sin^2\theta}(1 - \alpha^2\sin^2\theta)}\,d\theta. * \f] **********************************************************************/ Math::real Pi(real phi) const; /** * Jahnke's incomplete elliptic integral. * * @param[in] phi * @return \e D(φ, \e k). * * \e D(φ, \e k) is defined in https://dlmf.nist.gov/19.2.E4 * \f[ * D(\phi, k) = \int_0^\phi * \frac{\sin^2\theta}{\sqrt{1-k^2\sin^2\theta}}\,d\theta. * \f] **********************************************************************/ Math::real D(real phi) const; /** * Legendre's geodesic longitude integral. * * @param[in] phi * @return \e G(φ, α2, \e k). * * \e G(φ, α2, \e k) is defined by * \f[ * \begin{align} * G(\phi, \alpha^2, k) &= * \frac{k^2}{\alpha^2} F(\phi, k) + * \biggl(1 - \frac{k^2}{\alpha^2}\biggr) \Pi(\phi, \alpha^2, k) \\ * &= \int_0^\phi * \frac{\sqrt{1-k^2\sin^2\theta}}{1 - \alpha^2\sin^2\theta}\,d\theta. * \end{align} * \f] * * Legendre expresses the longitude of a point on the geodesic in terms of * this combination of elliptic integrals in Exercices de Calcul * Intégral, Vol. 1 (1811), p. 181, * https://books.google.com/books?id=riIOAAAAQAAJ&pg=PA181. * * See \ref geodellip for the expression for the longitude in terms of this * function. **********************************************************************/ Math::real G(real phi) const; /** * Cayley's geodesic longitude difference integral. * * @param[in] phi * @return \e H(φ, α2, \e k). * * \e H(φ, α2, \e k) is defined by * \f[ * \begin{align} * H(\phi, \alpha^2, k) &= * \frac1{\alpha^2} F(\phi, k) + * \biggl(1 - \frac1{\alpha^2}\biggr) \Pi(\phi, \alpha^2, k) \\ * &= \int_0^\phi * \frac{\cos^2\theta} * {(1-\alpha^2\sin^2\theta)\sqrt{1-k^2\sin^2\theta}} * \,d\theta. * \end{align} * \f] * * Cayley expresses the longitude difference of a point on the geodesic in * terms of this combination of elliptic integrals in Phil. Mag. 40 * (1870), p. 333, https://books.google.com/books?id=Zk0wAAAAIAAJ&pg=PA333. * * See \ref geodellip for the expression for the longitude in terms of this * function. **********************************************************************/ Math::real H(real phi) const; ///@} /** \name Incomplete integrals in terms of Jacobi elliptic functions. **********************************************************************/ ///@{ /** * The incomplete integral of the first kind in terms of Jacobi elliptic * functions. * * @param[in] sn = sinφ. * @param[in] cn = cosφ. * @param[in] dn = sqrt(1 − k2 * sin2φ). * @return \e F(φ, \e k) as though φ ∈ (−π, π]. **********************************************************************/ Math::real F(real sn, real cn, real dn) const; /** * The incomplete integral of the second kind in terms of Jacobi elliptic * functions. * * @param[in] sn = sinφ. * @param[in] cn = cosφ. * @param[in] dn = sqrt(1 − k2 * sin2φ). * @return \e E(φ, \e k) as though φ ∈ (−π, π]. **********************************************************************/ Math::real E(real sn, real cn, real dn) const; /** * The incomplete integral of the third kind in terms of Jacobi elliptic * functions. * * @param[in] sn = sinφ. * @param[in] cn = cosφ. * @param[in] dn = sqrt(1 − k2 * sin2φ). * @return Π(φ, α2, \e k) as though φ ∈ * (−π, π]. **********************************************************************/ Math::real Pi(real sn, real cn, real dn) const; /** * Jahnke's incomplete elliptic integral in terms of Jacobi elliptic * functions. * * @param[in] sn = sinφ. * @param[in] cn = cosφ. * @param[in] dn = sqrt(1 − k2 * sin2φ). * @return \e D(φ, \e k) as though φ ∈ (−π, π]. **********************************************************************/ Math::real D(real sn, real cn, real dn) const; /** * Legendre's geodesic longitude integral in terms of Jacobi elliptic * functions. * * @param[in] sn = sinφ. * @param[in] cn = cosφ. * @param[in] dn = sqrt(1 − k2 * sin2φ). * @return \e G(φ, α2, \e k) as though φ ∈ * (−π, π]. **********************************************************************/ Math::real G(real sn, real cn, real dn) const; /** * Cayley's geodesic longitude difference integral in terms of Jacobi * elliptic functions. * * @param[in] sn = sinφ. * @param[in] cn = cosφ. * @param[in] dn = sqrt(1 − k2 * sin2φ). * @return \e H(φ, α2, \e k) as though φ ∈ * (−π, π]. **********************************************************************/ Math::real H(real sn, real cn, real dn) const; ///@} /** \name Periodic versions of incomplete elliptic integrals. **********************************************************************/ ///@{ /** * The periodic incomplete integral of the first kind. * * @param[in] sn = sinφ. * @param[in] cn = cosφ. * @param[in] dn = sqrt(1 − k2 * sin2φ). * @return the periodic function π \e F(φ, \e k) / (2 \e K(\e k)) - * φ. **********************************************************************/ Math::real deltaF(real sn, real cn, real dn) const; /** * The periodic incomplete integral of the second kind. * * @param[in] sn = sinφ. * @param[in] cn = cosφ. * @param[in] dn = sqrt(1 − k2 * sin2φ). * @return the periodic function π \e E(φ, \e k) / (2 \e E(\e k)) - * φ. **********************************************************************/ Math::real deltaE(real sn, real cn, real dn) const; /** * The periodic inverse of the incomplete integral of the second kind. * * @param[in] stau = sinτ. * @param[in] ctau = sinτ. * @return the periodic function E−1(τ (2 \e * E(\e k)/π), \e k) - τ. **********************************************************************/ Math::real deltaEinv(real stau, real ctau) const; /** * The periodic incomplete integral of the third kind. * * @param[in] sn = sinφ. * @param[in] cn = cosφ. * @param[in] dn = sqrt(1 − k2 * sin2φ). * @return the periodic function π Π(φ, α2, * \e k) / (2 Π(α2, \e k)) - φ. **********************************************************************/ Math::real deltaPi(real sn, real cn, real dn) const; /** * The periodic Jahnke's incomplete elliptic integral. * * @param[in] sn = sinφ. * @param[in] cn = cosφ. * @param[in] dn = sqrt(1 − k2 * sin2φ). * @return the periodic function π \e D(φ, \e k) / (2 \e D(\e k)) - * φ. **********************************************************************/ Math::real deltaD(real sn, real cn, real dn) const; /** * Legendre's periodic geodesic longitude integral. * * @param[in] sn = sinφ. * @param[in] cn = cosφ. * @param[in] dn = sqrt(1 − k2 * sin2φ). * @return the periodic function π \e G(φ, \e k) / (2 \e G(\e k)) - * φ. **********************************************************************/ Math::real deltaG(real sn, real cn, real dn) const; /** * Cayley's periodic geodesic longitude difference integral. * * @param[in] sn = sinφ. * @param[in] cn = cosφ. * @param[in] dn = sqrt(1 − k2 * sin2φ). * @return the periodic function π \e H(φ, \e k) / (2 \e H(\e k)) - * φ. **********************************************************************/ Math::real deltaH(real sn, real cn, real dn) const; ///@} /** \name Elliptic functions. **********************************************************************/ ///@{ /** * The Jacobi elliptic functions. * * @param[in] x the argument. * @param[out] sn sn(\e x, \e k). * @param[out] cn cn(\e x, \e k). * @param[out] dn dn(\e x, \e k). **********************************************************************/ void sncndn(real x, real& sn, real& cn, real& dn) const; /** * The Δ amplitude function. * * @param[in] sn sinφ. * @param[in] cn cosφ. * @return Δ = sqrt(1 − k2 * sin2φ). **********************************************************************/ Math::real Delta(real sn, real cn) const { using std::sqrt; return sqrt(_k2 < 0 ? 1 - _k2 * sn*sn : _kp2 + _k2 * cn*cn); } ///@} /** \name Symmetric elliptic integrals. **********************************************************************/ ///@{ /** * Symmetric integral of the first kind RF. * * @param[in] x * @param[in] y * @param[in] z * @return RF(\e x, \e y, \e z). * * RF is defined in https://dlmf.nist.gov/19.16.E1 * \f[ R_F(x, y, z) = \frac12 * \int_0^\infty\frac1{\sqrt{(t + x) (t + y) (t + z)}}\, dt, \f] * where at most one of arguments, \e x, \e y, \e z, can be zero and those * arguments that are nonzero must be positive. If one of the arguments is * zero, it is more efficient to call the two-argument version of this * function with the non-zero arguments. **********************************************************************/ static real RF(real x, real y, real z); /** * Complete symmetric integral of the first kind, * RF with one argument zero. * * @param[in] x * @param[in] y * @return RF(\e x, \e y, 0). * * The arguments \e x and \e y must be positive. **********************************************************************/ static real RF(real x, real y); /** * Degenerate symmetric integral of the first kind * RC. * * @param[in] x * @param[in] y * @return RC(\e x, \e y) = * RF(\e x, \e y, \e y). * * RC is defined in https://dlmf.nist.gov/19.2.E17 * \f[ R_C(x, y) = \frac12 * \int_0^\infty\frac1{\sqrt{t + x}(t + y)}\,dt, \f] * where \e x ≥ 0 and \e y > 0. **********************************************************************/ static real RC(real x, real y); /** * Symmetric integral of the second kind RG. * * @param[in] x * @param[in] y * @param[in] z * @return RG(\e x, \e y, \e z). * * RG is defined in Carlson, eq 1.5 * \f[ R_G(x, y, z) = \frac14 * \int_0^\infty[(t + x) (t + y) (t + z)]^{-1/2} * \biggl( * \frac x{t + x} + \frac y{t + y} + \frac z{t + z} * \biggr)t\,dt, \f] * where at most one of arguments, \e x, \e y, \e z, can be zero and those * arguments that are nonzero must be positive. See also * https://dlmf.nist.gov/19.23.E6_5. If one of the arguments is zero, it * is more efficient to call the two-argument version of this function with * the non-zero arguments. **********************************************************************/ static real RG(real x, real y, real z); /** * Complete symmetric integral of the second kind, * RG with one argument zero. * * @param[in] x * @param[in] y * @return RG(\e x, \e y, 0). * * The arguments \e x and \e y must be positive. **********************************************************************/ static real RG(real x, real y); /** * Symmetric integral of the third kind RJ. * * @param[in] x * @param[in] y * @param[in] z * @param[in] p * @return RJ(\e x, \e y, \e z, \e p). * * RJ is defined in https://dlmf.nist.gov/19.16.E2 * \f[ R_J(x, y, z, p) = \frac32 * \int_0^\infty * [(t + x) (t + y) (t + z)]^{-1/2} (t + p)^{-1}\, dt, \f] * where \e p > 0, and \e x, \e y, \e z are nonnegative with at most one of * them being 0. **********************************************************************/ static real RJ(real x, real y, real z, real p); /** * Degenerate symmetric integral of the third kind * RD. * * @param[in] x * @param[in] y * @param[in] z * @return RD(\e x, \e y, \e z) = * RJ(\e x, \e y, \e z, \e z). * * RD is defined in https://dlmf.nist.gov/19.16.E5 * \f[ R_D(x, y, z) = \frac32 * \int_0^\infty[(t + x) (t + y)]^{-1/2} (t + z)^{-3/2}\, dt, \f] * where \e x, \e y, \e z are positive except that at most one of \e x and * \e y can be 0. **********************************************************************/ static real RD(real x, real y, real z); ///@} }; } // namespace GeographicLib #endif // GEOGRAPHICLIB_ELLIPTICFUNCTION_HPP geosphere/src/GeodesicLineExact.h0000644000176200001440000007277314323377037016543 0ustar liggesusers/** * \file GeodesicLineExact.hpp * \brief Header for GeographicLib::GeodesicLineExact class * * Copyright (c) Charles Karney (2012-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_GEODESICLINEEXACT_HPP) #define GEOGRAPHICLIB_GEODESICLINEEXACT_HPP 1 #include "Constants.h" #include "GeodesicExact.h" #include "EllipticFunction.h" #include namespace GeographicLib { /** * \brief An exact geodesic line * * GeodesicLineExact facilitates the determination of a series of points on a * single geodesic. This is a companion to the GeodesicExact class. For * additional information on this class see the documentation on the * GeodesicLine class. * * Example of use: * \include example-GeodesicLineExact.cpp * * GeodSolve is a command-line utility * providing access to the functionality of GeodesicExact and * GeodesicLineExact (via the -E option). **********************************************************************/ class GeodesicLineExact { private: typedef Math::real real; friend class GeodesicExact; int _nC4; real tiny_; real _lat1, _lon1, _azi1; real _a, _f, _b, _c2, _f1, _e2, _salp0, _calp0, _k2, _salp1, _calp1, _ssig1, _csig1, _dn1, _stau1, _ctau1, _somg1, _comg1, _cchi1, _aA4, _eE0, _dD0, _hH0, _eE1, _dD1, _hH1; real _a13, _s13; real _bB41; std::vector _cC4a; EllipticFunction _eE; unsigned _caps; void LineInit(const GeodesicExact& g, real lat1, real lon1, real azi1, real salp1, real calp1, unsigned caps); GeodesicLineExact(const GeodesicExact& g, real lat1, real lon1, real azi1, real salp1, real calp1, unsigned caps, bool arcmode, real s13_a13); enum captype { CAP_NONE = GeodesicExact::CAP_NONE, CAP_E = GeodesicExact::CAP_E, CAP_D = GeodesicExact::CAP_D, CAP_H = GeodesicExact::CAP_H, CAP_C4 = GeodesicExact::CAP_C4, CAP_ALL = GeodesicExact::CAP_ALL, CAP_MASK = GeodesicExact::CAP_MASK, OUT_ALL = GeodesicExact::OUT_ALL, OUT_MASK = GeodesicExact::OUT_MASK, }; public: /** * Bit masks for what calculations to do. They signify to the * GeodesicLineExact::GeodesicLineExact constructor and to * GeodesicExact::Line what capabilities should be included in the * GeodesicLineExact object. This is merely a duplication of * GeodesicExact::mask. **********************************************************************/ enum mask { /** * No capabilities, no output. * @hideinitializer **********************************************************************/ NONE = GeodesicExact::NONE, /** * Calculate latitude \e lat2. (It's not necessary to include this as a * capability to GeodesicLineExact because this is included by default.) * @hideinitializer **********************************************************************/ LATITUDE = GeodesicExact::LATITUDE, /** * Calculate longitude \e lon2. * @hideinitializer **********************************************************************/ LONGITUDE = GeodesicExact::LONGITUDE, /** * Calculate azimuths \e azi1 and \e azi2. (It's not necessary to * include this as a capability to GeodesicLineExact because this is * included by default.) * @hideinitializer **********************************************************************/ AZIMUTH = GeodesicExact::AZIMUTH, /** * Calculate distance \e s12. * @hideinitializer **********************************************************************/ DISTANCE = GeodesicExact::DISTANCE, /** * A combination of the common capabilities: GeodesicLineExact::LATITUDE, * GeodesicLineExact::LONGITUDE, GeodesicLineExact::AZIMUTH, * GeodesicLineExact::DISTANCE. * @hideinitializer **********************************************************************/ STANDARD = GeodesicExact::STANDARD, /** * Allow distance \e s12 to be used as input in the direct geodesic * problem. * @hideinitializer **********************************************************************/ DISTANCE_IN = GeodesicExact::DISTANCE_IN, /** * Calculate reduced length \e m12. * @hideinitializer **********************************************************************/ REDUCEDLENGTH = GeodesicExact::REDUCEDLENGTH, /** * Calculate geodesic scales \e M12 and \e M21. * @hideinitializer **********************************************************************/ GEODESICSCALE = GeodesicExact::GEODESICSCALE, /** * Calculate area \e S12. * @hideinitializer **********************************************************************/ AREA = GeodesicExact::AREA, /** * Unroll \e lon2 in the direct calculation. * @hideinitializer **********************************************************************/ LONG_UNROLL = GeodesicExact::LONG_UNROLL, /** * All capabilities, calculate everything. (LONG_UNROLL is not * included in this mask.) * @hideinitializer **********************************************************************/ ALL = GeodesicExact::ALL, }; /** \name Constructors **********************************************************************/ ///@{ /** * Constructor for a geodesic line staring at latitude \e lat1, longitude * \e lon1, and azimuth \e azi1 (all in degrees). * * @param[in] g A GeodesicExact object used to compute the necessary * information about the GeodesicLineExact. * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] caps bitor'ed combination of GeodesicLineExact::mask values * specifying the capabilities the GeodesicLineExact object should * possess, i.e., which quantities can be returned in calls to * GeodesicLine::Position. * * \e lat1 should be in the range [−90°, 90°]. * * The GeodesicLineExact::mask values are * - \e caps |= GeodesicLineExact::LATITUDE for the latitude \e lat2; this * is added automatically; * - \e caps |= GeodesicLineExact::LONGITUDE for the latitude \e lon2; * - \e caps |= GeodesicLineExact::AZIMUTH for the latitude \e azi2; this * is added automatically; * - \e caps |= GeodesicLineExact::DISTANCE for the distance \e s12; * - \e caps |= GeodesicLineExact::REDUCEDLENGTH for the reduced length \e * m12; * - \e caps |= GeodesicLineExact::GEODESICSCALE for the geodesic scales \e * M12 and \e M21; * - \e caps |= GeodesicLineExact::AREA for the area \e S12; * - \e caps |= GeodesicLineExact::DISTANCE_IN permits the length of the * geodesic to be given in terms of \e s12; without this capability the * length can only be specified in terms of arc length; * - \e caps |= GeodesicLineExact::ALL for all of the above. * . * The default value of \e caps is GeodesicLineExact::ALL. * * If the point is at a pole, the azimuth is defined by keeping \e lon1 * fixed, writing \e lat1 = ±(90° − ε), and taking * the limit ε → 0+. **********************************************************************/ GEOGRAPHICLIB_EXPORT GeodesicLineExact(const GeodesicExact& g, real lat1, real lon1, real azi1, unsigned caps = ALL); /** * A default constructor. If GeodesicLineExact::Position is called on the * resulting object, it returns immediately (without doing any * calculations). The object can be set with a call to * GeodesicExact::Line. Use Init() to test whether object is still in this * uninitialized state. **********************************************************************/ GEOGRAPHICLIB_EXPORT GeodesicLineExact() : _caps(0U) {} ///@} /** \name Position in terms of distance **********************************************************************/ ///@{ /** * Compute the position of point 2 which is a distance \e s12 (meters) * from point 1. * * @param[in] s12 distance from point 1 to point 2 (meters); it can be * signed. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees); requires that the * GeodesicLineExact object was constructed with \e caps |= * GeodesicLineExact::LONGITUDE. * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] m12 reduced length of geodesic (meters); requires that the * GeodesicLineExact object was constructed with \e caps |= * GeodesicLineExact::REDUCEDLENGTH. * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless); requires that the GeodesicLineExact object was * constructed with \e caps |= GeodesicLineExact::GEODESICSCALE. * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless); requires that the GeodesicLineExact object was * constructed with \e caps |= GeodesicLineExact::GEODESICSCALE. * @param[out] S12 area under the geodesic (meters2); requires * that the GeodesicLineExact object was constructed with \e caps |= * GeodesicLineExact::AREA. * @return \e a12 arc length from point 1 to point 2 (degrees). * * The values of \e lon2 and \e azi2 returned are in the range * [−180°, 180°]. * * The GeodesicLineExact object \e must have been constructed with \e caps * |= GeodesicLineExact::DISTANCE_IN; otherwise Math::NaN() is returned and * no parameters are set. Requesting a value which the GeodesicLineExact * object is not capable of computing is not an error; the corresponding * argument will not be altered. * * The following functions are overloaded versions of * GeodesicLineExact::Position which omit some of the output parameters. * Note, however, that the arc length is always computed and returned as * the function value. **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT Position(real s12, real& lat2, real& lon2, real& azi2, real& m12, real& M12, real& M21, real& S12) const { real t; return GenPosition(false, s12, LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH | GEODESICSCALE | AREA, lat2, lon2, azi2, t, m12, M12, M21, S12); } /** * See the documentation for GeodesicLineExact::Position. **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT Position(real s12, real& lat2, real& lon2) const { real t; return GenPosition(false, s12, LATITUDE | LONGITUDE, lat2, lon2, t, t, t, t, t, t); } /** * See the documentation for GeodesicLineExact::Position. **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT Position(real s12, real& lat2, real& lon2, real& azi2) const { real t; return GenPosition(false, s12, LATITUDE | LONGITUDE | AZIMUTH, lat2, lon2, azi2, t, t, t, t, t); } /** * See the documentation for GeodesicLineExact::Position. **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT Position(real s12, real& lat2, real& lon2, real& azi2, real& m12) const { real t; return GenPosition(false, s12, LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH, lat2, lon2, azi2, t, m12, t, t, t); } /** * See the documentation for GeodesicLineExact::Position. **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT Position(real s12, real& lat2, real& lon2, real& azi2, real& M12, real& M21) const { real t; return GenPosition(false, s12, LATITUDE | LONGITUDE | AZIMUTH | GEODESICSCALE, lat2, lon2, azi2, t, t, M12, M21, t); } /** * See the documentation for GeodesicLineExact::Position. **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT Position(real s12, real& lat2, real& lon2, real& azi2, real& m12, real& M12, real& M21) const { real t; return GenPosition(false, s12, LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH | GEODESICSCALE, lat2, lon2, azi2, t, m12, M12, M21, t); } ///@} /** \name Position in terms of arc length **********************************************************************/ ///@{ /** * Compute the position of point 2 which is an arc length \e a12 (degrees) * from point 1. * * @param[in] a12 arc length from point 1 to point 2 (degrees); it can * be signed. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees); requires that the * GeodesicLineExact object was constructed with \e caps |= * GeodesicLineExact::LONGITUDE. * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] s12 distance from point 1 to point 2 (meters); requires * that the GeodesicLineExact object was constructed with \e caps |= * GeodesicLineExact::DISTANCE. * @param[out] m12 reduced length of geodesic (meters); requires that the * GeodesicLineExact object was constructed with \e caps |= * GeodesicLineExact::REDUCEDLENGTH. * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless); requires that the GeodesicLineExact object was * constructed with \e caps |= GeodesicLineExact::GEODESICSCALE. * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless); requires that the GeodesicLineExact object was * constructed with \e caps |= GeodesicLineExact::GEODESICSCALE. * @param[out] S12 area under the geodesic (meters2); requires * that the GeodesicLineExact object was constructed with \e caps |= * GeodesicLineExact::AREA. * * The values of \e lon2 and \e azi2 returned are in the range * [−180°, 180°]. * * Requesting a value which the GeodesicLineExact object is not capable of * computing is not an error; the corresponding argument will not be * altered. * * The following functions are overloaded versions of * GeodesicLineExact::ArcPosition which omit some of the output parameters. **********************************************************************/ void GEOGRAPHICLIB_EXPORT ArcPosition(real a12, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21, real& S12) const { GenPosition(true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | REDUCEDLENGTH | GEODESICSCALE | AREA, lat2, lon2, azi2, s12, m12, M12, M21, S12); } /** * See the documentation for GeodesicLineExact::ArcPosition. **********************************************************************/ void GEOGRAPHICLIB_EXPORT ArcPosition(real a12, real& lat2, real& lon2) const { real t; GenPosition(true, a12, LATITUDE | LONGITUDE, lat2, lon2, t, t, t, t, t, t); } /** * See the documentation for GeodesicLineExact::ArcPosition. **********************************************************************/ void GEOGRAPHICLIB_EXPORT ArcPosition(real a12, real& lat2, real& lon2, real& azi2) const { real t; GenPosition(true, a12, LATITUDE | LONGITUDE | AZIMUTH, lat2, lon2, azi2, t, t, t, t, t); } /** * See the documentation for GeodesicLineExact::ArcPosition. **********************************************************************/ void GEOGRAPHICLIB_EXPORT ArcPosition(real a12, real& lat2, real& lon2, real& azi2, real& s12) const { real t; GenPosition(true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE, lat2, lon2, azi2, s12, t, t, t, t); } /** * See the documentation for GeodesicLineExact::ArcPosition. **********************************************************************/ void GEOGRAPHICLIB_EXPORT ArcPosition(real a12, real& lat2, real& lon2, real& azi2, real& s12, real& m12) const { real t; GenPosition(true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | REDUCEDLENGTH, lat2, lon2, azi2, s12, m12, t, t, t); } /** * See the documentation for GeodesicLineExact::ArcPosition. **********************************************************************/ void GEOGRAPHICLIB_EXPORT ArcPosition(real a12, real& lat2, real& lon2, real& azi2, real& s12, real& M12, real& M21) const { real t; GenPosition(true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | GEODESICSCALE, lat2, lon2, azi2, s12, t, M12, M21, t); } /** * See the documentation for GeodesicLineExact::ArcPosition. **********************************************************************/ void GEOGRAPHICLIB_EXPORT ArcPosition(real a12, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21) const { real t; GenPosition(true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | REDUCEDLENGTH | GEODESICSCALE, lat2, lon2, azi2, s12, m12, M12, M21, t); } ///@} /** \name The general position function. **********************************************************************/ ///@{ /** * The general position function. GeodesicLineExact::Position and * GeodesicLineExact::ArcPosition are defined in terms of this function. * * @param[in] arcmode boolean flag determining the meaning of the second * parameter; if \e arcmode is false, then the GeodesicLineExact object * must have been constructed with \e caps |= * GeodesicLineExact::DISTANCE_IN. * @param[in] s12_a12 if \e arcmode is false, this is the distance between * point 1 and point 2 (meters); otherwise it is the arc length between * point 1 and point 2 (degrees); it can be signed. * @param[in] outmask a bitor'ed combination of GeodesicLineExact::mask * values specifying which of the following parameters should be set. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees); requires that the * GeodesicLineExact object was constructed with \e caps |= * GeodesicLineExact::LONGITUDE. * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] s12 distance from point 1 to point 2 (meters); requires * that the GeodesicLineExact object was constructed with \e caps |= * GeodesicLineExact::DISTANCE. * @param[out] m12 reduced length of geodesic (meters); requires that the * GeodesicLineExact object was constructed with \e caps |= * GeodesicLineExact::REDUCEDLENGTH. * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless); requires that the GeodesicLineExact object was * constructed with \e caps |= GeodesicLineExact::GEODESICSCALE. * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless); requires that the GeodesicLineExact object was * constructed with \e caps |= GeodesicLineExact::GEODESICSCALE. * @param[out] S12 area under the geodesic (meters2); requires * that the GeodesicLineExact object was constructed with \e caps |= * GeodesicLineExact::AREA. * @return \e a12 arc length from point 1 to point 2 (degrees). * * The GeodesicLineExact::mask values possible for \e outmask are * - \e outmask |= GeodesicLineExact::LATITUDE for the latitude \e lat2; * - \e outmask |= GeodesicLineExact::LONGITUDE for the latitude \e lon2; * - \e outmask |= GeodesicLineExact::AZIMUTH for the latitude \e azi2; * - \e outmask |= GeodesicLineExact::DISTANCE for the distance \e s12; * - \e outmask |= GeodesicLineExact::REDUCEDLENGTH for the reduced length * \e m12; * - \e outmask |= GeodesicLineExact::GEODESICSCALE for the geodesic scales * \e M12 and \e M21; * - \e outmask |= GeodesicLineExact::AREA for the area \e S12; * - \e outmask |= GeodesicLineExact::ALL for all of the above; * - \e outmask |= GeodesicLineExact::LONG_UNROLL to unroll \e lon2 instead * of wrapping it into the range [−180°, 180°]. * . * Requesting a value which the GeodesicLineExact object is not capable of * computing is not an error; the corresponding argument will not be * altered. Note, however, that the arc length is always computed and * returned as the function value. * * With the GeodesicLineExact::LONG_UNROLL bit set, the quantity \e lon2 * − \e lon1 indicates how many times and in what sense the geodesic * encircles the ellipsoid. **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT GenPosition(bool arcmode, real s12_a12, unsigned outmask, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21, real& S12) const; ///@} /** \name Setting point 3 **********************************************************************/ ///@{ /** * Specify position of point 3 in terms of distance. * * @param[in] s13 the distance from point 1 to point 3 (meters); it * can be negative. * * This is only useful if the GeodesicLineExact object has been constructed * with \e caps |= GeodesicLineExact::DISTANCE_IN. **********************************************************************/ void GEOGRAPHICLIB_EXPORT SetDistance(real s13); /** * Specify position of point 3 in terms of arc length. * * @param[in] a13 the arc length from point 1 to point 3 (degrees); it * can be negative. * * The distance \e s13 is only set if the GeodesicLineExact object has been * constructed with \e caps |= GeodesicLineExact::DISTANCE. **********************************************************************/ void GEOGRAPHICLIB_EXPORT SetArc(real a13); /** * Specify position of point 3 in terms of either distance or arc length. * * @param[in] arcmode boolean flag determining the meaning of the second * parameter; if \e arcmode is false, then the GeodesicLineExact object * must have been constructed with \e caps |= * GeodesicLineExact::DISTANCE_IN. * @param[in] s13_a13 if \e arcmode is false, this is the distance from * point 1 to point 3 (meters); otherwise it is the arc length from * point 1 to point 3 (degrees); it can be negative. **********************************************************************/ void GEOGRAPHICLIB_EXPORT GenSetDistance(bool arcmode, real s13_a13); /** \name Inspector functions **********************************************************************/ ///@{ /** * @return true if the object has been initialized. **********************************************************************/ bool GEOGRAPHICLIB_EXPORT Init() const { return _caps != 0U; } /** * @return \e lat1 the latitude of point 1 (degrees). **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT Latitude() const { return Init() ? _lat1 : Math::NaN(); } /** * @return \e lon1 the longitude of point 1 (degrees). **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT Longitude() const { return Init() ? _lon1 : Math::NaN(); } /** * @return \e azi1 the azimuth (degrees) of the geodesic line at point 1. **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT Azimuth() const { return Init() ? _azi1 : Math::NaN(); } /** * The sine and cosine of \e azi1. * * @param[out] sazi1 the sine of \e azi1. * @param[out] cazi1 the cosine of \e azi1. **********************************************************************/ void GEOGRAPHICLIB_EXPORT Azimuth(real& sazi1, real& cazi1) const { if (Init()) { sazi1 = _salp1; cazi1 = _calp1; } } /** * @return \e azi0 the azimuth (degrees) of the geodesic line as it crosses * the equator in a northward direction. * * The result lies in [−90°, 90°]. **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT EquatorialAzimuth() const { return Init() ? Math::atan2d(_salp0, _calp0) : Math::NaN(); } /** * The sine and cosine of \e azi0. * * @param[out] sazi0 the sine of \e azi0. * @param[out] cazi0 the cosine of \e azi0. **********************************************************************/ void GEOGRAPHICLIB_EXPORT EquatorialAzimuth(real& sazi0, real& cazi0) const { if (Init()) { sazi0 = _salp0; cazi0 = _calp0; } } /** * @return \e a1 the arc length (degrees) between the northward equatorial * crossing and point 1. * * The result lies in [−180°, 180°]. **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT EquatorialArc() const { using std::atan2; return Init() ? atan2(_ssig1, _csig1) / Math::degree() : Math::NaN(); } /** * @return \e a the equatorial radius of the ellipsoid (meters). This is * the value inherited from the GeodesicExact object used in the * constructor. **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT EquatorialRadius() const { return Init() ? _a : Math::NaN(); } /** * @return \e f the flattening of the ellipsoid. This is the value * inherited from the GeodesicExact object used in the constructor. **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT Flattening() const { return Init() ? _f : Math::NaN(); } /** * @return \e caps the computational capabilities that this object was * constructed with. LATITUDE and AZIMUTH are always included. **********************************************************************/ unsigned GEOGRAPHICLIB_EXPORT Capabilities() const { return _caps; } /** * Test what capabilities are available. * * @param[in] testcaps a set of bitor'ed GeodesicLineExact::mask values. * @return true if the GeodesicLineExact object has all these capabilities. **********************************************************************/ bool GEOGRAPHICLIB_EXPORT Capabilities(unsigned testcaps) const { testcaps &= OUT_ALL; return (_caps & testcaps) == testcaps; } /** * The distance or arc length to point 3. * * @param[in] arcmode boolean flag determining the meaning of returned * value. * @return \e s13 if \e arcmode is false; \e a13 if \e arcmode is true. **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT GenDistance(bool arcmode) const { return Init() ? (arcmode ? _a13 : _s13) : Math::NaN(); } /** * @return \e s13, the distance to point 3 (meters). **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT Distance() const { return GenDistance(false); } /** * @return \e a13, the arc length to point 3 (degrees). **********************************************************************/ Math::real GEOGRAPHICLIB_EXPORT Arc() const { return GenDistance(true); } ///@} }; } // namespace GeographicLib #endif // GEOGRAPHICLIB_GEODESICLINEEXACT_HPP geosphere/src/AlbersEqualArea.cpp0000644000176200001440000005310614323376011016524 0ustar liggesusers/** * \file AlbersEqualArea.cpp * \brief Implementation for GeographicLib::AlbersEqualArea class * * Copyright (c) Charles Karney (2010-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #include "AlbersEqualArea.h" #if defined(_MSC_VER) // Squelch warnings about constant conditional and enum-float expressions # pragma warning (disable: 4127 5055) #endif namespace GeographicLib { using namespace std; AlbersEqualArea::AlbersEqualArea(real a, real f, real stdlat, real k0) : eps_(numeric_limits::epsilon()) , epsx_(Math::sq(eps_)) , epsx2_(Math::sq(epsx_)) , tol_(sqrt(eps_)) , tol0_(tol_ * sqrt(sqrt(eps_))) , _a(a) , _f(f) , _fm(1 - _f) , _e2(_f * (2 - _f)) , _e(sqrt(fabs(_e2))) , _e2m(1 - _e2) , _qZ(1 + _e2m * atanhee(real(1))) , _qx(_qZ / ( 2 * _e2m )) { if (!(isfinite(_a) && _a > 0)) throw GeographicErr("Equatorial radius is not positive"); if (!(isfinite(_f) && _f < 1)) throw GeographicErr("Polar semi-axis is not positive"); if (!(isfinite(k0) && k0 > 0)) throw GeographicErr("Scale is not positive"); if (!(fabs(stdlat) <= Math::qd)) throw GeographicErr("Standard latitude not in [-" + to_string(Math::qd) + "d, " + to_string(Math::qd) + "d]"); real sphi, cphi; Math::sincosd(stdlat, sphi, cphi); Init(sphi, cphi, sphi, cphi, k0); } AlbersEqualArea::AlbersEqualArea(real a, real f, real stdlat1, real stdlat2, real k1) : eps_(numeric_limits::epsilon()) , epsx_(Math::sq(eps_)) , epsx2_(Math::sq(epsx_)) , tol_(sqrt(eps_)) , tol0_(tol_ * sqrt(sqrt(eps_))) , _a(a) , _f(f) , _fm(1 - _f) , _e2(_f * (2 - _f)) , _e(sqrt(fabs(_e2))) , _e2m(1 - _e2) , _qZ(1 + _e2m * atanhee(real(1))) , _qx(_qZ / ( 2 * _e2m )) { if (!(isfinite(_a) && _a > 0)) throw GeographicErr("Equatorial radius is not positive"); if (!(isfinite(_f) && _f < 1)) throw GeographicErr("Polar semi-axis is not positive"); if (!(isfinite(k1) && k1 > 0)) throw GeographicErr("Scale is not positive"); if (!(fabs(stdlat1) <= Math::qd)) throw GeographicErr("Standard latitude 1 not in [-" + to_string(Math::qd) + "d, " + to_string(Math::qd) + "d]"); if (!(fabs(stdlat2) <= Math::qd)) throw GeographicErr("Standard latitude 2 not in [-" + to_string(Math::qd) + "d, " + to_string(Math::qd) + "d]"); real sphi1, cphi1, sphi2, cphi2; Math::sincosd(stdlat1, sphi1, cphi1); Math::sincosd(stdlat2, sphi2, cphi2); Init(sphi1, cphi1, sphi2, cphi2, k1); } AlbersEqualArea::AlbersEqualArea(real a, real f, real sinlat1, real coslat1, real sinlat2, real coslat2, real k1) : eps_(numeric_limits::epsilon()) , epsx_(Math::sq(eps_)) , epsx2_(Math::sq(epsx_)) , tol_(sqrt(eps_)) , tol0_(tol_ * sqrt(sqrt(eps_))) , _a(a) , _f(f) , _fm(1 - _f) , _e2(_f * (2 - _f)) , _e(sqrt(fabs(_e2))) , _e2m(1 - _e2) , _qZ(1 + _e2m * atanhee(real(1))) , _qx(_qZ / ( 2 * _e2m )) { if (!(isfinite(_a) && _a > 0)) throw GeographicErr("Equatorial radius is not positive"); if (!(isfinite(_f) && _f < 1)) throw GeographicErr("Polar semi-axis is not positive"); if (!(isfinite(k1) && k1 > 0)) throw GeographicErr("Scale is not positive"); if (signbit(coslat1)) throw GeographicErr("Standard latitude 1 not in [-" + to_string(Math::qd) + "d, " + to_string(Math::qd) + "d]"); if (signbit(coslat2)) throw GeographicErr("Standard latitude 2 not in [-" + to_string(Math::qd) + "d, " + to_string(Math::qd) + "d]"); if (!(fabs(sinlat1) <= 1 && coslat1 <= 1) || (coslat1 == 0 && sinlat1 == 0)) throw GeographicErr("Bad sine/cosine of standard latitude 1"); if (!(fabs(sinlat2) <= 1 && coslat2 <= 1) || (coslat2 == 0 && sinlat2 == 0)) throw GeographicErr("Bad sine/cosine of standard latitude 2"); if (coslat1 == 0 && coslat2 == 0 && sinlat1 * sinlat2 <= 0) throw GeographicErr ("Standard latitudes cannot be opposite poles"); Init(sinlat1, coslat1, sinlat2, coslat2, k1); } void AlbersEqualArea::Init(real sphi1, real cphi1, real sphi2, real cphi2, real k1) { { real r; r = hypot(sphi1, cphi1); sphi1 /= r; cphi1 /= r; r = hypot(sphi2, cphi2); sphi2 /= r; cphi2 /= r; } bool polar = (cphi1 == 0); cphi1 = fmax(epsx_, cphi1); // Avoid singularities at poles cphi2 = fmax(epsx_, cphi2); // Determine hemisphere of tangent latitude _sign = sphi1 + sphi2 >= 0 ? 1 : -1; // Internally work with tangent latitude positive sphi1 *= _sign; sphi2 *= _sign; if (sphi1 > sphi2) { swap(sphi1, sphi2); swap(cphi1, cphi2); // Make phi1 < phi2 } real tphi1 = sphi1/cphi1, tphi2 = sphi2/cphi2; // q = (1-e^2)*(sphi/(1-e^2*sphi^2) - atanhee(sphi)) // qZ = q(pi/2) = (1 + (1-e^2)*atanhee(1)) // atanhee(x) = atanh(e*x)/e // q = sxi * qZ // dq/dphi = 2*(1-e^2)*cphi/(1-e^2*sphi^2)^2 // // n = (m1^2-m2^2)/(q2-q1) -> sin(phi0) for phi1, phi2 -> phi0 // C = m1^2 + n*q1 = (m1^2*q2-m2^2*q1)/(q2-q1) // let // rho(pi/2)/rho(-pi/2) = (1-s)/(1+s) // s = n*qZ/C // = qZ * (m1^2-m2^2)/(m1^2*q2-m2^2*q1) // = qZ * (scbet2^2 - scbet1^2)/(scbet2^2*q2 - scbet1^2*q1) // = (scbet2^2 - scbet1^2)/(scbet2^2*sxi2 - scbet1^2*sxi1) // = (tbet2^2 - tbet1^2)/(scbet2^2*sxi2 - scbet1^2*sxi1) // 1-s = -((1-sxi2)*scbet2^2 - (1-sxi1)*scbet1^2)/ // (scbet2^2*sxi2 - scbet1^2*sxi1) // // Define phi0 to give same value of s, i.e., // s = sphi0 * qZ / (m0^2 + sphi0*q0) // = sphi0 * scbet0^2 / (1/qZ + sphi0 * scbet0^2 * sxi0) real tphi0, C; if (polar || tphi1 == tphi2) { tphi0 = tphi2; C = 1; // ignored } else { real tbet1 = _fm * tphi1, scbet12 = 1 + Math::sq(tbet1), tbet2 = _fm * tphi2, scbet22 = 1 + Math::sq(tbet2), txi1 = txif(tphi1), cxi1 = 1/hyp(txi1), sxi1 = txi1 * cxi1, txi2 = txif(tphi2), cxi2 = 1/hyp(txi2), sxi2 = txi2 * cxi2, dtbet2 = _fm * (tbet1 + tbet2), es1 = 1 - _e2 * Math::sq(sphi1), es2 = 1 - _e2 * Math::sq(sphi2), /* dsxi = ( (_e2 * sq(sphi2 + sphi1) + es2 + es1) / (2 * es2 * es1) + Datanhee(sphi2, sphi1) ) * Dsn(tphi2, tphi1, sphi2, sphi1) / ( 2 * _qx ), */ dsxi = ( (1 + _e2 * sphi1 * sphi2) / (es2 * es1) + Datanhee(sphi2, sphi1) ) * Dsn(tphi2, tphi1, sphi2, sphi1) / ( 2 * _qx ), den = (sxi2 + sxi1) * dtbet2 + (scbet22 + scbet12) * dsxi, // s = (sq(tbet2) - sq(tbet1)) / (scbet22*sxi2 - scbet12*sxi1) s = 2 * dtbet2 / den, // 1-s = -(sq(scbet2)*(1-sxi2) - sq(scbet1)*(1-sxi1)) / // (scbet22*sxi2 - scbet12*sxi1) // Write // sq(scbet)*(1-sxi) = sq(scbet)*(1-sphi) * (1-sxi)/(1-sphi) sm1 = -Dsn(tphi2, tphi1, sphi2, sphi1) * ( -( ((sphi2 <= 0 ? (1 - sxi2) / (1 - sphi2) : Math::sq(cxi2/cphi2) * (1 + sphi2) / (1 + sxi2)) + (sphi1 <= 0 ? (1 - sxi1) / (1 - sphi1) : Math::sq(cxi1/cphi1) * (1 + sphi1) / (1 + sxi1))) ) * (1 + _e2 * (sphi1 + sphi2 + sphi1 * sphi2)) / (1 + (sphi1 + sphi2 + sphi1 * sphi2)) + (scbet22 * (sphi2 <= 0 ? 1 - sphi2 : Math::sq(cphi2) / ( 1 + sphi2)) + scbet12 * (sphi1 <= 0 ? 1 - sphi1 : Math::sq(cphi1) / ( 1 + sphi1))) * (_e2 * (1 + sphi1 + sphi2 + _e2 * sphi1 * sphi2)/(es1 * es2) +_e2m * DDatanhee(sphi1, sphi2) ) / _qZ ) / den; // C = (scbet22*sxi2 - scbet12*sxi1) / (scbet22 * scbet12 * (sx2 - sx1)) C = den / (2 * scbet12 * scbet22 * dsxi); tphi0 = (tphi2 + tphi1)/2; real stol = tol0_ * fmax(real(1), fabs(tphi0)); for (int i = 0; i < 2*numit0_ || GEOGRAPHICLIB_PANIC; ++i) { // Solve (scbet0^2 * sphi0) / (1/qZ + scbet0^2 * sphi0 * sxi0) = s // for tphi0 by Newton's method on // v(tphi0) = (scbet0^2 * sphi0) - s * (1/qZ + scbet0^2 * sphi0 * sxi0) // = 0 // Alt: // (scbet0^2 * sphi0) / (1/qZ - scbet0^2 * sphi0 * (1-sxi0)) // = s / (1-s) // w(tphi0) = (1-s) * (scbet0^2 * sphi0) // - s * (1/qZ - scbet0^2 * sphi0 * (1-sxi0)) // = (1-s) * (scbet0^2 * sphi0) // - S/qZ * (1 - scbet0^2 * sphi0 * (qZ-q0)) // Now // qZ-q0 = (1+e2*sphi0)*(1-sphi0)/(1-e2*sphi0^2) + // (1-e2)*atanhee((1-sphi0)/(1-e2*sphi0)) // In limit sphi0 -> 1, qZ-q0 -> 2*(1-sphi0)/(1-e2), so wrte // qZ-q0 = 2*(1-sphi0)/(1-e2) + A + B // A = (1-sphi0)*( (1+e2*sphi0)/(1-e2*sphi0^2) - (1+e2)/(1-e2) ) // = -e2 *(1-sphi0)^2 * (2+(1+e2)*sphi0) / ((1-e2)*(1-e2*sphi0^2)) // B = (1-e2)*atanhee((1-sphi0)/(1-e2*sphi0)) - (1-sphi0) // = (1-sphi0)*(1-e2)/(1-e2*sphi0)* // ((atanhee(x)/x-1) - e2*(1-sphi0)/(1-e2)) // x = (1-sphi0)/(1-e2*sphi0), atanhee(x)/x = atanh(e*x)/(e*x) // // 1 - scbet0^2 * sphi0 * (qZ-q0) // = 1 - scbet0^2 * sphi0 * (2*(1-sphi0)/(1-e2) + A + B) // = D - scbet0^2 * sphi0 * (A + B) // D = 1 - scbet0^2 * sphi0 * 2*(1-sphi0)/(1-e2) // = (1-sphi0)*(1-e2*(1+2*sphi0*(1+sphi0)))/((1-e2)*(1+sphi0)) // dD/dsphi0 = -2*(1-e2*sphi0^2*(2*sphi0+3))/((1-e2)*(1+sphi0)^2) // d(A+B)/dsphi0 = 2*(1-sphi0^2)*e2*(2-e2*(1+sphi0^2))/ // ((1-e2)*(1-e2*sphi0^2)^2) real scphi02 = 1 + Math::sq(tphi0), scphi0 = sqrt(scphi02), // sphi0m = 1-sin(phi0) = 1/( sec(phi0) * (tan(phi0) + sec(phi0)) ) sphi0 = tphi0 / scphi0, sphi0m = 1/(scphi0 * (tphi0 + scphi0)), // scbet0^2 * sphi0 g = (1 + Math::sq( _fm * tphi0 )) * sphi0, // dg/dsphi0 = dg/dtphi0 * scphi0^3 dg = _e2m * scphi02 * (1 + 2 * Math::sq(tphi0)) + _e2, D = sphi0m * (1 - _e2*(1 + 2*sphi0*(1+sphi0))) / (_e2m * (1+sphi0)), // dD/dsphi0 dD = -2 * (1 - _e2*Math::sq(sphi0) * (2*sphi0+3)) / (_e2m * Math::sq(1+sphi0)), A = -_e2 * Math::sq(sphi0m) * (2+(1+_e2)*sphi0) / (_e2m*(1-_e2*Math::sq(sphi0))), B = (sphi0m * _e2m / (1 - _e2*sphi0) * (atanhxm1(_e2 * Math::sq(sphi0m / (1-_e2*sphi0))) - _e2*sphi0m/_e2m)), // d(A+B)/dsphi0 dAB = (2 * _e2 * (2 - _e2 * (1 + Math::sq(sphi0))) / (_e2m * Math::sq(1 - _e2*Math::sq(sphi0)) * scphi02)), u = sm1 * g - s/_qZ * ( D - g * (A + B) ), // du/dsphi0 du = sm1 * dg - s/_qZ * (dD - dg * (A + B) - g * dAB), dtu = -u/du * (scphi0 * scphi02); tphi0 += dtu; if (!(fabs(dtu) >= stol)) break; } } _txi0 = txif(tphi0); _scxi0 = hyp(_txi0); _sxi0 = _txi0 / _scxi0; _n0 = tphi0/hyp(tphi0); _m02 = 1 / (1 + Math::sq(_fm * tphi0)); _nrho0 = polar ? 0 : _a * sqrt(_m02); _k0 = sqrt(tphi1 == tphi2 ? 1 : C / (_m02 + _n0 * _qZ * _sxi0)) * k1; _k2 = Math::sq(_k0); _lat0 = _sign * atan(tphi0)/Math::degree(); } const AlbersEqualArea& AlbersEqualArea::CylindricalEqualArea() { static const AlbersEqualArea cylindricalequalarea(Constants::WGS84_a(), Constants::WGS84_f(), real(0), real(1), real(0), real(1), real(1)); return cylindricalequalarea; } const AlbersEqualArea& AlbersEqualArea::AzimuthalEqualAreaNorth() { static const AlbersEqualArea azimuthalequalareanorth(Constants::WGS84_a(), Constants::WGS84_f(), real(1), real(0), real(1), real(0), real(1)); return azimuthalequalareanorth; } const AlbersEqualArea& AlbersEqualArea::AzimuthalEqualAreaSouth() { static const AlbersEqualArea azimuthalequalareasouth(Constants::WGS84_a(), Constants::WGS84_f(), real(-1), real(0), real(-1), real(0), real(1)); return azimuthalequalareasouth; } Math::real AlbersEqualArea::txif(real tphi) const { // sxi = ( sphi/(1-e2*sphi^2) + atanhee(sphi) ) / // ( 1/(1-e2) + atanhee(1) ) // // txi = ( sphi/(1-e2*sphi^2) + atanhee(sphi) ) / // sqrt( ( (1+e2*sphi)*(1-sphi)/( (1-e2*sphi^2) * (1-e2) ) + // atanhee((1-sphi)/(1-e2*sphi)) ) * // ( (1-e2*sphi)*(1+sphi)/( (1-e2*sphi^2) * (1-e2) ) + // atanhee((1+sphi)/(1+e2*sphi)) ) ) // = ( tphi/(1-e2*sphi^2) + atanhee(sphi, e2)/cphi ) / // sqrt( // ( (1+e2*sphi)/( (1-e2*sphi^2) * (1-e2) ) + Datanhee(1, sphi) ) * // ( (1-e2*sphi)/( (1-e2*sphi^2) * (1-e2) ) + Datanhee(1, -sphi) ) ) // // This function maintains odd parity real cphi = 1 / sqrt(1 + Math::sq(tphi)), sphi = tphi * cphi, es1 = _e2 * sphi, es2m1 = 1 - es1 * sphi, // 1 - e2 * sphi^2 es2m1a = _e2m * es2m1; // (1 - e2 * sphi^2) * (1 - e2) return ( tphi / es2m1 + atanhee(sphi) / cphi ) / sqrt( ( (1 + es1) / es2m1a + Datanhee(1, sphi) ) * ( (1 - es1) / es2m1a + Datanhee(1, -sphi) ) ); } Math::real AlbersEqualArea::tphif(real txi) const { real tphi = txi, stol = tol_ * fmax(real(1), fabs(txi)); // CHECK: min iterations = 1, max iterations = 2; mean = 1.99 for (int i = 0; i < numit_ || GEOGRAPHICLIB_PANIC; ++i) { // dtxi/dtphi = (scxi/scphi)^3 * 2*(1-e^2)/(qZ*(1-e^2*sphi^2)^2) real txia = txif(tphi), tphi2 = Math::sq(tphi), scphi2 = 1 + tphi2, scterm = scphi2/(1 + Math::sq(txia)), dtphi = (txi - txia) * scterm * sqrt(scterm) * _qx * Math::sq(1 - _e2 * tphi2 / scphi2); tphi += dtphi; if (!(fabs(dtphi) >= stol)) break; } return tphi; } // return atanh(sqrt(x))/sqrt(x) - 1 = x/3 + x^2/5 + x^3/7 + ... // typical x < e^2 = 2*f Math::real AlbersEqualArea::atanhxm1(real x) { real s = 0; if (fabs(x) < real(0.5)) { static const real lg2eps_ = -log2(numeric_limits::epsilon() / 2); int e; frexp(x, &e); e = -e; // x = [0.5,1) * 2^(-e) // estimate n s.t. x^n/(2*n+1) < x/3 * epsilon/2 // a stronger condition is x^(n-1) < epsilon/2 // taking log2 of both sides, a stronger condition is // (n-1)*(-e) < -lg2eps or (n-1)*e > lg2eps or n > ceiling(lg2eps/e)+1 int n = x == 0 ? 1 : int(ceil(lg2eps_ / e)) + 1; while (n--) // iterating from n-1 down to 0 s = x * s + (n ? 1 : 0)/Math::real(2*n + 1); } else { real xs = sqrt(fabs(x)); s = (x > 0 ? atanh(xs) : atan(xs)) / xs - 1; } return s; } // return (Datanhee(1,y) - Datanhee(1,x))/(y-x) Math::real AlbersEqualArea::DDatanhee(real x, real y) const { // This function is called with x = sphi1, y = sphi2, phi1 <= phi2, sphi2 // >= 0, abs(sphi1) <= phi2. However for safety's sake we enforce x <= y. if (y < x) swap(x, y); // ensure that x <= y real q1 = fabs(_e2), q2 = fabs(2 * _e / _e2m * (1 - x)); return x <= 0 || !(fmin(q1, q2) < real(0.75)) ? DDatanhee0(x, y) : (q1 < q2 ? DDatanhee1(x, y) : DDatanhee2(x, y)); } // Rearrange difference so that 1 - x is in the denominator, then do a // straight divided difference. Math::real AlbersEqualArea::DDatanhee0(real x, real y) const { return (Datanhee(1, y) - Datanhee(x, y))/(1 - x); } // The expansion for e2 small Math::real AlbersEqualArea::DDatanhee1(real x, real y) const { // The series in e2 is // sum( c[l] * e2^l, l, 1, N) // where // c[l] = sum( x^i * y^j; i >= 0, j >= 0, i+j < 2*l) / (2*l + 1) // = ( (x-y) - (1-y) * x^(2*l+1) + (1-x) * y^(2*l+1) ) / // ( (2*l+1) * (x-y) * (1-y) * (1-x) ) // For x = y = 1, c[l] = l // // In the limit x,y -> 1, // // DDatanhee -> e2/(1-e2)^2 = sum(l * e2^l, l, 1, inf) // // Use if e2 is sufficiently small. real s = 0; real z = 1, k = 1, t = 0, c = 0, en = 1; while (true) { t = y * t + z; c += t; z *= x; t = y * t + z; c += t; z *= x; k += 2; en *= _e2; // Here en[l] = e2^l, k[l] = 2*l + 1, // c[l] = sum( x^i * y^j; i >= 0, j >= 0, i+j < 2*l) / (2*l + 1) // Taylor expansion is // s = sum( c[l] * e2^l, l, 1, N) real ds = en * c / k; s += ds; if (!(fabs(ds) > fabs(s) * eps_/2)) break; // Iterate until the added term is sufficiently small } return s; } // The expansion for x (and y) close to 1 Math::real AlbersEqualArea::DDatanhee2(real x, real y) const { // If x and y are both close to 1, expand in Taylor series in dx = 1-x and // dy = 1-y: // // DDatanhee = sum(C_m * (dx^(m+1) - dy^(m+1)) / (dx - dy), m, 0, inf) // // where // // C_m = sum( (m+2)!! / (m+2-2*k)!! * // ((m+1)/2)! / ((m+1)/2-k)! / // (k! * (2*k-1)!!) * // e2^((m+1)/2+k), // k, 0, (m+1)/2) * (-1)^m / ((m+2) * (1-e2)^(m+2)) // for m odd, and // // C_m = sum( 2 * (m+1)!! / (m+1-2*k)!! * // (m/2+1)! / (m/2-k)! / // (k! * (2*k+1)!!) * // e2^(m/2+1+k), // k, 0, m/2)) * (-1)^m / ((m+2) * (1-e2)^(m+2)) // for m even. // // Here i!! is the double factorial extended to negative i with // i!! = (i+2)!!/(i+2). // // Note that // (dx^(m+1) - dy^(m+1)) / (dx - dy) = // dx^m + dx^(m-1)*dy ... + dx*dy^(m-1) + dy^m // // Leading (m = 0) term is e2 / (1 - e2)^2 // // Magnitude of mth term relative to the leading term scales as // // 2*(2*e/(1-e2)*dx)^m // // So use series if (2*e/(1-e2)*dx) is sufficiently small real s, dx = 1 - x, dy = 1 - y, xy = 1, yy = 1, ee = _e2 / Math::sq(_e2m); s = ee; for (int m = 1; ; ++m) { real c = m + 2, t = c; yy *= dy; // yy = dy^m xy = dx * xy + yy; // Now xy = dx^m + dx^(m-1)*dy ... + dx*dy^(m-1) + dy^m // = (dx^(m+1) - dy^(m+1)) / (dx - dy) // max value = (m+1) * max(dx,dy)^m ee /= -_e2m; if (m % 2 == 0) ee *= _e2; // Now ee = (-1)^m * e2^(floor(m/2)+1) / (1-e2)^(m+2) int kmax = (m+1)/2; for (int k = kmax - 1; k >= 0; --k) { // max coeff is less than 2^(m+1) c *= (k + 1) * (2 * (k + m - 2*kmax) + 3); c /= (kmax - k) * (2 * (kmax - k) + 1); // Horner sum for inner _e2 series t = _e2 * t + c; } // Straight sum for outer m series real ds = t * ee * xy / (m + 2); s = s + ds; if (!(fabs(ds) > fabs(s) * eps_/2)) break; // Iterate until the added term is sufficiently small } return s; } void AlbersEqualArea::Forward(real lon0, real lat, real lon, real& x, real& y, real& gamma, real& k) const { lon = Math::AngDiff(lon0, lon); lat *= _sign; real sphi, cphi; Math::sincosd(Math::LatFix(lat) * _sign, sphi, cphi); cphi = fmax(epsx_, cphi); real lam = lon * Math::degree(), tphi = sphi/cphi, txi = txif(tphi), sxi = txi/hyp(txi), dq = _qZ * Dsn(txi, _txi0, sxi, _sxi0) * (txi - _txi0), drho = - _a * dq / (sqrt(_m02 - _n0 * dq) + _nrho0 / _a), theta = _k2 * _n0 * lam, stheta = sin(theta), ctheta = cos(theta), t = _nrho0 + _n0 * drho; x = t * (_n0 != 0 ? stheta / _n0 : _k2 * lam) / _k0; y = (_nrho0 * (_n0 != 0 ? (ctheta < 0 ? 1 - ctheta : Math::sq(stheta)/(1 + ctheta)) / _n0 : 0) - drho * ctheta) / _k0; k = _k0 * (t != 0 ? t * hyp(_fm * tphi) / _a : 1); y *= _sign; gamma = _sign * theta / Math::degree(); } void AlbersEqualArea::Reverse(real lon0, real x, real y, real& lat, real& lon, real& gamma, real& k) const { y *= _sign; real nx = _k0 * _n0 * x, ny = _k0 * _n0 * y, y1 = _nrho0 - ny, den = hypot(nx, y1) + _nrho0, // 0 implies origin with polar aspect drho = den != 0 ? (_k0*x*nx - 2*_k0*y*_nrho0 + _k0*y*ny) / den : 0, // dsxia = scxi0 * dsxi dsxia = - _scxi0 * (2 * _nrho0 + _n0 * drho) * drho / (Math::sq(_a) * _qZ), txi = (_txi0 + dsxia) / sqrt(fmax(1 - dsxia * (2*_txi0 + dsxia), epsx2_)), tphi = tphif(txi), theta = atan2(nx, y1), lam = _n0 != 0 ? theta / (_k2 * _n0) : x / (y1 * _k0); gamma = _sign * theta / Math::degree(); lat = Math::atand(_sign * tphi); lon = lam / Math::degree(); lon = Math::AngNormalize(lon + Math::AngNormalize(lon0)); k = _k0 * (den != 0 ? (_nrho0 + _n0 * drho) * hyp(_fm * tphi) / _a : 1); } void AlbersEqualArea::SetScale(real lat, real k) { if (!(isfinite(k) && k > 0)) throw GeographicErr("Scale is not positive"); if (!(fabs(lat) < Math::qd)) throw GeographicErr("Latitude for SetScale not in (-" + to_string(Math::qd) + "d, " + to_string(Math::qd) + "d)"); real x, y, gamma, kold; Forward(0, lat, 0, x, y, gamma, kold); k /= kold; _k0 *= k; _k2 = Math::sq(_k0); } } // namespace GeographicLib geosphere/src/AlbersEqualArea.h0000644000176200001440000003347314323377037016207 0ustar liggesusers/** * \file AlbersEqualArea.hpp * \brief Header for GeographicLib::AlbersEqualArea class * * Copyright (c) Charles Karney (2010-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_ALBERSEQUALAREA_HPP) #define GEOGRAPHICLIB_ALBERSEQUALAREA_HPP 1 #include "Constants.h" namespace GeographicLib { /** * \brief Albers equal area conic projection * * Implementation taken from the report, * - J. P. Snyder, * Map Projections: A * Working Manual, USGS Professional Paper 1395 (1987), * pp. 101--102. * * This is a implementation of the equations in Snyder except that divided * differences will be [have been] used to transform the expressions into * ones which may be evaluated accurately. [In this implementation, the * projection correctly becomes the cylindrical equal area or the azimuthal * equal area projection when the standard latitude is the equator or a * pole.] * * The ellipsoid parameters, the standard parallels, and the scale on the * standard parallels are set in the constructor. Internally, the case with * two standard parallels is converted into a single standard parallel, the * latitude of minimum azimuthal scale, with an azimuthal scale specified on * this parallel. This latitude is also used as the latitude of origin which * is returned by AlbersEqualArea::OriginLatitude. The azimuthal scale on * the latitude of origin is given by AlbersEqualArea::CentralScale. The * case with two standard parallels at opposite poles is singular and is * disallowed. The central meridian (which is a trivial shift of the * longitude) is specified as the \e lon0 argument of the * AlbersEqualArea::Forward and AlbersEqualArea::Reverse functions. * AlbersEqualArea::Forward and AlbersEqualArea::Reverse also return the * meridian convergence, γ, and azimuthal scale, \e k. A small square * aligned with the cardinal directions is projected to a rectangle with * dimensions \e k (in the E-W direction) and 1/\e k (in the N-S direction). * The E-W sides of the rectangle are oriented γ degrees * counter-clockwise from the \e x axis. There is no provision in this class * for specifying a false easting or false northing or a different latitude * of origin. * * Example of use: * \include example-AlbersEqualArea.cpp * * ConicProj is a command-line utility * providing access to the functionality of LambertConformalConic and * AlbersEqualArea. **********************************************************************/ class GEOGRAPHICLIB_EXPORT AlbersEqualArea { private: typedef Math::real real; real eps_, epsx_, epsx2_, tol_, tol0_; real _a, _f, _fm, _e2, _e, _e2m, _qZ, _qx; real _sign, _lat0, _k0; real _n0, _m02, _nrho0, _k2, _txi0, _scxi0, _sxi0; static const int numit_ = 5; // Newton iterations in Reverse static const int numit0_ = 20; // Newton iterations in Init static real hyp(real x) { using std::hypot; return hypot(real(1), x); } // atanh( e * x)/ e if f > 0 // atan (sqrt(-e2) * x)/sqrt(-e2) if f < 0 // x if f = 0 real atanhee(real x) const { using std::atan; using std::atanh; return _f > 0 ? atanh(_e * x)/_e : (_f < 0 ? (atan(_e * x)/_e) : x); } // return atanh(sqrt(x))/sqrt(x) - 1, accurate for small x static real atanhxm1(real x); // Divided differences // Definition: Df(x,y) = (f(x)-f(y))/(x-y) // See: // W. M. Kahan and R. J. Fateman, // Symbolic computation of divided differences, // SIGSAM Bull. 33(2), 7-28 (1999) // https://doi.org/10.1145/334714.334716 // http://www.cs.berkeley.edu/~fateman/papers/divdiff.pdf // // General rules // h(x) = f(g(x)): Dh(x,y) = Df(g(x),g(y))*Dg(x,y) // h(x) = f(x)*g(x): // Dh(x,y) = Df(x,y)*g(x) + Dg(x,y)*f(y) // = Df(x,y)*g(y) + Dg(x,y)*f(x) // = Df(x,y)*(g(x)+g(y))/2 + Dg(x,y)*(f(x)+f(y))/2 // // sn(x) = x/sqrt(1+x^2): Dsn(x,y) = (x+y)/((sn(x)+sn(y))*(1+x^2)*(1+y^2)) static real Dsn(real x, real y, real sx, real sy) { // sx = x/hyp(x) real t = x * y; return t > 0 ? (x + y) * Math::sq( (sx * sy)/t ) / (sx + sy) : (x - y != 0 ? (sx - sy) / (x - y) : 1); } // Datanhee(x,y) = (atanee(x)-atanee(y))/(x-y) // = atanhee((x-y)/(1-e^2*x*y))/(x-y) real Datanhee(real x, real y) const { real t = x - y, d = 1 - _e2 * x * y; return t == 0 ? 1 / d : (x*y < 0 ? atanhee(x) - atanhee(y) : atanhee(t / d)) / t; } // DDatanhee(x,y) = (Datanhee(1,y) - Datanhee(1,x))/(y-x) real DDatanhee(real x, real y) const; real DDatanhee0(real x, real y) const; real DDatanhee1(real x, real y) const; real DDatanhee2(real x, real y) const; void Init(real sphi1, real cphi1, real sphi2, real cphi2, real k1); real txif(real tphi) const; real tphif(real txi) const; friend class Ellipsoid; // For access to txif, tphif, etc. public: /** * Constructor with a single standard parallel. * * @param[in] a equatorial radius of ellipsoid (meters). * @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere. * Negative \e f gives a prolate ellipsoid. * @param[in] stdlat standard parallel (degrees), the circle of tangency. * @param[in] k0 azimuthal scale on the standard parallel. * @exception GeographicErr if \e a, (1 − \e f) \e a, or \e k0 is * not positive. * @exception GeographicErr if \e stdlat is not in [−90°, * 90°]. **********************************************************************/ AlbersEqualArea(real a, real f, real stdlat, real k0); /** * Constructor with two standard parallels. * * @param[in] a equatorial radius of ellipsoid (meters). * @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere. * Negative \e f gives a prolate ellipsoid. * @param[in] stdlat1 first standard parallel (degrees). * @param[in] stdlat2 second standard parallel (degrees). * @param[in] k1 azimuthal scale on the standard parallels. * @exception GeographicErr if \e a, (1 − \e f) \e a, or \e k1 is * not positive. * @exception GeographicErr if \e stdlat1 or \e stdlat2 is not in * [−90°, 90°], or if \e stdlat1 and \e stdlat2 are * opposite poles. **********************************************************************/ AlbersEqualArea(real a, real f, real stdlat1, real stdlat2, real k1); /** * Constructor with two standard parallels specified by sines and cosines. * * @param[in] a equatorial radius of ellipsoid (meters). * @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere. * Negative \e f gives a prolate ellipsoid. * @param[in] sinlat1 sine of first standard parallel. * @param[in] coslat1 cosine of first standard parallel. * @param[in] sinlat2 sine of second standard parallel. * @param[in] coslat2 cosine of second standard parallel. * @param[in] k1 azimuthal scale on the standard parallels. * @exception GeographicErr if \e a, (1 − \e f) \e a, or \e k1 is * not positive. * @exception GeographicErr if \e stdlat1 or \e stdlat2 is not in * [−90°, 90°], or if \e stdlat1 and \e stdlat2 are * opposite poles. * * This allows parallels close to the poles to be specified accurately. * This routine computes the latitude of origin and the azimuthal scale at * this latitude. If \e dlat = abs(\e lat2 − \e lat1) ≤ 160°, * then the error in the latitude of origin is less than 4.5 × * 10−14d;. **********************************************************************/ AlbersEqualArea(real a, real f, real sinlat1, real coslat1, real sinlat2, real coslat2, real k1); /** * Set the azimuthal scale for the projection. * * @param[in] lat (degrees). * @param[in] k azimuthal scale at latitude \e lat (default 1). * @exception GeographicErr \e k is not positive. * @exception GeographicErr if \e lat is not in (−90°, * 90°). * * This allows a "latitude of conformality" to be specified. **********************************************************************/ void SetScale(real lat, real k = real(1)); /** * Forward projection, from geographic to Lambert conformal conic. * * @param[in] lon0 central meridian longitude (degrees). * @param[in] lat latitude of point (degrees). * @param[in] lon longitude of point (degrees). * @param[out] x easting of point (meters). * @param[out] y northing of point (meters). * @param[out] gamma meridian convergence at point (degrees). * @param[out] k azimuthal scale of projection at point; the radial * scale is the 1/\e k. * * The latitude origin is given by AlbersEqualArea::LatitudeOrigin(). No * false easting or northing is added and \e lat should be in the range * [−90°, 90°]. The values of \e x and \e y returned for * points which project to infinity (i.e., one or both of the poles) will * be large but finite. **********************************************************************/ void Forward(real lon0, real lat, real lon, real& x, real& y, real& gamma, real& k) const; /** * Reverse projection, from Lambert conformal conic to geographic. * * @param[in] lon0 central meridian longitude (degrees). * @param[in] x easting of point (meters). * @param[in] y northing of point (meters). * @param[out] lat latitude of point (degrees). * @param[out] lon longitude of point (degrees). * @param[out] gamma meridian convergence at point (degrees). * @param[out] k azimuthal scale of projection at point; the radial * scale is the 1/\e k. * * The latitude origin is given by AlbersEqualArea::LatitudeOrigin(). No * false easting or northing is added. The value of \e lon returned is in * the range [−180°, 180°]. The value of \e lat returned is * in the range [−90°, 90°]. If the input point is outside * the legal projected space the nearest pole is returned. **********************************************************************/ void Reverse(real lon0, real x, real y, real& lat, real& lon, real& gamma, real& k) const; /** * AlbersEqualArea::Forward without returning the convergence and * scale. **********************************************************************/ void Forward(real lon0, real lat, real lon, real& x, real& y) const { real gamma, k; Forward(lon0, lat, lon, x, y, gamma, k); } /** * AlbersEqualArea::Reverse without returning the convergence and * scale. **********************************************************************/ void Reverse(real lon0, real x, real y, real& lat, real& lon) const { real gamma, k; Reverse(lon0, x, y, lat, lon, gamma, k); } /** \name Inspector functions **********************************************************************/ ///@{ /** * @return \e a the equatorial radius of the ellipsoid (meters). This is * the value used in the constructor. **********************************************************************/ Math::real EquatorialRadius() const { return _a; } /** * @return \e f the flattening of the ellipsoid. This is the value used in * the constructor. **********************************************************************/ Math::real Flattening() const { return _f; } /** * @return latitude of the origin for the projection (degrees). * * This is the latitude of minimum azimuthal scale and equals the \e stdlat * in the 1-parallel constructor and lies between \e stdlat1 and \e stdlat2 * in the 2-parallel constructors. **********************************************************************/ Math::real OriginLatitude() const { return _lat0; } /** * @return central scale for the projection. This is the azimuthal scale * on the latitude of origin. **********************************************************************/ Math::real CentralScale() const { return _k0; } ///@} /** * A global instantiation of AlbersEqualArea with the WGS84 ellipsoid, \e * stdlat = 0, and \e k0 = 1. This degenerates to the cylindrical equal * area projection. **********************************************************************/ static const AlbersEqualArea& CylindricalEqualArea(); /** * A global instantiation of AlbersEqualArea with the WGS84 ellipsoid, \e * stdlat = 90°, and \e k0 = 1. This degenerates to the * Lambert azimuthal equal area projection. **********************************************************************/ static const AlbersEqualArea& AzimuthalEqualAreaNorth(); /** * A global instantiation of AlbersEqualArea with the WGS84 ellipsoid, \e * stdlat = −90°, and \e k0 = 1. This degenerates to the * Lambert azimuthal equal area projection. **********************************************************************/ static const AlbersEqualArea& AzimuthalEqualAreaSouth(); }; } // namespace GeographicLib #endif // GEOGRAPHICLIB_ALBERSEQUALAREA_HPP geosphere/src/Accumulator.cpp0000644000176200001440000000113214323375571016014 0ustar liggesusers/** * \file Accumulator.cpp * \brief Implementation for GeographicLib::Accumulator class * * Copyright (c) Charles Karney (2013-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #include "Accumulator.h" namespace GeographicLib { /// \cond SKIP // Need to instantiate Accumulator to get the code into the shared library. template class GEOGRAPHICLIB_EXPORT Accumulator; /// \endcond } // namespace GeographicLib geosphere/src/Math.h0000644000176200001440000005021614323400305014062 0ustar liggesusers/** * \file Math.hpp * \brief Header for GeographicLib::Math class * * Copyright (c) Charles Karney (2008-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ // Constants.hpp includes Math.hpp. Place this include outside Math.hpp's // include guard to enforce this ordering. #include "Constants.h" #if !defined(GEOGRAPHICLIB_MATH_HPP) #define GEOGRAPHICLIB_MATH_HPP 1 #if !defined(GEOGRAPHICLIB_WORDS_BIGENDIAN) # define GEOGRAPHICLIB_WORDS_BIGENDIAN 0 #endif #if !defined(GEOGRAPHICLIB_HAVE_LONG_DOUBLE) # define GEOGRAPHICLIB_HAVE_LONG_DOUBLE 0 #endif #if !defined(GEOGRAPHICLIB_PRECISION) /** * The precision of floating point numbers used in %GeographicLib. 1 means * float (single precision); 2 (the default) means double; 3 means long double; * 4 is reserved for quadruple precision. Nearly all the testing has been * carried out with doubles and that's the recommended configuration. In order * for long double to be used, GEOGRAPHICLIB_HAVE_LONG_DOUBLE needs to be * defined. Note that with Microsoft Visual Studio, long double is the same as * double. **********************************************************************/ # define GEOGRAPHICLIB_PRECISION 2 #endif #include #include #include #if GEOGRAPHICLIB_PRECISION == 4 #include #include #include #elif GEOGRAPHICLIB_PRECISION == 5 #include #endif #if GEOGRAPHICLIB_PRECISION > 3 // volatile keyword makes no sense for multiprec types #define GEOGRAPHICLIB_VOLATILE // Signal a convergence failure with multiprec types by throwing an exception // at loop exit. #define GEOGRAPHICLIB_PANIC \ (throw GeographicLib::GeographicErr("Convergence failure"), false) #else #define GEOGRAPHICLIB_VOLATILE volatile // Ignore convergence failures with standard floating points types by allowing // loop to exit cleanly. #define GEOGRAPHICLIB_PANIC false #endif namespace GeographicLib { /** * \brief Mathematical functions needed by %GeographicLib * * Define mathematical functions in order to localize system dependencies and * to provide generic versions of the functions. In addition define a real * type to be used by %GeographicLib. * * Example of use: * \include example-Math.cpp **********************************************************************/ class GEOGRAPHICLIB_EXPORT Math { private: void dummy(); // Static check for GEOGRAPHICLIB_PRECISION Math() = delete; // Disable constructor public: #if GEOGRAPHICLIB_HAVE_LONG_DOUBLE /** * The extended precision type for real numbers, used for some testing. * This is long double on computers with this type; otherwise it is double. **********************************************************************/ typedef long double extended; #else typedef double extended; #endif #if GEOGRAPHICLIB_PRECISION == 2 /** * The real type for %GeographicLib. Nearly all the testing has been done * with \e real = double. However, the algorithms should also work with * float and long double (where available). (CAUTION: reasonable * accuracy typically cannot be obtained using floats.) **********************************************************************/ typedef double real; #elif GEOGRAPHICLIB_PRECISION == 1 typedef float real; #elif GEOGRAPHICLIB_PRECISION == 3 typedef extended real; #elif GEOGRAPHICLIB_PRECISION == 4 typedef boost::multiprecision::float128 real; #elif GEOGRAPHICLIB_PRECISION == 5 typedef mpfr::mpreal real; #else typedef double real; #endif /** * The constants defining the standard (Babylonian) meanings of degrees, * minutes, and seconds, for angles. Read the constants as follows (for * example): \e ms = 60 is the ratio 1 minute / 1 second. The * abbreviations are * - \e t a whole turn (360°) * - \e h a half turn (180°) * - \e q a quarter turn (a right angle = 90°) * - \e d a degree * - \e m a minute * - \e s a second * . * Note that degree() is ratio 1 degree / 1 radian, thus, for example, * Math::degree() * Math::qd is the ratio 1 quarter turn / 1 radian = * π/2. * * Defining all these in one place would mean that it's simple to convert * to the centesimal system for measuring angles. The DMS class assumes * that Math::dm and Math::ms are less than or equal to 100 (so that two * digits suffice for the integer parts of the minutes and degrees * components of an angle). Switching to the centesimal convention will * break most of the tests. Also the normal definition of degree is baked * into some classes, e.g., UTMUPS, MGRS, Georef, Geohash, etc. **********************************************************************/ #if GEOGRAPHICLIB_PRECISION == 4 static const int #else enum dms { #endif qd = 90, ///< degrees per quarter turn dm = 60, ///< minutes per degree ms = 60, ///< seconds per minute hd = 2 * qd, ///< degrees per half turn td = 2 * hd, ///< degrees per turn ds = dm * ms ///< seconds per degree #if GEOGRAPHICLIB_PRECISION == 4 ; #else }; #endif /** * @return the number of bits of precision in a real number. **********************************************************************/ static int digits(); /** * Set the binary precision of a real number. * * @param[in] ndigits the number of bits of precision. * @return the resulting number of bits of precision. * * This only has an effect when GEOGRAPHICLIB_PRECISION = 5. See also * Utility::set_digits for caveats about when this routine should be * called. **********************************************************************/ static int set_digits(int ndigits); /** * @return the number of decimal digits of precision in a real number. **********************************************************************/ static int digits10(); /** * Number of additional decimal digits of precision for real relative to * double (0 for float). **********************************************************************/ static int extra_digits(); /** * true if the machine is big-endian. **********************************************************************/ static const bool bigendian = GEOGRAPHICLIB_WORDS_BIGENDIAN; /** * @tparam T the type of the returned value. * @return π. **********************************************************************/ template static T pi() { using std::atan2; static const T pi = atan2(T(0), T(-1)); return pi; } /** * @tparam T the type of the returned value. * @return the number of radians in a degree. **********************************************************************/ template static T degree() { static const T degree = pi() / T(hd); return degree; } /** * Square a number. * * @tparam T the type of the argument and the returned value. * @param[in] x * @return x2. **********************************************************************/ template static T sq(T x) { return x * x; } /** * Normalize a two-vector. * * @tparam T the type of the argument and the returned value. * @param[in,out] x on output set to x/hypot(x, y). * @param[in,out] y on output set to y/hypot(x, y). **********************************************************************/ template static void norm(T& x, T& y) { #if defined(_MSC_VER) && defined(_M_IX86) // hypot for Visual Studio (A=win32) fails monotonicity, e.g., with // x = 0.6102683302836215 // y1 = 0.7906090004346522 // y2 = y1 + 1e-16 // the test // hypot(x, y2) >= hypot(x, y1) // fails. Reported 2021-03-14: // https://developercommunity.visualstudio.com/t/1369259 // See also: // https://bugs.python.org/issue43088 using std::sqrt; T h = sqrt(x * x + y * y); #else using std::hypot; T h = hypot(x, y); #endif x /= h; y /= h; } /** * The error-free sum of two numbers. * * @tparam T the type of the argument and the returned value. * @param[in] u * @param[in] v * @param[out] t the exact error given by (\e u + \e v) - \e s. * @return \e s = round(\e u + \e v). * * See D. E. Knuth, TAOCP, Vol 2, 4.2.2, Theorem B. * * \note \e t can be the same as one of the first two arguments. **********************************************************************/ template static T sum(T u, T v, T& t); /** * Evaluate a polynomial. * * @tparam T the type of the arguments and returned value. * @param[in] N the order of the polynomial. * @param[in] p the coefficient array (of size \e N + 1) with * p0 being coefficient of xN. * @param[in] x the variable. * @return the value of the polynomial. * * Evaluate ∑n=0..N * pn xNn. * Return 0 if \e N < 0. Return p0, if \e N = 0 (even * if \e x is infinite or a nan). The evaluation uses Horner's method. **********************************************************************/ template static T polyval(int N, const T p[], T x) { // This used to employ Math::fma; but that's too slow and it seemed not // to improve the accuracy noticeably. This might change when there's // direct hardware support for fma. T y = N < 0 ? 0 : *p++; while (--N >= 0) y = y * x + *p++; return y; } /** * Normalize an angle. * * @tparam T the type of the argument and returned value. * @param[in] x the angle in degrees. * @return the angle reduced to the range [−180°, 180°]. * * The range of \e x is unrestricted. If the result is ±0° or * ±180° then the sign is the sign of \e x. **********************************************************************/ template static T AngNormalize(T x); /** * Normalize a latitude. * * @tparam T the type of the argument and returned value. * @param[in] x the angle in degrees. * @return x if it is in the range [−90°, 90°], otherwise * return NaN. **********************************************************************/ template static T LatFix(T x) { using std::fabs; return fabs(x) > T(qd) ? NaN() : x; } /** * The exact difference of two angles reduced to * [−180°, 180°]. * * @tparam T the type of the arguments and returned value. * @param[in] x the first angle in degrees. * @param[in] y the second angle in degrees. * @param[out] e the error term in degrees. * @return \e d, the truncated value of \e y − \e x. * * This computes \e z = \e y − \e x exactly, reduced to * [−180°, 180°]; and then sets \e z = \e d + \e e where \e d * is the nearest representable number to \e z and \e e is the truncation * error. If \e z = ±0° or ±180°, then the sign of * \e d is given by the sign of \e y − \e x. The maximum absolute * value of \e e is 2−26 (for doubles). **********************************************************************/ template static T AngDiff(T x, T y, T& e); /** * Difference of two angles reduced to [−180°, 180°] * * @tparam T the type of the arguments and returned value. * @param[in] x the first angle in degrees. * @param[in] y the second angle in degrees. * @return \e y − \e x, reduced to the range [−180°, * 180°]. * * The result is equivalent to computing the difference exactly, reducing * it to [−180°, 180°] and rounding the result. **********************************************************************/ template static T AngDiff(T x, T y) { T e; return AngDiff(x, y, e); } /** * Coarsen a value close to zero. * * @tparam T the type of the argument and returned value. * @param[in] x * @return the coarsened value. * * The makes the smallest gap in \e x = 1/16 − nextafter(1/16, 0) = * 1/257 for doubles = 0.8 pm on the earth if \e x is an angle * in degrees. (This is about 2000 times more resolution than we get with * angles around 90°.) We use this to avoid having to deal with near * singular cases when \e x is non-zero but tiny (e.g., * 10−200). This sign of ±0 is preserved. **********************************************************************/ template static T AngRound(T x); /** * Evaluate the sine and cosine function with the argument in degrees * * @tparam T the type of the arguments. * @param[in] x in degrees. * @param[out] sinx sin(x). * @param[out] cosx cos(x). * * The results obey exactly the elementary properties of the trigonometric * functions, e.g., sin 9° = cos 81° = − sin 123456789°. * If x = −0 or a negative multiple of 180°, then \e sinx = * −0; this is the only case where −0 is returned. **********************************************************************/ template static void sincosd(T x, T& sinx, T& cosx); /** * Evaluate the sine and cosine with reduced argument plus correction * * @tparam T the type of the arguments. * @param[in] x reduced angle in degrees. * @param[in] t correction in degrees. * @param[out] sinx sin(x + t). * @param[out] cosx cos(x + t). * * This is a variant of Math::sincosd allowing a correction to the angle to * be supplied. \e x must be in [−180°, 180°] and \e t is * assumed to be a small correction. Math::AngRound is applied to * the reduced angle to prevent problems with \e x + \e t being extremely * close but not exactly equal to one of the four cardinal directions. **********************************************************************/ template static void sincosde(T x, T t, T& sinx, T& cosx); /** * Evaluate the sine function with the argument in degrees * * @tparam T the type of the argument and the returned value. * @param[in] x in degrees. * @return sin(x). * * The result is +0 for \e x = +0 and positive multiples of 180°. The * result is −0 for \e x = -0 and negative multiples of 180°. **********************************************************************/ template static T sind(T x); /** * Evaluate the cosine function with the argument in degrees * * @tparam T the type of the argument and the returned value. * @param[in] x in degrees. * @return cos(x). * * The result is +0 for \e x an odd multiple of 90°. **********************************************************************/ template static T cosd(T x); /** * Evaluate the tangent function with the argument in degrees * * @tparam T the type of the argument and the returned value. * @param[in] x in degrees. * @return tan(x). * * If \e x is an odd multiple of 90°, then a suitably large (but * finite) value is returned. **********************************************************************/ template static T tand(T x); /** * Evaluate the atan2 function with the result in degrees * * @tparam T the type of the arguments and the returned value. * @param[in] y * @param[in] x * @return atan2(y, x) in degrees. * * The result is in the range [−180° 180°]. N.B., * atan2d(±0, −1) = ±180°. **********************************************************************/ template static T atan2d(T y, T x); /** * Evaluate the atan function with the result in degrees * * @tparam T the type of the argument and the returned value. * @param[in] x * @return atan(x) in degrees. **********************************************************************/ template static T atand(T x); /** * Evaluate e atanh(e x) * * @tparam T the type of the argument and the returned value. * @param[in] x * @param[in] es the signed eccentricity = sign(e2) * sqrt(|e2|) * @return e atanh(e x) * * If e2 is negative (e is imaginary), the * expression is evaluated in terms of atan. **********************************************************************/ template static T eatanhe(T x, T es); /** * tanχ in terms of tanφ * * @tparam T the type of the argument and the returned value. * @param[in] tau τ = tanφ * @param[in] es the signed eccentricity = sign(e2) * sqrt(|e2|) * @return τ′ = tanχ * * See Eqs. (7--9) of * C. F. F. Karney, * * Transverse Mercator with an accuracy of a few nanometers, * J. Geodesy 85(8), 475--485 (Aug. 2011) * (preprint * arXiv:1002.1417). **********************************************************************/ template static T taupf(T tau, T es); /** * tanφ in terms of tanχ * * @tparam T the type of the argument and the returned value. * @param[in] taup τ′ = tanχ * @param[in] es the signed eccentricity = sign(e2) * sqrt(|e2|) * @return τ = tanφ * * See Eqs. (19--21) of * C. F. F. Karney, * * Transverse Mercator with an accuracy of a few nanometers, * J. Geodesy 85(8), 475--485 (Aug. 2011) * (preprint * arXiv:1002.1417). **********************************************************************/ template static T tauf(T taup, T es); /** * The NaN (not a number) * * @tparam T the type of the returned value. * @return NaN if available, otherwise return the max real of type T. **********************************************************************/ template static T NaN(); /** * Infinity * * @tparam T the type of the returned value. * @return infinity if available, otherwise return the max real. **********************************************************************/ template static T infinity(); /** * Swap the bytes of a quantity * * @tparam T the type of the argument and the returned value. * @param[in] x * @return x with its bytes swapped. **********************************************************************/ template static T swab(T x) { union { T r; unsigned char c[sizeof(T)]; } b; b.r = x; for (int i = sizeof(T)/2; i--; ) std::swap(b.c[i], b.c[sizeof(T) - 1 - i]); return b.r; } }; } // namespace GeographicLib #endif // GEOGRAPHICLIB_MATH_HPP geosphere/src/GeodesicLineExact.cpp0000644000176200001440000002622214323376011017051 0ustar liggesusers/** * \file GeodesicLineExact.cpp * \brief Implementation for GeographicLib::GeodesicLineExact class * * Copyright (c) Charles Karney (2012-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ * * This is a reformulation of the geodesic problem. The notation is as * follows: * - at a general point (no suffix or 1 or 2 as suffix) * - phi = latitude * - beta = latitude on auxiliary sphere * - omega = longitude on auxiliary sphere * - lambda = longitude * - alpha = azimuth of great circle * - sigma = arc length along great circle * - s = distance * - tau = scaled distance (= sigma at multiples of pi/2) * - at northwards equator crossing * - beta = phi = 0 * - omega = lambda = 0 * - alpha = alpha0 * - sigma = s = 0 * - a 12 suffix means a difference, e.g., s12 = s2 - s1. * - s and c prefixes mean sin and cos **********************************************************************/ #include "GeodesicLineExact.h" #if defined(_MSC_VER) // Squelch warnings about mixing enums # pragma warning (disable: 5054) #endif namespace GeographicLib { using namespace std; void GeodesicLineExact::LineInit(const GeodesicExact& g, real lat1, real lon1, real azi1, real salp1, real calp1, unsigned caps) { tiny_ = g.tiny_; _lat1 = Math::LatFix(lat1); _lon1 = lon1; _azi1 = azi1; _salp1 = salp1; _calp1 = calp1; _a = g._a; _f = g._f; _b = g._b; _c2 = g._c2; _f1 = g._f1; _e2 = g._e2; _nC4 = g._nC4; // Always allow latitude and azimuth and unrolling of longitude _caps = caps | LATITUDE | AZIMUTH | LONG_UNROLL; real cbet1, sbet1; Math::sincosd(Math::AngRound(_lat1), sbet1, cbet1); sbet1 *= _f1; // Ensure cbet1 = +epsilon at poles Math::norm(sbet1, cbet1); cbet1 = fmax(tiny_, cbet1); _dn1 = (_f >= 0 ? sqrt(1 + g._ep2 * Math::sq(sbet1)) : sqrt(1 - _e2 * Math::sq(cbet1)) / _f1); // Evaluate alp0 from sin(alp1) * cos(bet1) = sin(alp0), _salp0 = _salp1 * cbet1; // alp0 in [0, pi/2 - |bet1|] // Alt: calp0 = hypot(sbet1, calp1 * cbet1). The following // is slightly better (consider the case salp1 = 0). _calp0 = hypot(_calp1, _salp1 * sbet1); // Evaluate sig with tan(bet1) = tan(sig1) * cos(alp1). // sig = 0 is nearest northward crossing of equator. // With bet1 = 0, alp1 = pi/2, we have sig1 = 0 (equatorial line). // With bet1 = pi/2, alp1 = -pi, sig1 = pi/2 // With bet1 = -pi/2, alp1 = 0 , sig1 = -pi/2 // Evaluate omg1 with tan(omg1) = sin(alp0) * tan(sig1). // With alp0 in (0, pi/2], quadrants for sig and omg coincide. // No atan2(0,0) ambiguity at poles since cbet1 = +epsilon. // With alp0 = 0, omg1 = 0 for alp1 = 0, omg1 = pi for alp1 = pi. _ssig1 = sbet1; _somg1 = _salp0 * sbet1; _csig1 = _comg1 = sbet1 != 0 || _calp1 != 0 ? cbet1 * _calp1 : 1; // Without normalization we have schi1 = somg1. _cchi1 = _f1 * _dn1 * _comg1; Math::norm(_ssig1, _csig1); // sig1 in (-pi, pi] // Math::norm(_somg1, _comg1); -- don't need to normalize! // Math::norm(_schi1, _cchi1); -- don't need to normalize! _k2 = Math::sq(_calp0) * g._ep2; _eE.Reset(-_k2, -g._ep2, 1 + _k2, 1 + g._ep2); if (_caps & CAP_E) { _eE0 = _eE.E() / (Math::pi() / 2); _eE1 = _eE.deltaE(_ssig1, _csig1, _dn1); real s = sin(_eE1), c = cos(_eE1); // tau1 = sig1 + B11 _stau1 = _ssig1 * c + _csig1 * s; _ctau1 = _csig1 * c - _ssig1 * s; // Not necessary because Einv inverts E // _eE1 = -_eE.deltaEinv(_stau1, _ctau1); } if (_caps & CAP_D) { _dD0 = _eE.D() / (Math::pi() / 2); _dD1 = _eE.deltaD(_ssig1, _csig1, _dn1); } if (_caps & CAP_H) { _hH0 = _eE.H() / (Math::pi() / 2); _hH1 = _eE.deltaH(_ssig1, _csig1, _dn1); } if (_caps & CAP_C4) { // Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0) _aA4 = Math::sq(_a) * _calp0 * _salp0 * _e2; if (_aA4 == 0) _bB41 = 0; else { GeodesicExact::I4Integrand i4(g._ep2, _k2); _cC4a.resize(_nC4); g._fft.transform(i4, _cC4a.data()); _bB41 = DST::integral(_ssig1, _csig1, _cC4a.data(), _nC4); } } _a13 = _s13 = Math::NaN(); } GeodesicLineExact::GeodesicLineExact(const GeodesicExact& g, real lat1, real lon1, real azi1, unsigned caps) { azi1 = Math::AngNormalize(azi1); real salp1, calp1; // Guard against underflow in salp0. Also -0 is converted to +0. Math::sincosd(Math::AngRound(azi1), salp1, calp1); LineInit(g, lat1, lon1, azi1, salp1, calp1, caps); } GeodesicLineExact::GeodesicLineExact(const GeodesicExact& g, real lat1, real lon1, real azi1, real salp1, real calp1, unsigned caps, bool arcmode, real s13_a13) { LineInit(g, lat1, lon1, azi1, salp1, calp1, caps); GenSetDistance(arcmode, s13_a13); } Math::real GeodesicLineExact::GenPosition(bool arcmode, real s12_a12, unsigned outmask, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21, real& S12) const { outmask &= _caps & OUT_MASK; if (!( Init() && (arcmode || (_caps & (OUT_MASK & DISTANCE_IN))) )) // Uninitialized or impossible distance calculation requested return Math::NaN(); // Avoid warning about uninitialized B12. real sig12, ssig12, csig12, E2 = 0, AB1 = 0; if (arcmode) { // Interpret s12_a12 as spherical arc length sig12 = s12_a12 * Math::degree(); Math::sincosd(s12_a12, ssig12, csig12); } else { // Interpret s12_a12 as distance real tau12 = s12_a12 / (_b * _eE0), s = sin(tau12), c = cos(tau12); // tau2 = tau1 + tau12 E2 = - _eE.deltaEinv(_stau1 * c + _ctau1 * s, _ctau1 * c - _stau1 * s); sig12 = tau12 - (E2 - _eE1); ssig12 = sin(sig12); csig12 = cos(sig12); } real ssig2, csig2, sbet2, cbet2, salp2, calp2; // sig2 = sig1 + sig12 ssig2 = _ssig1 * csig12 + _csig1 * ssig12; csig2 = _csig1 * csig12 - _ssig1 * ssig12; real dn2 = _eE.Delta(ssig2, csig2); if (outmask & (DISTANCE | REDUCEDLENGTH | GEODESICSCALE)) { if (arcmode) { E2 = _eE.deltaE(ssig2, csig2, dn2); } AB1 = _eE0 * (E2 - _eE1); } // sin(bet2) = cos(alp0) * sin(sig2) sbet2 = _calp0 * ssig2; // Alt: cbet2 = hypot(csig2, salp0 * ssig2); cbet2 = hypot(_salp0, _calp0 * csig2); if (cbet2 == 0) // I.e., salp0 = 0, csig2 = 0. Break the degeneracy in this case cbet2 = csig2 = tiny_; // tan(alp0) = cos(sig2)*tan(alp2) salp2 = _salp0; calp2 = _calp0 * csig2; // No need to normalize if (outmask & DISTANCE) s12 = arcmode ? _b * (_eE0 * sig12 + AB1) : s12_a12; if (outmask & LONGITUDE) { real somg2 = _salp0 * ssig2, comg2 = csig2, // No need to normalize E = copysign(real(1), _salp0); // east-going? // Without normalization we have schi2 = somg2. real cchi2 = _f1 * dn2 * comg2; real chi12 = outmask & LONG_UNROLL ? E * (sig12 - (atan2( ssig2, csig2) - atan2( _ssig1, _csig1)) + (atan2(E * somg2, cchi2) - atan2(E * _somg1, _cchi1))) : atan2(somg2 * _cchi1 - cchi2 * _somg1, cchi2 * _cchi1 + somg2 * _somg1); real lam12 = chi12 - _e2/_f1 * _salp0 * _hH0 * (sig12 + (_eE.deltaH(ssig2, csig2, dn2) - _hH1)); real lon12 = lam12 / Math::degree(); lon2 = outmask & LONG_UNROLL ? _lon1 + lon12 : Math::AngNormalize(Math::AngNormalize(_lon1) + Math::AngNormalize(lon12)); } if (outmask & LATITUDE) lat2 = Math::atan2d(sbet2, _f1 * cbet2); if (outmask & AZIMUTH) azi2 = Math::atan2d(salp2, calp2); if (outmask & (REDUCEDLENGTH | GEODESICSCALE)) { real J12 = _k2 * _dD0 * (sig12 + (_eE.deltaD(ssig2, csig2, dn2) - _dD1)); if (outmask & REDUCEDLENGTH) // Add parens around (_csig1 * ssig2) and (_ssig1 * csig2) to ensure // accurate cancellation in the case of coincident points. m12 = _b * ((dn2 * (_csig1 * ssig2) - _dn1 * (_ssig1 * csig2)) - _csig1 * csig2 * J12); if (outmask & GEODESICSCALE) { real t = _k2 * (ssig2 - _ssig1) * (ssig2 + _ssig1) / (_dn1 + dn2); M12 = csig12 + (t * ssig2 - csig2 * J12) * _ssig1 / _dn1; M21 = csig12 - (t * _ssig1 - _csig1 * J12) * ssig2 / dn2; } } if (outmask & AREA) { real B42 = _aA4 == 0 ? 0 : DST::integral(ssig2, csig2, _cC4a.data(), _nC4); real salp12, calp12; if (_calp0 == 0 || _salp0 == 0) { // alp12 = alp2 - alp1, used in atan2 so no need to normalize salp12 = salp2 * _calp1 - calp2 * _salp1; calp12 = calp2 * _calp1 + salp2 * _salp1; // We used to include here some patch up code that purported to deal // with nearly meridional geodesics properly. However, this turned out // to be wrong once _salp1 = -0 was allowed (via // GeodesicExact::InverseLine). In fact, the calculation of {s,c}alp12 // was already correct (following the IEEE rules for handling signed // zeros). So the patch up code was unnecessary (as well as // dangerous). } else { // tan(alp) = tan(alp0) * sec(sig) // tan(alp2-alp1) = (tan(alp2) -tan(alp1)) / (tan(alp2)*tan(alp1)+1) // = calp0 * salp0 * (csig1-csig2) / (salp0^2 + calp0^2 * csig1*csig2) // If csig12 > 0, write // csig1 - csig2 = ssig12 * (csig1 * ssig12 / (1 + csig12) + ssig1) // else // csig1 - csig2 = csig1 * (1 - csig12) + ssig12 * ssig1 // No need to normalize salp12 = _calp0 * _salp0 * (csig12 <= 0 ? _csig1 * (1 - csig12) + ssig12 * _ssig1 : ssig12 * (_csig1 * ssig12 / (1 + csig12) + _ssig1)); calp12 = Math::sq(_salp0) + Math::sq(_calp0) * _csig1 * csig2; } S12 = _c2 * atan2(salp12, calp12) + _aA4 * (B42 - _bB41); } return arcmode ? s12_a12 : sig12 / Math::degree(); } void GeodesicLineExact::SetDistance(real s13) { _s13 = s13; real t; // This will set _a13 to NaN if the GeodesicLineExact doesn't have the // DISTANCE_IN capability. _a13 = GenPosition(false, _s13, 0u, t, t, t, t, t, t, t, t); } void GeodesicLineExact::SetArc(real a13) { _a13 = a13; // In case the GeodesicLineExact doesn't have the DISTANCE capability. _s13 = Math::NaN(); real t; GenPosition(true, _a13, DISTANCE, t, t, t, _s13, t, t, t, t); } void GeodesicLineExact::GenSetDistance(bool arcmode, real s13_a13) { arcmode ? SetArc(s13_a13) : SetDistance(s13_a13); } } // namespace GeographicLib geosphere/src/EllipticFunction.cpp0000644000176200001440000004505214323376011017007 0ustar liggesusers/** * \file EllipticFunction.cpp * \brief Implementation for GeographicLib::EllipticFunction class * * Copyright (c) Charles Karney (2008-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #include "EllipticFunction.h" #if defined(_MSC_VER) // Squelch warnings about constant conditional and enum-float expressions # pragma warning (disable: 4127 5055) #endif namespace GeographicLib { using namespace std; /* * Implementation of methods given in * * B. C. Carlson * Computation of elliptic integrals * Numerical Algorithms 10, 13-26 (1995) */ Math::real EllipticFunction::RF(real x, real y, real z) { // Carlson, eqs 2.2 - 2.7 static const real tolRF = pow(3 * numeric_limits::epsilon() * real(0.01), 1/real(8)); real A0 = (x + y + z)/3, An = A0, Q = fmax(fmax(fabs(A0-x), fabs(A0-y)), fabs(A0-z)) / tolRF, x0 = x, y0 = y, z0 = z, mul = 1; while (Q >= mul * fabs(An)) { // Max 6 trips real lam = sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0); An = (An + lam)/4; x0 = (x0 + lam)/4; y0 = (y0 + lam)/4; z0 = (z0 + lam)/4; mul *= 4; } real X = (A0 - x) / (mul * An), Y = (A0 - y) / (mul * An), Z = - (X + Y), E2 = X*Y - Z*Z, E3 = X*Y*Z; // https://dlmf.nist.gov/19.36.E1 // Polynomial is // (1 - E2/10 + E3/14 + E2^2/24 - 3*E2*E3/44 // - 5*E2^3/208 + 3*E3^2/104 + E2^2*E3/16) // convert to Horner form... return (E3 * (6930 * E3 + E2 * (15015 * E2 - 16380) + 17160) + E2 * ((10010 - 5775 * E2) * E2 - 24024) + 240240) / (240240 * sqrt(An)); } Math::real EllipticFunction::RF(real x, real y) { // Carlson, eqs 2.36 - 2.38 static const real tolRG0 = real(2.7) * sqrt((numeric_limits::epsilon() * real(0.01))); real xn = sqrt(x), yn = sqrt(y); if (xn < yn) swap(xn, yn); while (fabs(xn-yn) > tolRG0 * xn) { // Max 4 trips real t = (xn + yn) /2; yn = sqrt(xn * yn); xn = t; } return Math::pi() / (xn + yn); } Math::real EllipticFunction::RC(real x, real y) { // Defined only for y != 0 and x >= 0. return ( !(x >= y) ? // x < y and catch nans // https://dlmf.nist.gov/19.2.E18 atan(sqrt((y - x) / x)) / sqrt(y - x) : ( x == y ? 1 / sqrt(y) : asinh( y > 0 ? // https://dlmf.nist.gov/19.2.E19 // atanh(sqrt((x - y) / x)) sqrt((x - y) / y) : // https://dlmf.nist.gov/19.2.E20 // atanh(sqrt(x / (x - y))) sqrt(-x / y) ) / sqrt(x - y) ) ); } Math::real EllipticFunction::RG(real x, real y, real z) { if (z == 0) swap(y, z); // Carlson, eq 1.7 return (z * RF(x, y, z) - (x-z) * (y-z) * RD(x, y, z) / 3 + sqrt(x * y / z)) / 2; } Math::real EllipticFunction::RG(real x, real y) { // Carlson, eqs 2.36 - 2.39 static const real tolRG0 = real(2.7) * sqrt((numeric_limits::epsilon() * real(0.01))); real x0 = sqrt(fmax(x, y)), y0 = sqrt(fmin(x, y)), xn = x0, yn = y0, s = 0, mul = real(0.25); while (fabs(xn-yn) > tolRG0 * xn) { // Max 4 trips real t = (xn + yn) /2; yn = sqrt(xn * yn); xn = t; mul *= 2; t = xn - yn; s += mul * t * t; } return (Math::sq( (x0 + y0)/2 ) - s) * Math::pi() / (2 * (xn + yn)); } Math::real EllipticFunction::RJ(real x, real y, real z, real p) { // Carlson, eqs 2.17 - 2.25 static const real tolRD = pow(real(0.2) * (numeric_limits::epsilon() * real(0.01)), 1/real(8)); real A0 = (x + y + z + 2*p)/5, An = A0, delta = (p-x) * (p-y) * (p-z), Q = fmax(fmax(fabs(A0-x), fabs(A0-y)), fmax(fabs(A0-z), fabs(A0-p))) / tolRD, x0 = x, y0 = y, z0 = z, p0 = p, mul = 1, mul3 = 1, s = 0; while (Q >= mul * fabs(An)) { // Max 7 trips real lam = sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0), d0 = (sqrt(p0)+sqrt(x0)) * (sqrt(p0)+sqrt(y0)) * (sqrt(p0)+sqrt(z0)), e0 = delta/(mul3 * Math::sq(d0)); s += RC(1, 1 + e0)/(mul * d0); An = (An + lam)/4; x0 = (x0 + lam)/4; y0 = (y0 + lam)/4; z0 = (z0 + lam)/4; p0 = (p0 + lam)/4; mul *= 4; mul3 *= 64; } real X = (A0 - x) / (mul * An), Y = (A0 - y) / (mul * An), Z = (A0 - z) / (mul * An), P = -(X + Y + Z) / 2, E2 = X*Y + X*Z + Y*Z - 3*P*P, E3 = X*Y*Z + 2*P * (E2 + 2*P*P), E4 = (2*X*Y*Z + P * (E2 + 3*P*P)) * P, E5 = X*Y*Z*P*P; // https://dlmf.nist.gov/19.36.E2 // Polynomial is // (1 - 3*E2/14 + E3/6 + 9*E2^2/88 - 3*E4/22 - 9*E2*E3/52 + 3*E5/26 // - E2^3/16 + 3*E3^2/40 + 3*E2*E4/20 + 45*E2^2*E3/272 // - 9*(E3*E4+E2*E5)/68) return ((471240 - 540540 * E2) * E5 + (612612 * E2 - 540540 * E3 - 556920) * E4 + E3 * (306306 * E3 + E2 * (675675 * E2 - 706860) + 680680) + E2 * ((417690 - 255255 * E2) * E2 - 875160) + 4084080) / (4084080 * mul * An * sqrt(An)) + 6 * s; } Math::real EllipticFunction::RD(real x, real y, real z) { // Carlson, eqs 2.28 - 2.34 static const real tolRD = pow(real(0.2) * (numeric_limits::epsilon() * real(0.01)), 1/real(8)); real A0 = (x + y + 3*z)/5, An = A0, Q = fmax(fmax(fabs(A0-x), fabs(A0-y)), fabs(A0-z)) / tolRD, x0 = x, y0 = y, z0 = z, mul = 1, s = 0; while (Q >= mul * fabs(An)) { // Max 7 trips real lam = sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0); s += 1/(mul * sqrt(z0) * (z0 + lam)); An = (An + lam)/4; x0 = (x0 + lam)/4; y0 = (y0 + lam)/4; z0 = (z0 + lam)/4; mul *= 4; } real X = (A0 - x) / (mul * An), Y = (A0 - y) / (mul * An), Z = -(X + Y) / 3, E2 = X*Y - 6*Z*Z, E3 = (3*X*Y - 8*Z*Z)*Z, E4 = 3 * (X*Y - Z*Z) * Z*Z, E5 = X*Y*Z*Z*Z; // https://dlmf.nist.gov/19.36.E2 // Polynomial is // (1 - 3*E2/14 + E3/6 + 9*E2^2/88 - 3*E4/22 - 9*E2*E3/52 + 3*E5/26 // - E2^3/16 + 3*E3^2/40 + 3*E2*E4/20 + 45*E2^2*E3/272 // - 9*(E3*E4+E2*E5)/68) return ((471240 - 540540 * E2) * E5 + (612612 * E2 - 540540 * E3 - 556920) * E4 + E3 * (306306 * E3 + E2 * (675675 * E2 - 706860) + 680680) + E2 * ((417690 - 255255 * E2) * E2 - 875160) + 4084080) / (4084080 * mul * An * sqrt(An)) + 3 * s; } void EllipticFunction::Reset(real k2, real alpha2, real kp2, real alphap2) { // Accept nans here (needed for GeodesicExact) if (k2 > 1) throw GeographicErr("Parameter k2 is not in (-inf, 1]"); if (alpha2 > 1) throw GeographicErr("Parameter alpha2 is not in (-inf, 1]"); if (kp2 < 0) throw GeographicErr("Parameter kp2 is not in [0, inf)"); if (alphap2 < 0) throw GeographicErr("Parameter alphap2 is not in [0, inf)"); _k2 = k2; _kp2 = kp2; _alpha2 = alpha2; _alphap2 = alphap2; _eps = _k2/Math::sq(sqrt(_kp2) + 1); // Values of complete elliptic integrals for k = 0,1 and alpha = 0,1 // K E D // k = 0: pi/2 pi/2 pi/4 // k = 1: inf 1 inf // Pi G H // k = 0, alpha = 0: pi/2 pi/2 pi/4 // k = 1, alpha = 0: inf 1 1 // k = 0, alpha = 1: inf inf pi/2 // k = 1, alpha = 1: inf inf inf // // Pi(0, k) = K(k) // G(0, k) = E(k) // H(0, k) = K(k) - D(k) // Pi(0, k) = K(k) // G(0, k) = E(k) // H(0, k) = K(k) - D(k) // Pi(alpha2, 0) = pi/(2*sqrt(1-alpha2)) // G(alpha2, 0) = pi/(2*sqrt(1-alpha2)) // H(alpha2, 0) = pi/(2*(1 + sqrt(1-alpha2))) // Pi(alpha2, 1) = inf // H(1, k) = K(k) // G(alpha2, 1) = H(alpha2, 1) = RC(1, alphap2) if (_k2 != 0) { // Complete elliptic integral K(k), Carlson eq. 4.1 // https://dlmf.nist.gov/19.25.E1 _kKc = _kp2 != 0 ? RF(_kp2, 1) : Math::infinity(); // Complete elliptic integral E(k), Carlson eq. 4.2 // https://dlmf.nist.gov/19.25.E1 _eEc = _kp2 != 0 ? 2 * RG(_kp2, 1) : 1; // D(k) = (K(k) - E(k))/k^2, Carlson eq.4.3 // https://dlmf.nist.gov/19.25.E1 _dDc = _kp2 != 0 ? RD(0, _kp2, 1) / 3 : Math::infinity(); } else { _kKc = _eEc = Math::pi()/2; _dDc = _kKc/2; } if (_alpha2 != 0) { // https://dlmf.nist.gov/19.25.E2 real rj = (_kp2 != 0 && _alphap2 != 0) ? RJ(0, _kp2, 1, _alphap2) : Math::infinity(), // Only use rc if _kp2 = 0. rc = _kp2 != 0 ? 0 : (_alphap2 != 0 ? RC(1, _alphap2) : Math::infinity()); // Pi(alpha^2, k) _pPic = _kp2 != 0 ? _kKc + _alpha2 * rj / 3 : Math::infinity(); // G(alpha^2, k) _gGc = _kp2 != 0 ? _kKc + (_alpha2 - _k2) * rj / 3 : rc; // H(alpha^2, k) _hHc = _kp2 != 0 ? _kKc - (_alphap2 != 0 ? _alphap2 * rj : 0) / 3 : rc; } else { _pPic = _kKc; _gGc = _eEc; // Hc = Kc - Dc but this involves large cancellations if k2 is close to // 1. So write (for alpha2 = 0) // Hc = int(cos(phi)^2/sqrt(1-k2*sin(phi)^2),phi,0,pi/2) // = 1/sqrt(1-k2) * int(sin(phi)^2/sqrt(1-k2/kp2*sin(phi)^2,...) // = 1/kp * D(i*k/kp) // and use D(k) = RD(0, kp2, 1) / 3 // so Hc = 1/kp * RD(0, 1/kp2, 1) / 3 // = kp2 * RD(0, 1, kp2) / 3 // using https://dlmf.nist.gov/19.20.E18 // Equivalently // RF(x, 1) - RD(0, x, 1)/3 = x * RD(0, 1, x)/3 for x > 0 // For k2 = 1 and alpha2 = 0, we have // Hc = int(cos(phi),...) = 1 _hHc = _kp2 != 0 ? _kp2 * RD(0, 1, _kp2) / 3 : 1; } } /* * Implementation of methods given in * * R. Bulirsch * Numerical Calculation of Elliptic Integrals and Elliptic Functions * Numericshe Mathematik 7, 78-90 (1965) */ void EllipticFunction::sncndn(real x, real& sn, real& cn, real& dn) const { // Bulirsch's sncndn routine, p 89. static const real tolJAC = sqrt(numeric_limits::epsilon() * real(0.01)); if (_kp2 != 0) { real mc = _kp2, d = 0; if (signbit(_kp2)) { d = 1 - mc; mc /= -d; d = sqrt(d); x *= d; } real c = 0; // To suppress warning about uninitialized variable real m[num_], n[num_]; unsigned l = 0; for (real a = 1; l < num_ || GEOGRAPHICLIB_PANIC; ++l) { // This converges quadratically. Max 5 trips m[l] = a; n[l] = mc = sqrt(mc); c = (a + mc) / 2; if (!(fabs(a - mc) > tolJAC * a)) { ++l; break; } mc *= a; a = c; } x *= c; sn = sin(x); cn = cos(x); dn = 1; if (sn != 0) { real a = cn / sn; c *= a; while (l--) { real b = m[l]; a *= c; c *= dn; dn = (n[l] + a) / (b + a); a = c / b; } a = 1 / sqrt(c*c + 1); sn = signbit(sn) ? -a : a; cn = c * sn; if (signbit(_kp2)) { swap(cn, dn); sn /= d; } } } else { sn = tanh(x); dn = cn = 1 / cosh(x); } } Math::real EllipticFunction::F(real sn, real cn, real dn) const { // Carlson, eq. 4.5 and // https://dlmf.nist.gov/19.25.E5 real cn2 = cn*cn, dn2 = dn*dn, fi = cn2 != 0 ? fabs(sn) * RF(cn2, dn2, 1) : K(); // Enforce usual trig-like symmetries if (signbit(cn)) fi = 2 * K() - fi; return copysign(fi, sn); } Math::real EllipticFunction::E(real sn, real cn, real dn) const { real cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn, ei = cn2 != 0 ? fabs(sn) * ( _k2 <= 0 ? // Carlson, eq. 4.6 and // https://dlmf.nist.gov/19.25.E9 RF(cn2, dn2, 1) - _k2 * sn2 * RD(cn2, dn2, 1) / 3 : ( _kp2 >= 0 ? // https://dlmf.nist.gov/19.25.E10 _kp2 * RF(cn2, dn2, 1) + _k2 * _kp2 * sn2 * RD(cn2, 1, dn2) / 3 + _k2 * fabs(cn) / dn : // https://dlmf.nist.gov/19.25.E11 - _kp2 * sn2 * RD(dn2, 1, cn2) / 3 + dn / fabs(cn) ) ) : E(); // Enforce usual trig-like symmetries if (signbit(cn)) ei = 2 * E() - ei; return copysign(ei, sn); } Math::real EllipticFunction::D(real sn, real cn, real dn) const { // Carlson, eq. 4.8 and // https://dlmf.nist.gov/19.25.E13 real cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn, di = cn2 != 0 ? fabs(sn) * sn2 * RD(cn2, dn2, 1) / 3 : D(); // Enforce usual trig-like symmetries if (signbit(cn)) di = 2 * D() - di; return copysign(di, sn); } Math::real EllipticFunction::Pi(real sn, real cn, real dn) const { // Carlson, eq. 4.7 and // https://dlmf.nist.gov/19.25.E14 real cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn, pii = cn2 != 0 ? fabs(sn) * (RF(cn2, dn2, 1) + _alpha2 * sn2 * RJ(cn2, dn2, 1, cn2 + _alphap2 * sn2) / 3) : Pi(); // Enforce usual trig-like symmetries if (signbit(cn)) pii = 2 * Pi() - pii; return copysign(pii, sn); } Math::real EllipticFunction::G(real sn, real cn, real dn) const { real cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn, gi = cn2 != 0 ? fabs(sn) * (RF(cn2, dn2, 1) + (_alpha2 - _k2) * sn2 * RJ(cn2, dn2, 1, cn2 + _alphap2 * sn2) / 3) : G(); // Enforce usual trig-like symmetries if (signbit(cn)) gi = 2 * G() - gi; return copysign(gi, sn); } Math::real EllipticFunction::H(real sn, real cn, real dn) const { real cn2 = cn*cn, dn2 = dn*dn, sn2 = sn*sn, // WARNING: large cancellation if k2 = 1, alpha2 = 0, and phi near pi/2 hi = cn2 != 0 ? fabs(sn) * (RF(cn2, dn2, 1) - _alphap2 * sn2 * RJ(cn2, dn2, 1, cn2 + _alphap2 * sn2) / 3) : H(); // Enforce usual trig-like symmetries if (signbit(cn)) hi = 2 * H() - hi; return copysign(hi, sn); } Math::real EllipticFunction::deltaF(real sn, real cn, real dn) const { // Function is periodic with period pi if (signbit(cn)) { cn = -cn; sn = -sn; } return F(sn, cn, dn) * (Math::pi()/2) / K() - atan2(sn, cn); } Math::real EllipticFunction::deltaE(real sn, real cn, real dn) const { // Function is periodic with period pi if (signbit(cn)) { cn = -cn; sn = -sn; } return E(sn, cn, dn) * (Math::pi()/2) / E() - atan2(sn, cn); } Math::real EllipticFunction::deltaPi(real sn, real cn, real dn) const { // Function is periodic with period pi if (signbit(cn)) { cn = -cn; sn = -sn; } return Pi(sn, cn, dn) * (Math::pi()/2) / Pi() - atan2(sn, cn); } Math::real EllipticFunction::deltaD(real sn, real cn, real dn) const { // Function is periodic with period pi if (signbit(cn)) { cn = -cn; sn = -sn; } return D(sn, cn, dn) * (Math::pi()/2) / D() - atan2(sn, cn); } Math::real EllipticFunction::deltaG(real sn, real cn, real dn) const { // Function is periodic with period pi if (signbit(cn)) { cn = -cn; sn = -sn; } return G(sn, cn, dn) * (Math::pi()/2) / G() - atan2(sn, cn); } Math::real EllipticFunction::deltaH(real sn, real cn, real dn) const { // Function is periodic with period pi if (signbit(cn)) { cn = -cn; sn = -sn; } return H(sn, cn, dn) * (Math::pi()/2) / H() - atan2(sn, cn); } Math::real EllipticFunction::F(real phi) const { real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn); return fabs(phi) < Math::pi() ? F(sn, cn, dn) : (deltaF(sn, cn, dn) + phi) * K() / (Math::pi()/2); } Math::real EllipticFunction::E(real phi) const { real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn); return fabs(phi) < Math::pi() ? E(sn, cn, dn) : (deltaE(sn, cn, dn) + phi) * E() / (Math::pi()/2); } Math::real EllipticFunction::Ed(real ang) const { // ang - Math::AngNormalize(ang) is (nearly) an exact multiple of 360 real n = round((ang - Math::AngNormalize(ang))/Math::td); real sn, cn; Math::sincosd(ang, sn, cn); return E(sn, cn, Delta(sn, cn)) + 4 * E() * n; } Math::real EllipticFunction::Pi(real phi) const { real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn); return fabs(phi) < Math::pi() ? Pi(sn, cn, dn) : (deltaPi(sn, cn, dn) + phi) * Pi() / (Math::pi()/2); } Math::real EllipticFunction::D(real phi) const { real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn); return fabs(phi) < Math::pi() ? D(sn, cn, dn) : (deltaD(sn, cn, dn) + phi) * D() / (Math::pi()/2); } Math::real EllipticFunction::G(real phi) const { real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn); return fabs(phi) < Math::pi() ? G(sn, cn, dn) : (deltaG(sn, cn, dn) + phi) * G() / (Math::pi()/2); } Math::real EllipticFunction::H(real phi) const { real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn); return fabs(phi) < Math::pi() ? H(sn, cn, dn) : (deltaH(sn, cn, dn) + phi) * H() / (Math::pi()/2); } Math::real EllipticFunction::Einv(real x) const { static const real tolJAC = sqrt(numeric_limits::epsilon() * real(0.01)); real n = floor(x / (2 * _eEc) + real(0.5)); x -= 2 * _eEc * n; // x now in [-ec, ec) // Linear approximation real phi = Math::pi() * x / (2 * _eEc); // phi in [-pi/2, pi/2) // First order correction phi -= _eps * sin(2 * phi) / 2; // For kp2 close to zero use asin(x/_eEc) or // J. P. Boyd, Applied Math. and Computation 218, 7005-7013 (2012) // https://doi.org/10.1016/j.amc.2011.12.021 for (int i = 0; i < num_ || GEOGRAPHICLIB_PANIC; ++i) { real sn = sin(phi), cn = cos(phi), dn = Delta(sn, cn), err = (E(sn, cn, dn) - x)/dn; phi -= err; if (!(fabs(err) > tolJAC)) break; } return n * Math::pi() + phi; } Math::real EllipticFunction::deltaEinv(real stau, real ctau) const { // Function is periodic with period pi if (signbit(ctau)) { ctau = -ctau; stau = -stau; } real tau = atan2(stau, ctau); return Einv( tau * E() / (Math::pi()/2) ) - tau; } } // namespace GeographicLib geosphere/src/Ellipsoid.h0000644000176200001440000005653214323377037015143 0ustar liggesusers/** * \file Ellipsoid.hpp * \brief Header for GeographicLib::Ellipsoid class * * Copyright (c) Charles Karney (2012-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_ELLIPSOID_HPP) #define GEOGRAPHICLIB_ELLIPSOID_HPP 1 #include "Constants.h" #include "TransverseMercator.h" #include "EllipticFunction.h" #include "AlbersEqualArea.h" namespace GeographicLib { /** * \brief Properties of an ellipsoid * * This class returns various properties of the ellipsoid and converts * between various types of latitudes. The latitude conversions are also * possible using the various projections supported by %GeographicLib; but * Ellipsoid provides more direct access (sometimes using private functions * of the projection classes). Ellipsoid::RectifyingLatitude, * Ellipsoid::InverseRectifyingLatitude, and Ellipsoid::MeridianDistance * provide functionality which can be provided by the Geodesic class. * However Geodesic uses a series approximation (valid for abs \e f < 1/150), * whereas Ellipsoid computes these quantities using EllipticFunction which * provides accurate results even when \e f is large. Use of this class * should be limited to −3 < \e f < 3/4 (i.e., 1/4 < b/a < 4). * * Example of use: * \include example-Ellipsoid.cpp **********************************************************************/ class GEOGRAPHICLIB_EXPORT Ellipsoid { private: typedef Math::real real; static const int numit_ = 10; real stol_; real _a, _f, _f1, _f12, _e2, _es, _e12, _n, _b; TransverseMercator _tm; EllipticFunction _ell; AlbersEqualArea _au; // These are the alpha and beta coefficients in the Krueger series from // TransverseMercator. Thy are used by RhumbSolve to compute // (psi2-psi1)/(mu2-mu1). const Math::real* ConformalToRectifyingCoeffs() const { return _tm._alp; } const Math::real* RectifyingToConformalCoeffs() const { return _tm._bet; } friend class Rhumb; friend class RhumbLine; public: /** \name Constructor **********************************************************************/ ///@{ /** * Constructor for an ellipsoid with * * @param[in] a equatorial radius (meters). * @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere. * Negative \e f gives a prolate ellipsoid. * @exception GeographicErr if \e a or (1 − \e f) \e a is not * positive. **********************************************************************/ Ellipsoid(real a, real f); ///@} /** \name %Ellipsoid dimensions. **********************************************************************/ ///@{ /** * @return \e a the equatorial radius of the ellipsoid (meters). This is * the value used in the constructor. **********************************************************************/ Math::real EquatorialRadius() const { return _a; } /** * @return \e b the polar semi-axis (meters). **********************************************************************/ Math::real PolarRadius() const { return _b; } /** * @return \e L the distance between the equator and a pole along a * meridian (meters). For a sphere \e L = (π/2) \e a. The radius * of a sphere with the same meridian length is \e L / (π/2). **********************************************************************/ Math::real QuarterMeridian() const; /** * @return \e A the total area of the ellipsoid (meters2). For * a sphere \e A = 4π a2. The radius of a sphere * with the same area is sqrt(\e A / (4π)). **********************************************************************/ Math::real Area() const; /** * @return \e V the total volume of the ellipsoid (meters3). * For a sphere \e V = (4π / 3) a3. The radius of * a sphere with the same volume is cbrt(\e V / (4π/3)). **********************************************************************/ Math::real Volume() const { return (4 * Math::pi()) * Math::sq(_a) * _b / 3; } ///@} /** \name %Ellipsoid shape **********************************************************************/ ///@{ /** * @return \e f = (\e a − \e b) / \e a, the flattening of the * ellipsoid. This is the value used in the constructor. This is zero, * positive, or negative for a sphere, oblate ellipsoid, or prolate * ellipsoid. **********************************************************************/ Math::real Flattening() const { return _f; } /** * @return \e f ' = (\e a − \e b) / \e b, the second flattening of * the ellipsoid. This is zero, positive, or negative for a sphere, * oblate ellipsoid, or prolate ellipsoid. **********************************************************************/ Math::real SecondFlattening() const { return _f / (1 - _f); } /** * @return \e n = (\e a − \e b) / (\e a + \e b), the third flattening * of the ellipsoid. This is zero, positive, or negative for a sphere, * oblate ellipsoid, or prolate ellipsoid. **********************************************************************/ Math::real ThirdFlattening() const { return _n; } /** * @return e2 = (a2 − * b2) / a2, the eccentricity squared * of the ellipsoid. This is zero, positive, or negative for a sphere, * oblate ellipsoid, or prolate ellipsoid. **********************************************************************/ Math::real EccentricitySq() const { return _e2; } /** * @return e' 2 = (a2 − * b2) / b2, the second eccentricity * squared of the ellipsoid. This is zero, positive, or negative for a * sphere, oblate ellipsoid, or prolate ellipsoid. **********************************************************************/ Math::real SecondEccentricitySq() const { return _e12; } /** * @return e'' 2 = (a2 − * b2) / (a2 + b2), * the third eccentricity squared of the ellipsoid. This is zero, * positive, or negative for a sphere, oblate ellipsoid, or prolate * ellipsoid. **********************************************************************/ Math::real ThirdEccentricitySq() const { return _e2 / (2 - _e2); } ///@} /** \name Latitude conversion. **********************************************************************/ ///@{ /** * @param[in] phi the geographic latitude (degrees). * @return β the parametric latitude (degrees). * * The geographic latitude, φ, is the angle between the equatorial * plane and a vector normal to the surface of the ellipsoid. * * The parametric latitude (also called the reduced latitude), β, * allows the cartesian coordinated of a meridian to be expressed * conveniently in parametric form as * - \e R = \e a cos β * - \e Z = \e b sin β * . * where \e a and \e b are the equatorial radius and the polar semi-axis. * For a sphere β = φ. * * φ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. The returned value * β lies in [−90°, 90°]. **********************************************************************/ Math::real ParametricLatitude(real phi) const; /** * @param[in] beta the parametric latitude (degrees). * @return φ the geographic latitude (degrees). * * β must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. The returned value * φ lies in [−90°, 90°]. **********************************************************************/ Math::real InverseParametricLatitude(real beta) const; /** * @param[in] phi the geographic latitude (degrees). * @return θ the geocentric latitude (degrees). * * The geocentric latitude, θ, is the angle between the equatorial * plane and a line between the center of the ellipsoid and a point on the * ellipsoid. For a sphere θ = φ. * * φ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. The returned value * θ lies in [−90°, 90°]. **********************************************************************/ Math::real GeocentricLatitude(real phi) const; /** * @param[in] theta the geocentric latitude (degrees). * @return φ the geographic latitude (degrees). * * θ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. The returned value * φ lies in [−90°, 90°]. **********************************************************************/ Math::real InverseGeocentricLatitude(real theta) const; /** * @param[in] phi the geographic latitude (degrees). * @return μ the rectifying latitude (degrees). * * The rectifying latitude, μ, has the property that the distance along * a meridian of the ellipsoid between two points with rectifying latitudes * μ1 and μ2 is equal to * (μ2 - μ1) \e L / 90°, * where \e L = QuarterMeridian(). For a sphere μ = φ. * * φ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. The returned value * μ lies in [−90°, 90°]. **********************************************************************/ Math::real RectifyingLatitude(real phi) const; /** * @param[in] mu the rectifying latitude (degrees). * @return φ the geographic latitude (degrees). * * μ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. The returned value * φ lies in [−90°, 90°]. **********************************************************************/ Math::real InverseRectifyingLatitude(real mu) const; /** * @param[in] phi the geographic latitude (degrees). * @return ξ the authalic latitude (degrees). * * The authalic latitude, ξ, has the property that the area of the * ellipsoid between two circles with authalic latitudes * ξ1 and ξ2 is equal to (sin * ξ2 - sin ξ1) \e A / 2, where \e A * = Area(). For a sphere ξ = φ. * * φ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. The returned value * ξ lies in [−90°, 90°]. **********************************************************************/ Math::real AuthalicLatitude(real phi) const; /** * @param[in] xi the authalic latitude (degrees). * @return φ the geographic latitude (degrees). * * ξ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. The returned value * φ lies in [−90°, 90°]. **********************************************************************/ Math::real InverseAuthalicLatitude(real xi) const; /** * @param[in] phi the geographic latitude (degrees). * @return χ the conformal latitude (degrees). * * The conformal latitude, χ, gives the mapping of the ellipsoid to a * sphere which which is conformal (angles are preserved) and in which the * equator of the ellipsoid maps to the equator of the sphere. For a * sphere χ = φ. * * φ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. The returned value * χ lies in [−90°, 90°]. **********************************************************************/ Math::real ConformalLatitude(real phi) const; /** * @param[in] chi the conformal latitude (degrees). * @return φ the geographic latitude (degrees). * * χ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. The returned value * φ lies in [−90°, 90°]. **********************************************************************/ Math::real InverseConformalLatitude(real chi) const; /** * @param[in] phi the geographic latitude (degrees). * @return ψ the isometric latitude (degrees). * * The isometric latitude gives the mapping of the ellipsoid to a plane * which which is conformal (angles are preserved) and in which the equator * of the ellipsoid maps to a straight line of constant scale; this mapping * defines the Mercator projection. For a sphere ψ = * sinh−1 tan φ. * * φ must lie in the range [−90°, 90°]; the result is * undefined if this condition does not hold. The value returned for φ * = ±90° is some (positive or negative) large but finite value, * such that InverseIsometricLatitude returns the original value of φ. **********************************************************************/ Math::real IsometricLatitude(real phi) const; /** * @param[in] psi the isometric latitude (degrees). * @return φ the geographic latitude (degrees). * * The returned value φ lies in [−90°, 90°]. For a * sphere φ = tan−1 sinh ψ. **********************************************************************/ Math::real InverseIsometricLatitude(real psi) const; ///@} /** \name Other quantities. **********************************************************************/ ///@{ /** * @param[in] phi the geographic latitude (degrees). * @return \e R = \e a cos β the radius of a circle of latitude * φ (meters). \e R (π/180°) gives meters per degree * longitude measured along a circle of latitude. * * φ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. **********************************************************************/ Math::real CircleRadius(real phi) const; /** * @param[in] phi the geographic latitude (degrees). * @return \e Z = \e b sin β the distance of a circle of latitude * φ from the equator measured parallel to the ellipsoid axis * (meters). * * φ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. **********************************************************************/ Math::real CircleHeight(real phi) const; /** * @param[in] phi the geographic latitude (degrees). * @return \e s the distance along a meridian * between the equator and a point of latitude φ (meters). \e s is * given by \e s = μ \e L / 90°, where \e L = * QuarterMeridian()). * * φ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. **********************************************************************/ Math::real MeridianDistance(real phi) const; /** * @param[in] phi the geographic latitude (degrees). * @return ρ the meridional radius of curvature of the ellipsoid at * latitude φ (meters); this is the curvature of the meridian. \e * rho is given by ρ = (180°/π) d\e s / dφ, * where \e s = MeridianDistance(); thus ρ (π/180°) * gives meters per degree latitude measured along a meridian. * * φ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. **********************************************************************/ Math::real MeridionalCurvatureRadius(real phi) const; /** * @param[in] phi the geographic latitude (degrees). * @return ν the transverse radius of curvature of the ellipsoid at * latitude φ (meters); this is the curvature of a curve on the * ellipsoid which also lies in a plane perpendicular to the ellipsoid * and to the meridian. ν is related to \e R = CircleRadius() by \e * R = ν cos φ. * * φ must lie in the range [−90°, 90°]; the * result is undefined if this condition does not hold. **********************************************************************/ Math::real TransverseCurvatureRadius(real phi) const; /** * @param[in] phi the geographic latitude (degrees). * @param[in] azi the angle between the meridian and the normal section * (degrees). * @return the radius of curvature of the ellipsoid in the normal * section at latitude φ inclined at an angle \e azi to the * meridian (meters). * * φ must lie in the range [−90°, 90°]; the result is * undefined this condition does not hold. **********************************************************************/ Math::real NormalCurvatureRadius(real phi, real azi) const; ///@} /** \name Eccentricity conversions. **********************************************************************/ ///@{ /** * @param[in] fp = \e f ' = (\e a − \e b) / \e b, the second * flattening. * @return \e f = (\e a − \e b) / \e a, the flattening. * * \e f ' should lie in (−1, ∞). * The returned value \e f lies in (−∞, 1). **********************************************************************/ static Math::real SecondFlatteningToFlattening(real fp) { return fp / (1 + fp); } /** * @param[in] f = (\e a − \e b) / \e a, the flattening. * @return \e f ' = (\e a − \e b) / \e b, the second flattening. * * \e f should lie in (−∞, 1). * The returned value \e f ' lies in (−1, ∞). **********************************************************************/ static Math::real FlatteningToSecondFlattening(real f) { return f / (1 - f); } /** * @param[in] n = (\e a − \e b) / (\e a + \e b), the third * flattening. * @return \e f = (\e a − \e b) / \e a, the flattening. * * \e n should lie in (−1, 1). * The returned value \e f lies in (−∞, 1). **********************************************************************/ static Math::real ThirdFlatteningToFlattening(real n) { return 2 * n / (1 + n); } /** * @param[in] f = (\e a − \e b) / \e a, the flattening. * @return \e n = (\e a − \e b) / (\e a + \e b), the third * flattening. * * \e f should lie in (−∞, 1). * The returned value \e n lies in (−1, 1). **********************************************************************/ static Math::real FlatteningToThirdFlattening(real f) { return f / (2 - f); } /** * @param[in] e2 = e2 = (a2 − * b2) / a2, the eccentricity * squared. * @return \e f = (\e a − \e b) / \e a, the flattening. * * e2 should lie in (−∞, 1). * The returned value \e f lies in (−∞, 1). **********************************************************************/ static Math::real EccentricitySqToFlattening(real e2) { using std::sqrt; return e2 / (sqrt(1 - e2) + 1); } /** * @param[in] f = (\e a − \e b) / \e a, the flattening. * @return e2 = (a2 − * b2) / a2, the eccentricity * squared. * * \e f should lie in (−∞, 1). * The returned value e2 lies in (−∞, 1). **********************************************************************/ static Math::real FlatteningToEccentricitySq(real f) { return f * (2 - f); } /** * @param[in] ep2 = e' 2 = (a2 − * b2) / b2, the second eccentricity * squared. * @return \e f = (\e a − \e b) / \e a, the flattening. * * e' 2 should lie in (−1, ∞). * The returned value \e f lies in (−∞, 1). **********************************************************************/ static Math::real SecondEccentricitySqToFlattening(real ep2) { using std::sqrt; return ep2 / (sqrt(1 + ep2) + 1 + ep2); } /** * @param[in] f = (\e a − \e b) / \e a, the flattening. * @return e' 2 = (a2 − * b2) / b2, the second eccentricity * squared. * * \e f should lie in (−∞, 1). * The returned value e' 2 lies in (−1, ∞). **********************************************************************/ static Math::real FlatteningToSecondEccentricitySq(real f) { return f * (2 - f) / Math::sq(1 - f); } /** * @param[in] epp2 = e'' 2 = (a2 * − b2) / (a2 + * b2), the third eccentricity squared. * @return \e f = (\e a − \e b) / \e a, the flattening. * * e'' 2 should lie in (−1, 1). * The returned value \e f lies in (−∞, 1). **********************************************************************/ static Math::real ThirdEccentricitySqToFlattening(real epp2) { using std::sqrt; return 2 * epp2 / (sqrt((1 - epp2) * (1 + epp2)) + 1 + epp2); } /** * @param[in] f = (\e a − \e b) / \e a, the flattening. * @return e'' 2 = (a2 − * b2) / (a2 + b2), * the third eccentricity squared. * * \e f should lie in (−∞, 1). * The returned value e'' 2 lies in (−1, 1). **********************************************************************/ static Math::real FlatteningToThirdEccentricitySq(real f) { return f * (2 - f) / (1 + Math::sq(1 - f)); } ///@} /** * A global instantiation of Ellipsoid with the parameters for the WGS84 * ellipsoid. **********************************************************************/ static const Ellipsoid& WGS84(); }; } // namespace GeographicLib #endif // GEOGRAPHICLIB_ELLIPSOID_HPP geosphere/src/GeodesicExact.h0000644000176200001440000011311714323377037015717 0ustar liggesusers/** * \file GeodesicExact.hpp * \brief Header for GeographicLib::GeodesicExact class * * Copyright (c) Charles Karney (2012-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_GEODESICEXACT_HPP) #define GEOGRAPHICLIB_GEODESICEXACT_HPP 1 #include "Constants.h" #include "EllipticFunction.h" #include "DST.h" #include namespace GeographicLib { class GEOGRAPHICLIB_EXPORT DST; class GeodesicLineExact; /** * \brief Exact geodesic calculations * * The equations for geodesics on an ellipsoid can be expressed in terms of * incomplete elliptic integrals. The Geodesic class expands these integrals * in a series in the flattening \e f and this provides an accurate solution * for \e f ∈ [-0.01, 0.01]. The GeodesicExact class computes the * ellitpic integrals directly and so provides a solution which is valid for * all \e f. However, in practice, its use should be limited to about * b/\e a ∈ [0.01, 100] or \e f ∈ [−99, 0.99]. * * For the WGS84 ellipsoid, these classes are 2--3 times \e slower than the * series solution and 2--3 times \e less \e accurate (because it's less easy * to control round-off errors with the elliptic integral formulation); i.e., * the error is about 40 nm (40 nanometers) instead of 15 nm. However the * error in the series solution scales as f7 while the * error in the elliptic integral solution depends weakly on \e f. If the * quarter meridian distance is 10000 km and the ratio b/\e a = 1 * − \e f is varied then the approximate maximum error (expressed as a * distance) is
   *       1 - f  error (nm)
   *       1/128     387
   *       1/64      345
   *       1/32      269
   *       1/16      210
   *       1/8       115
   *       1/4        69
   *       1/2        36
   *         1        15
   *         2        25
   *         4        96
   *         8       318
   *        16       985
   *        32      2352
   *        64      6008
   *       128     19024
   * 
* * The area in this classes is computing by finding an accurate approximation * to the area integrand using a discrete sine transform fitting \e N equally * spaced points in σ. \e N chosen to ensure full accuracy for * b/\e a ∈ [0.01, 100] or \e f ∈ [−99, 0.99]. * * See \ref geodellip for the formulation. See the documentation on the * Geodesic class for additional information on the geodesic problems. * * Example of use: * \include example-GeodesicExact.cpp * * GeodSolve is a command-line utility * providing access to the functionality of GeodesicExact and * GeodesicLineExact (via the -E option). **********************************************************************/ class GEOGRAPHICLIB_EXPORT GeodesicExact { private: typedef Math::real real; friend class GeodesicLineExact; static const unsigned maxit1_ = 20; unsigned maxit2_; real tiny_, tol0_, tol1_, tol2_, tolb_, xthresh_; enum captype { CAP_NONE = 0U, CAP_E = 1U<<0, // Skip 1U<<1 for compatibility with Geodesic (not required) CAP_D = 1U<<2, CAP_H = 1U<<3, CAP_C4 = 1U<<4, CAP_ALL = 0x1FU, CAP_MASK = CAP_ALL, OUT_ALL = 0x7F80U, OUT_MASK = 0xFF80U, // Includes LONG_UNROLL }; static real Astroid(real x, real y); real _a, _f, _f1, _e2, _ep2, _n, _b, _c2, _etol2; int _nC4; DST _fft; void Lengths(const EllipticFunction& E, real sig12, real ssig1, real csig1, real dn1, real ssig2, real csig2, real dn2, real cbet1, real cbet2, unsigned outmask, real& s12s, real& m12a, real& m0, real& M12, real& M21) const; real InverseStart(EllipticFunction& E, real sbet1, real cbet1, real dn1, real sbet2, real cbet2, real dn2, real lam12, real slam12, real clam12, real& salp1, real& calp1, real& salp2, real& calp2, real& dnm) const; real Lambda12(real sbet1, real cbet1, real dn1, real sbet2, real cbet2, real dn2, real salp1, real calp1, real slam120, real clam120, real& salp2, real& calp2, real& sig12, real& ssig1, real& csig1, real& ssig2, real& csig2, EllipticFunction& E, real& domg12, bool diffp, real& dlam12) const; real GenInverse(real lat1, real lon1, real lat2, real lon2, unsigned outmask, real& s12, real& salp1, real& calp1, real& salp2, real& calp2, real& m12, real& M12, real& M21, real& S12) const; class I4Integrand { private: real X, tX, tdX, sX, sX1, sXX1, asinhsX, _k2; static real asinhsqrt(real x); static real t(real x); static real td(real x); // static real Dt(real x, real y); real DtX(real y) const; public: I4Integrand(real ep2, real k2); real operator()(real sig) const; }; public: /** * Bit masks for what calculations to do. These masks do double duty. * They signify to the GeodesicLineExact::GeodesicLineExact constructor and * to GeodesicExact::Line what capabilities should be included in the * GeodesicLineExact object. They also specify which results to return in * the general routines GeodesicExact::GenDirect and * GeodesicExact::GenInverse routines. GeodesicLineExact::mask is a * duplication of this enum. **********************************************************************/ enum mask { /** * No capabilities, no output. * @hideinitializer **********************************************************************/ NONE = 0U, /** * Calculate latitude \e lat2. (It's not necessary to include this as a * capability to GeodesicLineExact because this is included by default.) * @hideinitializer **********************************************************************/ LATITUDE = 1U<<7 | CAP_NONE, /** * Calculate longitude \e lon2. * @hideinitializer **********************************************************************/ LONGITUDE = 1U<<8 | CAP_H, /** * Calculate azimuths \e azi1 and \e azi2. (It's not necessary to * include this as a capability to GeodesicLineExact because this is * included by default.) * @hideinitializer **********************************************************************/ AZIMUTH = 1U<<9 | CAP_NONE, /** * Calculate distance \e s12. * @hideinitializer **********************************************************************/ DISTANCE = 1U<<10 | CAP_E, /** * A combination of the common capabilities: GeodesicExact::LATITUDE, * GeodesicExact::LONGITUDE, GeodesicExact::AZIMUTH, * GeodesicExact::DISTANCE. * @hideinitializer **********************************************************************/ STANDARD = LATITUDE | LONGITUDE | AZIMUTH | DISTANCE, /** * Allow distance \e s12 to be used as input in the direct geodesic * problem. * @hideinitializer **********************************************************************/ DISTANCE_IN = 1U<<11 | CAP_E, /** * Calculate reduced length \e m12. * @hideinitializer **********************************************************************/ REDUCEDLENGTH = 1U<<12 | CAP_D, /** * Calculate geodesic scales \e M12 and \e M21. * @hideinitializer **********************************************************************/ GEODESICSCALE = 1U<<13 | CAP_D, /** * Calculate area \e S12. * @hideinitializer **********************************************************************/ AREA = 1U<<14 | CAP_C4, /** * Unroll \e lon2 in the direct calculation. * @hideinitializer **********************************************************************/ LONG_UNROLL = 1U<<15, /** * All capabilities, calculate everything. (GeodesicExact::LONG_UNROLL * is not included in this mask.) * @hideinitializer **********************************************************************/ ALL = OUT_ALL| CAP_ALL, }; /** \name Constructor **********************************************************************/ ///@{ /** * Constructor for an ellipsoid with * * @param[in] a equatorial radius (meters). * @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere. * Negative \e f gives a prolate ellipsoid. * @exception GeographicErr if \e a or (1 − \e f) \e a is not * positive. **********************************************************************/ GeodesicExact(real a, real f); ///@} /** \name Direct geodesic problem specified in terms of distance. **********************************************************************/ ///@{ /** * Perform the direct geodesic calculation where the length of the geodesic * is specified in terms of distance. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] s12 distance between point 1 and point 2 (meters); it can be * signed. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees). * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] m12 reduced length of geodesic (meters). * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless). * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless). * @param[out] S12 area under the geodesic (meters2). * @return \e a12 arc length of between point 1 and point 2 (degrees). * * \e lat1 should be in the range [−90°, 90°]. The values of * \e lon2 and \e azi2 returned are in the range [−180°, * 180°]. * * If either point is at a pole, the azimuth is defined by keeping the * longitude fixed, writing \e lat = ±(90° − ε), * and taking the limit ε → 0+. An arc length greater that * 180° signifies a geodesic which is not a shortest path. (For a * prolate ellipsoid, an additional condition is necessary for a shortest * path: the longitudinal extent must not exceed of 180°.) * * The following functions are overloaded versions of GeodesicExact::Direct * which omit some of the output parameters. Note, however, that the arc * length is always computed and returned as the function value. **********************************************************************/ Math::real Direct(real lat1, real lon1, real azi1, real s12, real& lat2, real& lon2, real& azi2, real& m12, real& M12, real& M21, real& S12) const { real t; return GenDirect(lat1, lon1, azi1, false, s12, LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH | GEODESICSCALE | AREA, lat2, lon2, azi2, t, m12, M12, M21, S12); } /** * See the documentation for GeodesicExact::Direct. **********************************************************************/ Math::real Direct(real lat1, real lon1, real azi1, real s12, real& lat2, real& lon2) const { real t; return GenDirect(lat1, lon1, azi1, false, s12, LATITUDE | LONGITUDE, lat2, lon2, t, t, t, t, t, t); } /** * See the documentation for GeodesicExact::Direct. **********************************************************************/ Math::real Direct(real lat1, real lon1, real azi1, real s12, real& lat2, real& lon2, real& azi2) const { real t; return GenDirect(lat1, lon1, azi1, false, s12, LATITUDE | LONGITUDE | AZIMUTH, lat2, lon2, azi2, t, t, t, t, t); } /** * See the documentation for GeodesicExact::Direct. **********************************************************************/ Math::real Direct(real lat1, real lon1, real azi1, real s12, real& lat2, real& lon2, real& azi2, real& m12) const { real t; return GenDirect(lat1, lon1, azi1, false, s12, LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH, lat2, lon2, azi2, t, m12, t, t, t); } /** * See the documentation for GeodesicExact::Direct. **********************************************************************/ Math::real Direct(real lat1, real lon1, real azi1, real s12, real& lat2, real& lon2, real& azi2, real& M12, real& M21) const { real t; return GenDirect(lat1, lon1, azi1, false, s12, LATITUDE | LONGITUDE | AZIMUTH | GEODESICSCALE, lat2, lon2, azi2, t, t, M12, M21, t); } /** * See the documentation for GeodesicExact::Direct. **********************************************************************/ Math::real Direct(real lat1, real lon1, real azi1, real s12, real& lat2, real& lon2, real& azi2, real& m12, real& M12, real& M21) const { real t; return GenDirect(lat1, lon1, azi1, false, s12, LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH | GEODESICSCALE, lat2, lon2, azi2, t, m12, M12, M21, t); } ///@} /** \name Direct geodesic problem specified in terms of arc length. **********************************************************************/ ///@{ /** * Perform the direct geodesic calculation where the length of the geodesic * is specified in terms of arc length. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] a12 arc length between point 1 and point 2 (degrees); it can * be signed. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees). * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] s12 distance between point 1 and point 2 (meters). * @param[out] m12 reduced length of geodesic (meters). * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless). * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless). * @param[out] S12 area under the geodesic (meters2). * * \e lat1 should be in the range [−90°, 90°]. The values of * \e lon2 and \e azi2 returned are in the range [−180°, * 180°]. * * If either point is at a pole, the azimuth is defined by keeping the * longitude fixed, writing \e lat = ±(90° − ε), * and taking the limit ε → 0+. An arc length greater that * 180° signifies a geodesic which is not a shortest path. (For a * prolate ellipsoid, an additional condition is necessary for a shortest * path: the longitudinal extent must not exceed of 180°.) * * The following functions are overloaded versions of GeodesicExact::Direct * which omit some of the output parameters. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21, real& S12) const { GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | REDUCEDLENGTH | GEODESICSCALE | AREA, lat2, lon2, azi2, s12, m12, M12, M21, S12); } /** * See the documentation for GeodesicExact::ArcDirect. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2) const { real t; GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE, lat2, lon2, t, t, t, t, t, t); } /** * See the documentation for GeodesicExact::ArcDirect. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2, real& azi2) const { real t; GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE | AZIMUTH, lat2, lon2, azi2, t, t, t, t, t); } /** * See the documentation for GeodesicExact::ArcDirect. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2, real& azi2, real& s12) const { real t; GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE, lat2, lon2, azi2, s12, t, t, t, t); } /** * See the documentation for GeodesicExact::ArcDirect. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2, real& azi2, real& s12, real& m12) const { real t; GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | REDUCEDLENGTH, lat2, lon2, azi2, s12, m12, t, t, t); } /** * See the documentation for GeodesicExact::ArcDirect. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2, real& azi2, real& s12, real& M12, real& M21) const { real t; GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | GEODESICSCALE, lat2, lon2, azi2, s12, t, M12, M21, t); } /** * See the documentation for GeodesicExact::ArcDirect. **********************************************************************/ void ArcDirect(real lat1, real lon1, real azi1, real a12, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21) const { real t; GenDirect(lat1, lon1, azi1, true, a12, LATITUDE | LONGITUDE | AZIMUTH | DISTANCE | REDUCEDLENGTH | GEODESICSCALE, lat2, lon2, azi2, s12, m12, M12, M21, t); } ///@} /** \name General version of the direct geodesic solution. **********************************************************************/ ///@{ /** * The general direct geodesic calculation. GeodesicExact::Direct and * GeodesicExact::ArcDirect are defined in terms of this function. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] arcmode boolean flag determining the meaning of the second * parameter. * @param[in] s12_a12 if \e arcmode is false, this is the distance between * point 1 and point 2 (meters); otherwise it is the arc length between * point 1 and point 2 (degrees); it can be signed. * @param[in] outmask a bitor'ed combination of GeodesicExact::mask values * specifying which of the following parameters should be set. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees). * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] s12 distance between point 1 and point 2 (meters). * @param[out] m12 reduced length of geodesic (meters). * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless). * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless). * @param[out] S12 area under the geodesic (meters2). * @return \e a12 arc length of between point 1 and point 2 (degrees). * * The GeodesicExact::mask values possible for \e outmask are * - \e outmask |= GeodesicExact::LATITUDE for the latitude \e lat2; * - \e outmask |= GeodesicExact::LONGITUDE for the latitude \e lon2; * - \e outmask |= GeodesicExact::AZIMUTH for the latitude \e azi2; * - \e outmask |= GeodesicExact::DISTANCE for the distance \e s12; * - \e outmask |= GeodesicExact::REDUCEDLENGTH for the reduced length \e * m12; * - \e outmask |= GeodesicExact::GEODESICSCALE for the geodesic scales \e * M12 and \e M21; * - \e outmask |= GeodesicExact::AREA for the area \e S12; * - \e outmask |= GeodesicExact::ALL for all of the above; * - \e outmask |= GeodesicExact::LONG_UNROLL to unroll \e lon2 instead of * wrapping it into the range [−180°, 180°]. * . * The function value \e a12 is always computed and returned and this * equals \e s12_a12 is \e arcmode is true. If \e outmask includes * GeodesicExact::DISTANCE and \e arcmode is false, then \e s12 = \e * s12_a12. It is not necessary to include GeodesicExact::DISTANCE_IN in * \e outmask; this is automatically included is \e arcmode is false. * * With the GeodesicExact::LONG_UNROLL bit set, the quantity \e lon2 * − \e lon1 indicates how many times and in what sense the geodesic * encircles the ellipsoid. **********************************************************************/ Math::real GenDirect(real lat1, real lon1, real azi1, bool arcmode, real s12_a12, unsigned outmask, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21, real& S12) const; ///@} /** \name Inverse geodesic problem. **********************************************************************/ ///@{ /** * Perform the inverse geodesic calculation. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] lat2 latitude of point 2 (degrees). * @param[in] lon2 longitude of point 2 (degrees). * @param[out] s12 distance between point 1 and point 2 (meters). * @param[out] azi1 azimuth at point 1 (degrees). * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] m12 reduced length of geodesic (meters). * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless). * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless). * @param[out] S12 area under the geodesic (meters2). * @return \e a12 arc length of between point 1 and point 2 (degrees). * * \e lat1 and \e lat2 should be in the range [−90°, 90°]. * The values of \e azi1 and \e azi2 returned are in the range * [−180°, 180°]. * * If either point is at a pole, the azimuth is defined by keeping the * longitude fixed, writing \e lat = ±(90° − ε), * and taking the limit ε → 0+. * * The following functions are overloaded versions of * GeodesicExact::Inverse which omit some of the output parameters. Note, * however, that the arc length is always computed and returned as the * function value. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& s12, real& azi1, real& azi2, real& m12, real& M12, real& M21, real& S12) const { return GenInverse(lat1, lon1, lat2, lon2, DISTANCE | AZIMUTH | REDUCEDLENGTH | GEODESICSCALE | AREA, s12, azi1, azi2, m12, M12, M21, S12); } /** * See the documentation for GeodesicExact::Inverse. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& s12) const { real t; return GenInverse(lat1, lon1, lat2, lon2, DISTANCE, s12, t, t, t, t, t, t); } /** * See the documentation for GeodesicExact::Inverse. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& azi1, real& azi2) const { real t; return GenInverse(lat1, lon1, lat2, lon2, AZIMUTH, t, azi1, azi2, t, t, t, t); } /** * See the documentation for GeodesicExact::Inverse. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& s12, real& azi1, real& azi2) const { real t; return GenInverse(lat1, lon1, lat2, lon2, DISTANCE | AZIMUTH, s12, azi1, azi2, t, t, t, t); } /** * See the documentation for GeodesicExact::Inverse. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& s12, real& azi1, real& azi2, real& m12) const { real t; return GenInverse(lat1, lon1, lat2, lon2, DISTANCE | AZIMUTH | REDUCEDLENGTH, s12, azi1, azi2, m12, t, t, t); } /** * See the documentation for GeodesicExact::Inverse. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& s12, real& azi1, real& azi2, real& M12, real& M21) const { real t; return GenInverse(lat1, lon1, lat2, lon2, DISTANCE | AZIMUTH | GEODESICSCALE, s12, azi1, azi2, t, M12, M21, t); } /** * See the documentation for GeodesicExact::Inverse. **********************************************************************/ Math::real Inverse(real lat1, real lon1, real lat2, real lon2, real& s12, real& azi1, real& azi2, real& m12, real& M12, real& M21) const { real t; return GenInverse(lat1, lon1, lat2, lon2, DISTANCE | AZIMUTH | REDUCEDLENGTH | GEODESICSCALE, s12, azi1, azi2, m12, M12, M21, t); } ///@} /** \name General version of inverse geodesic solution. **********************************************************************/ ///@{ /** * The general inverse geodesic calculation. GeodesicExact::Inverse is * defined in terms of this function. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] lat2 latitude of point 2 (degrees). * @param[in] lon2 longitude of point 2 (degrees). * @param[in] outmask a bitor'ed combination of GeodesicExact::mask values * specifying which of the following parameters should be set. * @param[out] s12 distance between point 1 and point 2 (meters). * @param[out] azi1 azimuth at point 1 (degrees). * @param[out] azi2 (forward) azimuth at point 2 (degrees). * @param[out] m12 reduced length of geodesic (meters). * @param[out] M12 geodesic scale of point 2 relative to point 1 * (dimensionless). * @param[out] M21 geodesic scale of point 1 relative to point 2 * (dimensionless). * @param[out] S12 area under the geodesic (meters2). * @return \e a12 arc length of between point 1 and point 2 (degrees). * * The GeodesicExact::mask values possible for \e outmask are * - \e outmask |= GeodesicExact::DISTANCE for the distance \e s12; * - \e outmask |= GeodesicExact::AZIMUTH for the latitude \e azi2; * - \e outmask |= GeodesicExact::REDUCEDLENGTH for the reduced length \e * m12; * - \e outmask |= GeodesicExact::GEODESICSCALE for the geodesic scales \e * M12 and \e M21; * - \e outmask |= GeodesicExact::AREA for the area \e S12; * - \e outmask |= GeodesicExact::ALL for all of the above. * . * The arc length is always computed and returned as the function value. **********************************************************************/ Math::real GenInverse(real lat1, real lon1, real lat2, real lon2, unsigned outmask, real& s12, real& azi1, real& azi2, real& m12, real& M12, real& M21, real& S12) const; ///@} /** \name Interface to GeodesicLineExact. **********************************************************************/ ///@{ /** * Set up to compute several points on a single geodesic. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] caps bitor'ed combination of GeodesicExact::mask values * specifying the capabilities the GeodesicLineExact object should * possess, i.e., which quantities can be returned in calls to * GeodesicLineExact::Position. * @return a GeodesicLineExact object. * * \e lat1 should be in the range [−90°, 90°]. * * The GeodesicExact::mask values are * - \e caps |= GeodesicExact::LATITUDE for the latitude \e lat2; this is * added automatically; * - \e caps |= GeodesicExact::LONGITUDE for the latitude \e lon2; * - \e caps |= GeodesicExact::AZIMUTH for the azimuth \e azi2; this is * added automatically; * - \e caps |= GeodesicExact::DISTANCE for the distance \e s12; * - \e caps |= GeodesicExact::REDUCEDLENGTH for the reduced length \e m12; * - \e caps |= GeodesicExact::GEODESICSCALE for the geodesic scales \e M12 * and \e M21; * - \e caps |= GeodesicExact::AREA for the area \e S12; * - \e caps |= GeodesicExact::DISTANCE_IN permits the length of the * geodesic to be given in terms of \e s12; without this capability the * length can only be specified in terms of arc length; * - \e caps |= GeodesicExact::ALL for all of the above. * . * The default value of \e caps is GeodesicExact::ALL which turns on all * the capabilities. * * If the point is at a pole, the azimuth is defined by keeping \e lon1 * fixed, writing \e lat1 = ±(90 − ε), and taking the * limit ε → 0+. **********************************************************************/ GeodesicLineExact Line(real lat1, real lon1, real azi1, unsigned caps = ALL) const; /** * Define a GeodesicLineExact in terms of the inverse geodesic problem. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] lat2 latitude of point 2 (degrees). * @param[in] lon2 longitude of point 2 (degrees). * @param[in] caps bitor'ed combination of GeodesicExact::mask values * specifying the capabilities the GeodesicLineExact object should * possess, i.e., which quantities can be returned in calls to * GeodesicLineExact::Position. * @return a GeodesicLineExact object. * * This function sets point 3 of the GeodesicLineExact to correspond to * point 2 of the inverse geodesic problem. * * \e lat1 and \e lat2 should be in the range [−90°, 90°]. **********************************************************************/ GeodesicLineExact InverseLine(real lat1, real lon1, real lat2, real lon2, unsigned caps = ALL) const; /** * Define a GeodesicLineExact in terms of the direct geodesic problem * specified in terms of distance. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] s12 distance between point 1 and point 2 (meters); it can be * negative. * @param[in] caps bitor'ed combination of GeodesicExact::mask values * specifying the capabilities the GeodesicLineExact object should * possess, i.e., which quantities can be returned in calls to * GeodesicLineExact::Position. * @return a GeodesicLineExact object. * * This function sets point 3 of the GeodesicLineExact to correspond to * point 2 of the direct geodesic problem. * * \e lat1 should be in the range [−90°, 90°]. **********************************************************************/ GeodesicLineExact DirectLine(real lat1, real lon1, real azi1, real s12, unsigned caps = ALL) const; /** * Define a GeodesicLineExact in terms of the direct geodesic problem * specified in terms of arc length. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] a12 arc length between point 1 and point 2 (degrees); it can * be negative. * @param[in] caps bitor'ed combination of GeodesicExact::mask values * specifying the capabilities the GeodesicLineExact object should * possess, i.e., which quantities can be returned in calls to * GeodesicLineExact::Position. * @return a GeodesicLineExact object. * * This function sets point 3 of the GeodesicLineExact to correspond to * point 2 of the direct geodesic problem. * * \e lat1 should be in the range [−90°, 90°]. **********************************************************************/ GeodesicLineExact ArcDirectLine(real lat1, real lon1, real azi1, real a12, unsigned caps = ALL) const; /** * Define a GeodesicLineExact in terms of the direct geodesic problem * specified in terms of either distance or arc length. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi1 azimuth at point 1 (degrees). * @param[in] arcmode boolean flag determining the meaning of the \e * s12_a12. * @param[in] s12_a12 if \e arcmode is false, this is the distance between * point 1 and point 2 (meters); otherwise it is the arc length between * point 1 and point 2 (degrees); it can be negative. * @param[in] caps bitor'ed combination of GeodesicExact::mask values * specifying the capabilities the GeodesicLineExact object should * possess, i.e., which quantities can be returned in calls to * GeodesicLineExact::Position. * @return a GeodesicLineExact object. * * This function sets point 3 of the GeodesicLineExact to correspond to * point 2 of the direct geodesic problem. * * \e lat1 should be in the range [−90°, 90°]. **********************************************************************/ GeodesicLineExact GenDirectLine(real lat1, real lon1, real azi1, bool arcmode, real s12_a12, unsigned caps = ALL) const; ///@} /** \name Inspector functions. **********************************************************************/ ///@{ /** * @return \e a the equatorial radius of the ellipsoid (meters). This is * the value used in the constructor. **********************************************************************/ Math::real EquatorialRadius() const { return _a; } /** * @return \e f the flattening of the ellipsoid. This is the * value used in the constructor. **********************************************************************/ Math::real Flattening() const { return _f; } /** * @return total area of ellipsoid in meters2. The area of a * polygon encircling a pole can be found by adding * GeodesicExact::EllipsoidArea()/2 to the sum of \e S12 for each side of * the polygon. **********************************************************************/ Math::real EllipsoidArea() const { return 4 * Math::pi() * _c2; } ///@} /** * A global instantiation of GeodesicExact with the parameters for the * WGS84 ellipsoid. **********************************************************************/ static const GeodesicExact& WGS84(); }; } // namespace GeographicLib #endif // GEOGRAPHICLIB_GEODESICEXACT_HPP geosphere/src/Config.h0000644000176200001440000000063014064202407014376 0ustar liggesusers// This will be overwritten by ./configure #define GEOGRAPHICLIB_VERSION_STRING "1.52" #define GEOGRAPHICLIB_VERSION_MAJOR 1 #define GEOGRAPHICLIB_VERSION_MINOR 52 #define GEOGRAPHICLIB_VERSION_PATCH 0 // Undefine HAVE_LONG_DOUBLE if this type is unknown to the compiler #define GEOGRAPHICLIB_HAVE_LONG_DOUBLE 1 // Define WORDS_BIGENDIAN to be 1 if your machine is big endian /* #undef WORDS_BIGENDIAN */ geosphere/src/Constants.h0000644000176200001440000003171114323377171015162 0ustar liggesusers/** * \file Constants.hpp * \brief Header for GeographicLib::Constants class * * Copyright (c) Charles Karney (2008-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_CONSTANTS_HPP) #define GEOGRAPHICLIB_CONSTANTS_HPP 1 #include "Config.h" /** * @relates GeographicLib::Constants * Pack the version components into a single integer. Users should not rely on * this particular packing of the components of the version number; see the * documentation for GEOGRAPHICLIB_VERSION, below. **********************************************************************/ #define GEOGRAPHICLIB_VERSION_NUM(a,b,c) ((((a) * 10000 + (b)) * 100) + (c)) /** * @relates GeographicLib::Constants * The version of GeographicLib as a single integer, packed as MMmmmmpp where * MM is the major version, mmmm is the minor version, and pp is the patch * level. Users should not rely on this particular packing of the components * of the version number. Instead they should use a test such as \code #if GEOGRAPHICLIB_VERSION >= GEOGRAPHICLIB_VERSION_NUM(1,37,0) ... #endif * \endcode **********************************************************************/ #define GEOGRAPHICLIB_VERSION \ GEOGRAPHICLIB_VERSION_NUM(GEOGRAPHICLIB_VERSION_MAJOR, \ GEOGRAPHICLIB_VERSION_MINOR, \ GEOGRAPHICLIB_VERSION_PATCH) // For reference, here is a table of Visual Studio and _MSC_VER // correspondences: // // _MSC_VER Visual Studio // 1100 vc5 // 1200 vc6 // 1300 vc7 // 1310 vc7.1 (2003) // 1400 vc8 (2005) // 1500 vc9 (2008) // 1600 vc10 (2010) // 1700 vc11 (2012) // 1800 vc12 (2013) // 1900 vc14 (2015) First version of VS to include enough C++11 support // 191[0-9] vc15 (2017) // 192[0-9] vc16 (2019) // 193[0-9] vc17 (2022) #if defined(_MSC_VER) && defined(GEOGRAPHICLIB_SHARED_LIB) && \ GEOGRAPHICLIB_SHARED_LIB # if GEOGRAPHICLIB_SHARED_LIB > 1 # error GEOGRAPHICLIB_SHARED_LIB must be 0 or 1 # elif defined(GeographicLib_SHARED_EXPORTS) # define GEOGRAPHICLIB_EXPORT __declspec(dllexport) # else # define GEOGRAPHICLIB_EXPORT __declspec(dllimport) # endif #else # define GEOGRAPHICLIB_EXPORT #endif // Use GEOGRAPHICLIB_DEPRECATED to mark functions, types or variables as // deprecated. Code inspired by Apache Subversion's svn_types.h file (via // MPFR). #if defined(__GNUC__) # if __GNUC__ > 4 # define GEOGRAPHICLIB_DEPRECATED(msg) __attribute__((deprecated(msg))) # else # define GEOGRAPHICLIB_DEPRECATED(msg) __attribute__((deprecated)) # endif #elif defined(_MSC_VER) && _MSC_VER >= 1300 # define GEOGRAPHICLIB_DEPRECATED(msg) __declspec(deprecated(msg)) #else # define GEOGRAPHICLIB_DEPRECATED(msg) #endif #include #include #include "Math.h" /** * \brief Namespace for %GeographicLib * * All of %GeographicLib is defined within the GeographicLib namespace. In * addition all the header files are included via %GeographicLib/Class.hpp. * This minimizes the likelihood of conflicts with other packages. **********************************************************************/ namespace GeographicLib { /** * \brief %Constants needed by %GeographicLib * * Define constants specifying the WGS84 ellipsoid, the UTM and UPS * projections, and various unit conversions. * * Example of use: * \include example-Constants.cpp **********************************************************************/ class GEOGRAPHICLIB_EXPORT Constants { private: typedef Math::real real; Constants() = delete; // Disable constructor public: /** * A synonym for Math::degree(). **********************************************************************/ static Math::real degree() { return Math::degree(); } /** * @return the number of radians in an arcminute. **********************************************************************/ static Math::real arcminute() { return Math::degree() / Math::real(Math::dm); } /** * @return the number of radians in an arcsecond. **********************************************************************/ static Math::real arcsecond() { return Math::degree() / Math::real(Math::ds); } /** \name Ellipsoid parameters **********************************************************************/ ///@{ /** * @tparam T the type of the returned value. * @return the equatorial radius of WGS84 ellipsoid (6378137 m). **********************************************************************/ template static T WGS84_a() { return 6378137 * meter(); } /** * @tparam T the type of the returned value. * @return the flattening of WGS84 ellipsoid (1/298.257223563). **********************************************************************/ template static T WGS84_f() { // Evaluating this as 1000000000 / T(298257223563LL) reduces the // round-off error by about 10%. However, expressing the flattening as // 1/298.257223563 is well ingrained. return 1 / ( T(298257223563LL) / 1000000000 ); } /** * @tparam T the type of the returned value. * @return the gravitational constant of the WGS84 ellipsoid, \e GM, in * m3 s−2. **********************************************************************/ template static T WGS84_GM() { return T(3986004) * 100000000 + 41800000; } /** * @tparam T the type of the returned value. * @return the angular velocity of the WGS84 ellipsoid, ω, in rad * s−1. **********************************************************************/ template static T WGS84_omega() { return 7292115 / (T(1000000) * 100000); } /** * @tparam T the type of the returned value. * @return the equatorial radius of GRS80 ellipsoid, \e a, in m. **********************************************************************/ template static T GRS80_a() { return 6378137 * meter(); } /** * @tparam T the type of the returned value. * @return the gravitational constant of the GRS80 ellipsoid, \e GM, in * m3 s−2. **********************************************************************/ template static T GRS80_GM() { return T(3986005) * 100000000; } /** * @tparam T the type of the returned value. * @return the angular velocity of the GRS80 ellipsoid, ω, in rad * s−1. * * This is about 2 π 366.25 / (365.25 × 24 × 3600) rad * s−1. 365.25 is the number of days in a Julian year and * 365.35/366.25 converts from solar days to sidereal days. Using the * number of days in a Gregorian year (365.2425) results in a worse * approximation (because the Gregorian year includes the precession of the * earth's axis). **********************************************************************/ template static T GRS80_omega() { return 7292115 / (T(1000000) * 100000); } /** * @tparam T the type of the returned value. * @return the dynamical form factor of the GRS80 ellipsoid, * J2. **********************************************************************/ template static T GRS80_J2() { return T(108263) / 100000000; } /** * @tparam T the type of the returned value. * @return the central scale factor for UTM (0.9996). **********************************************************************/ template static T UTM_k0() {return T(9996) / 10000; } /** * @tparam T the type of the returned value. * @return the central scale factor for UPS (0.994). **********************************************************************/ template static T UPS_k0() { return T(994) / 1000; } ///@} /** \name SI units **********************************************************************/ ///@{ /** * @tparam T the type of the returned value. * @return the number of meters in a meter. * * This is unity, but this lets the internal system of units be changed if * necessary. **********************************************************************/ template static T meter() { return T(1); } /** * @return the number of meters in a kilometer. **********************************************************************/ static Math::real kilometer() { return 1000 * meter(); } /** * @return the number of meters in a nautical mile (approximately 1 arc * minute) **********************************************************************/ static Math::real nauticalmile() { return 1852 * meter(); } /** * @tparam T the type of the returned value. * @return the number of square meters in a square meter. * * This is unity, but this lets the internal system of units be changed if * necessary. **********************************************************************/ template static T square_meter() { return meter() * meter(); } /** * @return the number of square meters in a hectare. **********************************************************************/ static Math::real hectare() { return 10000 * square_meter(); } /** * @return the number of square meters in a square kilometer. **********************************************************************/ static Math::real square_kilometer() { return kilometer() * kilometer(); } /** * @return the number of square meters in a square nautical mile. **********************************************************************/ static Math::real square_nauticalmile() { return nauticalmile() * nauticalmile(); } ///@} /** \name Anachronistic British units **********************************************************************/ ///@{ /** * @return the number of meters in an international foot. **********************************************************************/ static Math::real foot() { return real(254 * 12) / 10000 * meter(); } /** * @return the number of meters in a yard. **********************************************************************/ static Math::real yard() { return 3 * foot(); } /** * @return the number of meters in a fathom. **********************************************************************/ static Math::real fathom() { return 2 * yard(); } /** * @return the number of meters in a chain. **********************************************************************/ static Math::real chain() { return 22 * yard(); } /** * @return the number of meters in a furlong. **********************************************************************/ static Math::real furlong() { return 10 * chain(); } /** * @return the number of meters in a statute mile. **********************************************************************/ static Math::real mile() { return 8 * furlong(); } /** * @return the number of square meters in an acre. **********************************************************************/ static Math::real acre() { return chain() * furlong(); } /** * @return the number of square meters in a square statute mile. **********************************************************************/ static Math::real square_mile() { return mile() * mile(); } ///@} /** \name Anachronistic US units **********************************************************************/ ///@{ /** * @return the number of meters in a US survey foot. **********************************************************************/ static Math::real surveyfoot() { return real(1200) / 3937 * meter(); } ///@} }; /** * \brief Exception handling for %GeographicLib * * A class to handle exceptions. It's derived from std::runtime_error so it * can be caught by the usual catch clauses. * * Example of use: * \include example-GeographicErr.cpp **********************************************************************/ class GeographicErr : public std::runtime_error { public: /** * Constructor * * @param[in] msg a string message, which is accessible in the catch * clause via what(). **********************************************************************/ GeographicErr(const std::string& msg) : std::runtime_error(msg) {} }; } // namespace GeographicLib #endif // GEOGRAPHICLIB_CONSTANTS_HPP geosphere/src/Math.cpp0000644000176200001440000002625714323376012014434 0ustar liggesusers/** * \file Math.cpp * \brief Implementation for GeographicLib::Math class * * Copyright (c) Charles Karney (2015-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #include "Math.h" #if defined(_MSC_VER) // Squelch warnings about constant conditional and enum-float expressions # pragma warning (disable: 4127 5055) #endif namespace GeographicLib { using namespace std; void Math::dummy() { static_assert(GEOGRAPHICLIB_PRECISION >= 1 && GEOGRAPHICLIB_PRECISION <= 5, "Bad value of precision"); } int Math::digits() { #if GEOGRAPHICLIB_PRECISION != 5 return numeric_limits::digits; #else return numeric_limits::digits(); #endif } int Math::set_digits(int ndigits) { #if GEOGRAPHICLIB_PRECISION != 5 (void)ndigits; #else mpfr::mpreal::set_default_prec(ndigits >= 2 ? ndigits : 2); #endif return digits(); } int Math::digits10() { #if GEOGRAPHICLIB_PRECISION != 5 return numeric_limits::digits10; #else return numeric_limits::digits10(); #endif } int Math::extra_digits() { return digits10() > numeric_limits::digits10 ? digits10() - numeric_limits::digits10 : 0; } template T Math::sum(T u, T v, T& t) { GEOGRAPHICLIB_VOLATILE T s = u + v; GEOGRAPHICLIB_VOLATILE T up = s - v; GEOGRAPHICLIB_VOLATILE T vpp = s - up; up -= u; vpp -= v; // if s = 0, then t = 0 and give t the same sign as s // mpreal needs T(0) here t = s != 0 ? T(0) - (up + vpp) : s; // u + v = s + t // = round(u + v) + t return s; } template T Math::AngNormalize(T x) { T y = remainder(x, T(td)); #if GEOGRAPHICLIB_PRECISION == 4 // boost-quadmath doesn't set the sign of 0 correctly, see // https://github.com/boostorg/multiprecision/issues/426 // Fixed by https://github.com/boostorg/multiprecision/pull/428 if (y == 0) y = copysign(y, x); #endif return fabs(y) == T(hd) ? copysign(T(hd), x) : y; } template T Math::AngDiff(T x, T y, T& e) { // Use remainder instead of AngNormalize, since we treat boundary cases // later taking account of the error T d = sum(remainder(-x, T(td)), remainder( y, T(td)), e); // This second sum can only change d if abs(d) < 128, so don't need to // apply remainder yet again. d = sum(remainder(d, T(td)), e, e); // Fix the sign if d = -180, 0, 180. if (d == 0 || fabs(d) == hd) // If e == 0, take sign from y - x // else (e != 0, implies d = +/-180), d and e must have opposite signs d = copysign(d, e == 0 ? y - x : -e); return d; } template T Math::AngRound(T x) { static const T z = T(1)/T(16); GEOGRAPHICLIB_VOLATILE T y = fabs(x); GEOGRAPHICLIB_VOLATILE T w = z - y; // The compiler mustn't "simplify" z - (z - y) to y y = w > 0 ? z - w : y; return copysign(y, x); } template void Math::sincosd(T x, T& sinx, T& cosx) { // In order to minimize round-off errors, this function exactly reduces // the argument to the range [-45, 45] before converting it to radians. T r; int q = 0; r = remquo(x, T(qd), &q); // now abs(r) <= 45 r *= degree(); // g++ -O turns these two function calls into a call to sincos T s = sin(r), c = cos(r); switch (unsigned(q) & 3U) { case 0U: sinx = s; cosx = c; break; case 1U: sinx = c; cosx = -s; break; case 2U: sinx = -s; cosx = -c; break; default: sinx = -c; cosx = s; break; // case 3U } // http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1950.pdf // mpreal needs T(0) here cosx += T(0); // special values from F.10.1.12 if (sinx == 0) sinx = copysign(sinx, x); // special values from F.10.1.13 } template void Math::sincosde(T x, T t, T& sinx, T& cosx) { // In order to minimize round-off errors, this function exactly reduces // the argument to the range [-45, 45] before converting it to radians. // This implementation allows x outside [-180, 180], but implementations in // other languages may not. T r; int q = 0; r = AngRound(remquo(x, T(qd), &q) + t); // now abs(r) <= 45 r *= degree(); // g++ -O turns these two function calls into a call to sincos T s = sin(r), c = cos(r); switch (unsigned(q) & 3U) { case 0U: sinx = s; cosx = c; break; case 1U: sinx = c; cosx = -s; break; case 2U: sinx = -s; cosx = -c; break; default: sinx = -c; cosx = s; break; // case 3U } // http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1950.pdf // mpreal needs T(0) here cosx += T(0); // special values from F.10.1.12 if (sinx == 0) sinx = copysign(sinx, x); // special values from F.10.1.13 } template T Math::sind(T x) { // See sincosd T r; int q = 0; r = remquo(x, T(qd), &q); // now abs(r) <= 45 r *= degree(); unsigned p = unsigned(q); r = p & 1U ? cos(r) : sin(r); if (p & 2U) r = -r; if (r == 0) r = copysign(r, x); return r; } template T Math::cosd(T x) { // See sincosd T r; int q = 0; r = remquo(x, T(qd), &q); // now abs(r) <= 45 r *= degree(); unsigned p = unsigned(q + 1); r = p & 1U ? cos(r) : sin(r); if (p & 2U) r = -r; // mpreal needs T(0) here return T(0) + r; } template T Math::tand(T x) { static const T overflow = 1 / sq(numeric_limits::epsilon()); T s, c; sincosd(x, s, c); // http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1950.pdf T r = s / c; // special values from F.10.1.14 // With C++17 this becomes clamp(s / c, -overflow, overflow); // Use max/min here (instead of fmax/fmin) to preserve NaN return min(max(r, -overflow), overflow); } template T Math::atan2d(T y, T x) { // In order to minimize round-off errors, this function rearranges the // arguments so that result of atan2 is in the range [-pi/4, pi/4] before // converting it to degrees and mapping the result to the correct // quadrant. int q = 0; if (fabs(y) > fabs(x)) { swap(x, y); q = 2; } if (signbit(x)) { x = -x; ++q; } // here x >= 0 and x >= abs(y), so angle is in [-pi/4, pi/4] T ang = atan2(y, x) / degree(); switch (q) { case 1: ang = copysign(T(hd), y) - ang; break; case 2: ang = qd - ang; break; case 3: ang = -qd + ang; break; default: break; } return ang; } template T Math::atand(T x) { return atan2d(x, T(1)); } template T Math::eatanhe(T x, T es) { return es > 0 ? es * atanh(es * x) : -es * atan(es * x); } template T Math::taupf(T tau, T es) { // Need this test, otherwise tau = +/-inf gives taup = nan. if (isfinite(tau)) { T tau1 = hypot(T(1), tau), sig = sinh( eatanhe(tau / tau1, es ) ); return hypot(T(1), sig) * tau - sig * tau1; } else return tau; } template T Math::tauf(T taup, T es) { static const int numit = 5; // min iterations = 1, max iterations = 2; mean = 1.95 static const T tol = sqrt(numeric_limits::epsilon()) / 10; static const T taumax = 2 / sqrt(numeric_limits::epsilon()); T e2m = 1 - sq(es), // To lowest order in e^2, taup = (1 - e^2) * tau = _e2m * tau; so use // tau = taup/e2m as a starting guess. Only 1 iteration is needed for // |lat| < 3.35 deg, otherwise 2 iterations are needed. If, instead, tau // = taup is used the mean number of iterations increases to 1.999 (2 // iterations are needed except near tau = 0). // // For large tau, taup = exp(-es*atanh(es)) * tau. Use this as for the // initial guess for |taup| > 70 (approx |phi| > 89deg). Then for // sufficiently large tau (such that sqrt(1+tau^2) = |tau|), we can exit // with the intial guess and avoid overflow problems. This also reduces // the mean number of iterations slightly from 1.963 to 1.954. tau = fabs(taup) > 70 ? taup * exp(eatanhe(T(1), es)) : taup/e2m, stol = tol * fmax(T(1), fabs(taup)); if (!(fabs(tau) < taumax)) return tau; // handles +/-inf and nan for (int i = 0; i < numit || GEOGRAPHICLIB_PANIC; ++i) { T taupa = taupf(tau, es), dtau = (taup - taupa) * (1 + e2m * sq(tau)) / ( e2m * hypot(T(1), tau) * hypot(T(1), taupa) ); tau += dtau; if (!(fabs(dtau) >= stol)) break; } return tau; } template T Math::NaN() { #if defined(_MSC_VER) return numeric_limits::has_quiet_NaN ? numeric_limits::quiet_NaN() : (numeric_limits::max)(); #else return numeric_limits::has_quiet_NaN ? numeric_limits::quiet_NaN() : numeric_limits::max(); #endif } template T Math::infinity() { #if defined(_MSC_VER) return numeric_limits::has_infinity ? numeric_limits::infinity() : (numeric_limits::max)(); #else return numeric_limits::has_infinity ? numeric_limits::infinity() : numeric_limits::max(); #endif } /// \cond SKIP // Instantiate #define GEOGRAPHICLIB_MATH_INSTANTIATE(T) \ template T GEOGRAPHICLIB_EXPORT Math::sum (T, T, T&); \ template T GEOGRAPHICLIB_EXPORT Math::AngNormalize (T); \ template T GEOGRAPHICLIB_EXPORT Math::AngDiff (T, T, T&); \ template T GEOGRAPHICLIB_EXPORT Math::AngRound (T); \ template void GEOGRAPHICLIB_EXPORT Math::sincosd (T, T&, T&); \ template void GEOGRAPHICLIB_EXPORT Math::sincosde (T, T, T&, T&); \ template T GEOGRAPHICLIB_EXPORT Math::sind (T); \ template T GEOGRAPHICLIB_EXPORT Math::cosd (T); \ template T GEOGRAPHICLIB_EXPORT Math::tand (T); \ template T GEOGRAPHICLIB_EXPORT Math::atan2d (T, T); \ template T GEOGRAPHICLIB_EXPORT Math::atand (T); \ template T GEOGRAPHICLIB_EXPORT Math::eatanhe (T, T); \ template T GEOGRAPHICLIB_EXPORT Math::taupf (T, T); \ template T GEOGRAPHICLIB_EXPORT Math::tauf (T, T); \ template T GEOGRAPHICLIB_EXPORT Math::NaN (); \ template T GEOGRAPHICLIB_EXPORT Math::infinity (); // Instantiate with the standard floating type GEOGRAPHICLIB_MATH_INSTANTIATE(float) GEOGRAPHICLIB_MATH_INSTANTIATE(double) #if GEOGRAPHICLIB_HAVE_LONG_DOUBLE // Instantiate if long double is distinct from double GEOGRAPHICLIB_MATH_INSTANTIATE(long double) #endif #if GEOGRAPHICLIB_PRECISION > 3 // Instantiate with the high precision type GEOGRAPHICLIB_MATH_INSTANTIATE(Math::real) #endif #undef GEOGRAPHICLIB_MATH_INSTANTIATE // Also we need int versions for Utility::nummatch template int GEOGRAPHICLIB_EXPORT Math::NaN (); template int GEOGRAPHICLIB_EXPORT Math::infinity(); /// \endcond } // namespace GeographicLib geosphere/src/RcppExports.cpp0000644000176200001440000001065514323401003016014 0ustar liggesusers// Generated by using Rcpp::compileAttributes() -> do not edit by hand // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 #include using namespace Rcpp; #ifdef RCPP_USE_GLOBAL_ROSTREAM Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); #endif // geodesic std::vector geodesic(std::vector lon1, std::vector lat1, std::vector azi1, std::vector s12, double a, double f); RcppExport SEXP _geosphere_geodesic(SEXP lon1SEXP, SEXP lat1SEXP, SEXP azi1SEXP, SEXP s12SEXP, SEXP aSEXP, SEXP fSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< std::vector >::type lon1(lon1SEXP); Rcpp::traits::input_parameter< std::vector >::type lat1(lat1SEXP); Rcpp::traits::input_parameter< std::vector >::type azi1(azi1SEXP); Rcpp::traits::input_parameter< std::vector >::type s12(s12SEXP); Rcpp::traits::input_parameter< double >::type a(aSEXP); Rcpp::traits::input_parameter< double >::type f(fSEXP); rcpp_result_gen = Rcpp::wrap(geodesic(lon1, lat1, azi1, s12, a, f)); return rcpp_result_gen; END_RCPP } // inversegeodesic std::vector inversegeodesic(std::vector lon1, std::vector lat1, std::vector lon2, std::vector lat2, double a, double f); RcppExport SEXP _geosphere_inversegeodesic(SEXP lon1SEXP, SEXP lat1SEXP, SEXP lon2SEXP, SEXP lat2SEXP, SEXP aSEXP, SEXP fSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< std::vector >::type lon1(lon1SEXP); Rcpp::traits::input_parameter< std::vector >::type lat1(lat1SEXP); Rcpp::traits::input_parameter< std::vector >::type lon2(lon2SEXP); Rcpp::traits::input_parameter< std::vector >::type lat2(lat2SEXP); Rcpp::traits::input_parameter< double >::type a(aSEXP); Rcpp::traits::input_parameter< double >::type f(fSEXP); rcpp_result_gen = Rcpp::wrap(inversegeodesic(lon1, lat1, lon2, lat2, a, f)); return rcpp_result_gen; END_RCPP } // polygonarea std::vector polygonarea(std::vector lon, std::vector lat, double a, double f); RcppExport SEXP _geosphere_polygonarea(SEXP lonSEXP, SEXP latSEXP, SEXP aSEXP, SEXP fSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< std::vector >::type lon(lonSEXP); Rcpp::traits::input_parameter< std::vector >::type lat(latSEXP); Rcpp::traits::input_parameter< double >::type a(aSEXP); Rcpp::traits::input_parameter< double >::type f(fSEXP); rcpp_result_gen = Rcpp::wrap(polygonarea(lon, lat, a, f)); return rcpp_result_gen; END_RCPP } // geodesic_nodes std::vector> geodesic_nodes(double lon1, double lat1, double lon2, double lat2, size_t n, double distance, bool arc, double a, double f); RcppExport SEXP _geosphere_geodesic_nodes(SEXP lon1SEXP, SEXP lat1SEXP, SEXP lon2SEXP, SEXP lat2SEXP, SEXP nSEXP, SEXP distanceSEXP, SEXP arcSEXP, SEXP aSEXP, SEXP fSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< double >::type lon1(lon1SEXP); Rcpp::traits::input_parameter< double >::type lat1(lat1SEXP); Rcpp::traits::input_parameter< double >::type lon2(lon2SEXP); Rcpp::traits::input_parameter< double >::type lat2(lat2SEXP); Rcpp::traits::input_parameter< size_t >::type n(nSEXP); Rcpp::traits::input_parameter< double >::type distance(distanceSEXP); Rcpp::traits::input_parameter< bool >::type arc(arcSEXP); Rcpp::traits::input_parameter< double >::type a(aSEXP); Rcpp::traits::input_parameter< double >::type f(fSEXP); rcpp_result_gen = Rcpp::wrap(geodesic_nodes(lon1, lat1, lon2, lat2, n, distance, arc, a, f)); return rcpp_result_gen; END_RCPP } static const R_CallMethodDef CallEntries[] = { {"_geosphere_geodesic", (DL_FUNC) &_geosphere_geodesic, 6}, {"_geosphere_inversegeodesic", (DL_FUNC) &_geosphere_inversegeodesic, 6}, {"_geosphere_polygonarea", (DL_FUNC) &_geosphere_polygonarea, 4}, {"_geosphere_geodesic_nodes", (DL_FUNC) &_geosphere_geodesic_nodes, 9}, {NULL, NULL, 0} }; RcppExport void R_init_geosphere(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } geosphere/src/GeodesicLine.cpp0000644000176200001440000003102614323376011016062 0ustar liggesusers/** * \file GeodesicLine.cpp * \brief Implementation for GeographicLib::GeodesicLine class * * Copyright (c) Charles Karney (2009-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ * * This is a reformulation of the geodesic problem. The notation is as * follows: * - at a general point (no suffix or 1 or 2 as suffix) * - phi = latitude * - beta = latitude on auxiliary sphere * - omega = longitude on auxiliary sphere * - lambda = longitude * - alpha = azimuth of great circle * - sigma = arc length along great circle * - s = distance * - tau = scaled distance (= sigma at multiples of pi/2) * - at northwards equator crossing * - beta = phi = 0 * - omega = lambda = 0 * - alpha = alpha0 * - sigma = s = 0 * - a 12 suffix means a difference, e.g., s12 = s2 - s1. * - s and c prefixes mean sin and cos **********************************************************************/ #include "GeodesicLine.h" #if defined(_MSC_VER) // Squelch warnings about mixing enums # pragma warning (disable: 5054) #endif namespace GeographicLib { using namespace std; void GeodesicLine::LineInit(const Geodesic& g, real lat1, real lon1, real azi1, real salp1, real calp1, unsigned caps) { tiny_ = g.tiny_; _lat1 = Math::LatFix(lat1); _lon1 = lon1; _azi1 = azi1; _salp1 = salp1; _calp1 = calp1; _a = g._a; _f = g._f; _b = g._b; _c2 = g._c2; _f1 = g._f1; // Always allow latitude and azimuth and unrolling of longitude _caps = caps | LATITUDE | AZIMUTH | LONG_UNROLL; real cbet1, sbet1; Math::sincosd(Math::AngRound(_lat1), sbet1, cbet1); sbet1 *= _f1; // Ensure cbet1 = +epsilon at poles Math::norm(sbet1, cbet1); cbet1 = fmax(tiny_, cbet1); _dn1 = sqrt(1 + g._ep2 * Math::sq(sbet1)); // Evaluate alp0 from sin(alp1) * cos(bet1) = sin(alp0), _salp0 = _salp1 * cbet1; // alp0 in [0, pi/2 - |bet1|] // Alt: calp0 = hypot(sbet1, calp1 * cbet1). The following // is slightly better (consider the case salp1 = 0). _calp0 = hypot(_calp1, _salp1 * sbet1); // Evaluate sig with tan(bet1) = tan(sig1) * cos(alp1). // sig = 0 is nearest northward crossing of equator. // With bet1 = 0, alp1 = pi/2, we have sig1 = 0 (equatorial line). // With bet1 = pi/2, alp1 = -pi, sig1 = pi/2 // With bet1 = -pi/2, alp1 = 0 , sig1 = -pi/2 // Evaluate omg1 with tan(omg1) = sin(alp0) * tan(sig1). // With alp0 in (0, pi/2], quadrants for sig and omg coincide. // No atan2(0,0) ambiguity at poles since cbet1 = +epsilon. // With alp0 = 0, omg1 = 0 for alp1 = 0, omg1 = pi for alp1 = pi. _ssig1 = sbet1; _somg1 = _salp0 * sbet1; _csig1 = _comg1 = sbet1 != 0 || _calp1 != 0 ? cbet1 * _calp1 : 1; Math::norm(_ssig1, _csig1); // sig1 in (-pi, pi] // Math::norm(_somg1, _comg1); -- don't need to normalize! _k2 = Math::sq(_calp0) * g._ep2; real eps = _k2 / (2 * (1 + sqrt(1 + _k2)) + _k2); if (_caps & CAP_C1) { _aA1m1 = Geodesic::A1m1f(eps); Geodesic::C1f(eps, _cC1a); _bB11 = Geodesic::SinCosSeries(true, _ssig1, _csig1, _cC1a, nC1_); real s = sin(_bB11), c = cos(_bB11); // tau1 = sig1 + B11 _stau1 = _ssig1 * c + _csig1 * s; _ctau1 = _csig1 * c - _ssig1 * s; // Not necessary because C1pa reverts C1a // _bB11 = -SinCosSeries(true, _stau1, _ctau1, _cC1pa, nC1p_); } if (_caps & CAP_C1p) Geodesic::C1pf(eps, _cC1pa); if (_caps & CAP_C2) { _aA2m1 = Geodesic::A2m1f(eps); Geodesic::C2f(eps, _cC2a); _bB21 = Geodesic::SinCosSeries(true, _ssig1, _csig1, _cC2a, nC2_); } if (_caps & CAP_C3) { g.C3f(eps, _cC3a); _aA3c = -_f * _salp0 * g.A3f(eps); _bB31 = Geodesic::SinCosSeries(true, _ssig1, _csig1, _cC3a, nC3_-1); } if (_caps & CAP_C4) { g.C4f(eps, _cC4a); // Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0) _aA4 = Math::sq(_a) * _calp0 * _salp0 * g._e2; _bB41 = Geodesic::SinCosSeries(false, _ssig1, _csig1, _cC4a, nC4_); } _a13 = _s13 = Math::NaN(); } GeodesicLine::GeodesicLine(const Geodesic& g, real lat1, real lon1, real azi1, unsigned caps) { azi1 = Math::AngNormalize(azi1); real salp1, calp1; // Guard against underflow in salp0. Also -0 is converted to +0. Math::sincosd(Math::AngRound(azi1), salp1, calp1); LineInit(g, lat1, lon1, azi1, salp1, calp1, caps); } GeodesicLine::GeodesicLine(const Geodesic& g, real lat1, real lon1, real azi1, real salp1, real calp1, unsigned caps, bool arcmode, real s13_a13) { LineInit(g, lat1, lon1, azi1, salp1, calp1, caps); GenSetDistance(arcmode, s13_a13); } Math::real GeodesicLine::GenPosition(bool arcmode, real s12_a12, unsigned outmask, real& lat2, real& lon2, real& azi2, real& s12, real& m12, real& M12, real& M21, real& S12) const { outmask &= _caps & OUT_MASK; if (!( Init() && (arcmode || (_caps & (OUT_MASK & DISTANCE_IN))) )) // Uninitialized or impossible distance calculation requested return Math::NaN(); // Avoid warning about uninitialized B12. real sig12, ssig12, csig12, B12 = 0, AB1 = 0; if (arcmode) { // Interpret s12_a12 as spherical arc length sig12 = s12_a12 * Math::degree(); Math::sincosd(s12_a12, ssig12, csig12); } else { // Interpret s12_a12 as distance real tau12 = s12_a12 / (_b * (1 + _aA1m1)), s = sin(tau12), c = cos(tau12); // tau2 = tau1 + tau12 B12 = - Geodesic::SinCosSeries(true, _stau1 * c + _ctau1 * s, _ctau1 * c - _stau1 * s, _cC1pa, nC1p_); sig12 = tau12 - (B12 - _bB11); ssig12 = sin(sig12); csig12 = cos(sig12); if (fabs(_f) > 0.01) { // Reverted distance series is inaccurate for |f| > 1/100, so correct // sig12 with 1 Newton iteration. The following table shows the // approximate maximum error for a = WGS_a() and various f relative to // GeodesicExact. // erri = the error in the inverse solution (nm) // errd = the error in the direct solution (series only) (nm) // errda = the error in the direct solution // (series + 1 Newton) (nm) // // f erri errd errda // -1/5 12e6 1.2e9 69e6 // -1/10 123e3 12e6 765e3 // -1/20 1110 108e3 7155 // -1/50 18.63 200.9 27.12 // -1/100 18.63 23.78 23.37 // -1/150 18.63 21.05 20.26 // 1/150 22.35 24.73 25.83 // 1/100 22.35 25.03 25.31 // 1/50 29.80 231.9 30.44 // 1/20 5376 146e3 10e3 // 1/10 829e3 22e6 1.5e6 // 1/5 157e6 3.8e9 280e6 real ssig2 = _ssig1 * csig12 + _csig1 * ssig12, csig2 = _csig1 * csig12 - _ssig1 * ssig12; B12 = Geodesic::SinCosSeries(true, ssig2, csig2, _cC1a, nC1_); real serr = (1 + _aA1m1) * (sig12 + (B12 - _bB11)) - s12_a12 / _b; sig12 = sig12 - serr / sqrt(1 + _k2 * Math::sq(ssig2)); ssig12 = sin(sig12); csig12 = cos(sig12); // Update B12 below } } real ssig2, csig2, sbet2, cbet2, salp2, calp2; // sig2 = sig1 + sig12 ssig2 = _ssig1 * csig12 + _csig1 * ssig12; csig2 = _csig1 * csig12 - _ssig1 * ssig12; real dn2 = sqrt(1 + _k2 * Math::sq(ssig2)); if (outmask & (DISTANCE | REDUCEDLENGTH | GEODESICSCALE)) { if (arcmode || fabs(_f) > 0.01) B12 = Geodesic::SinCosSeries(true, ssig2, csig2, _cC1a, nC1_); AB1 = (1 + _aA1m1) * (B12 - _bB11); } // sin(bet2) = cos(alp0) * sin(sig2) sbet2 = _calp0 * ssig2; // Alt: cbet2 = hypot(csig2, salp0 * ssig2); cbet2 = hypot(_salp0, _calp0 * csig2); if (cbet2 == 0) // I.e., salp0 = 0, csig2 = 0. Break the degeneracy in this case cbet2 = csig2 = tiny_; // tan(alp0) = cos(sig2)*tan(alp2) salp2 = _salp0; calp2 = _calp0 * csig2; // No need to normalize if (outmask & DISTANCE) s12 = arcmode ? _b * ((1 + _aA1m1) * sig12 + AB1) : s12_a12; if (outmask & LONGITUDE) { // tan(omg2) = sin(alp0) * tan(sig2) real somg2 = _salp0 * ssig2, comg2 = csig2, // No need to normalize E = copysign(real(1), _salp0); // east-going? // omg12 = omg2 - omg1 real omg12 = outmask & LONG_UNROLL ? E * (sig12 - (atan2( ssig2, csig2) - atan2( _ssig1, _csig1)) + (atan2(E * somg2, comg2) - atan2(E * _somg1, _comg1))) : atan2(somg2 * _comg1 - comg2 * _somg1, comg2 * _comg1 + somg2 * _somg1); real lam12 = omg12 + _aA3c * ( sig12 + (Geodesic::SinCosSeries(true, ssig2, csig2, _cC3a, nC3_-1) - _bB31)); real lon12 = lam12 / Math::degree(); lon2 = outmask & LONG_UNROLL ? _lon1 + lon12 : Math::AngNormalize(Math::AngNormalize(_lon1) + Math::AngNormalize(lon12)); } if (outmask & LATITUDE) lat2 = Math::atan2d(sbet2, _f1 * cbet2); if (outmask & AZIMUTH) azi2 = Math::atan2d(salp2, calp2); if (outmask & (REDUCEDLENGTH | GEODESICSCALE)) { real B22 = Geodesic::SinCosSeries(true, ssig2, csig2, _cC2a, nC2_), AB2 = (1 + _aA2m1) * (B22 - _bB21), J12 = (_aA1m1 - _aA2m1) * sig12 + (AB1 - AB2); if (outmask & REDUCEDLENGTH) // Add parens around (_csig1 * ssig2) and (_ssig1 * csig2) to ensure // accurate cancellation in the case of coincident points. m12 = _b * ((dn2 * (_csig1 * ssig2) - _dn1 * (_ssig1 * csig2)) - _csig1 * csig2 * J12); if (outmask & GEODESICSCALE) { real t = _k2 * (ssig2 - _ssig1) * (ssig2 + _ssig1) / (_dn1 + dn2); M12 = csig12 + (t * ssig2 - csig2 * J12) * _ssig1 / _dn1; M21 = csig12 - (t * _ssig1 - _csig1 * J12) * ssig2 / dn2; } } if (outmask & AREA) { real B42 = Geodesic::SinCosSeries(false, ssig2, csig2, _cC4a, nC4_); real salp12, calp12; if (_calp0 == 0 || _salp0 == 0) { // alp12 = alp2 - alp1, used in atan2 so no need to normalize salp12 = salp2 * _calp1 - calp2 * _salp1; calp12 = calp2 * _calp1 + salp2 * _salp1; // We used to include here some patch up code that purported to deal // with nearly meridional geodesics properly. However, this turned out // to be wrong once _salp1 = -0 was allowed (via // Geodesic::InverseLine). In fact, the calculation of {s,c}alp12 // was already correct (following the IEEE rules for handling signed // zeros). So the patch up code was unnecessary (as well as // dangerous). } else { // tan(alp) = tan(alp0) * sec(sig) // tan(alp2-alp1) = (tan(alp2) -tan(alp1)) / (tan(alp2)*tan(alp1)+1) // = calp0 * salp0 * (csig1-csig2) / (salp0^2 + calp0^2 * csig1*csig2) // If csig12 > 0, write // csig1 - csig2 = ssig12 * (csig1 * ssig12 / (1 + csig12) + ssig1) // else // csig1 - csig2 = csig1 * (1 - csig12) + ssig12 * ssig1 // No need to normalize salp12 = _calp0 * _salp0 * (csig12 <= 0 ? _csig1 * (1 - csig12) + ssig12 * _ssig1 : ssig12 * (_csig1 * ssig12 / (1 + csig12) + _ssig1)); calp12 = Math::sq(_salp0) + Math::sq(_calp0) * _csig1 * csig2; } S12 = _c2 * atan2(salp12, calp12) + _aA4 * (B42 - _bB41); } return arcmode ? s12_a12 : sig12 / Math::degree(); } void GeodesicLine::SetDistance(real s13) { _s13 = s13; real t; // This will set _a13 to NaN if the GeodesicLine doesn't have the // DISTANCE_IN capability. _a13 = GenPosition(false, _s13, 0u, t, t, t, t, t, t, t, t); } void GeodesicLine::SetArc(real a13) { _a13 = a13; // In case the GeodesicLine doesn't have the DISTANCE capability. _s13 = Math::NaN(); real t; GenPosition(true, _a13, DISTANCE, t, t, t, _s13, t, t, t, t); } void GeodesicLine::GenSetDistance(bool arcmode, real s13_a13) { arcmode ? SetArc(s13_a13) : SetDistance(s13_a13); } } // namespace GeographicLib geosphere/src/Accumulator.h0000644000176200001440000001754514323400747015472 0ustar liggesusers/** * \file Accumulator.hpp * \brief Header for GeographicLib::Accumulator class * * Copyright (c) Charles Karney (2010-2020) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_ACCUMULATOR_HPP) #define GEOGRAPHICLIB_ACCUMULATOR_HPP 1 #include "Constants.h" namespace GeographicLib { /** * \brief An accumulator for sums * * This allows many numbers of floating point type \e T to be added together * with twice the normal precision. Thus if \e T is double, the effective * precision of the sum is 106 bits or about 32 decimal places. * * The implementation follows J. R. Shewchuk, * Adaptive Precision * Floating-Point Arithmetic and Fast Robust Geometric Predicates, * Discrete & Computational Geometry 18(3) 305--363 (1997). * * Approximate timings (summing a vector) * - double: 2ns * - Accumulator: 23ns * * In the documentation of the member functions, \e sum stands for the value * currently held in the accumulator. * * Example of use: * \include example-Accumulator.cpp **********************************************************************/ template class GEOGRAPHICLIB_EXPORT Accumulator { private: // _s + _t accumulators for the sum. T _s, _t; // Same as Math::sum, but requires abs(u) >= abs(v). This isn't currently // used. static T fastsum(T u, T v, T& t) { GEOGRAPHICLIB_VOLATILE T s = u + v; GEOGRAPHICLIB_VOLATILE T vp = s - u; t = v - vp; return s; } void Add(T y) { // Here's Shewchuk's solution... T u; // hold exact sum as [s, t, u] // Accumulate starting at least significant end y = Math::sum(y, _t, u); _s = Math::sum(y, _s, _t); // Start is _s, _t decreasing and non-adjacent. Sum is now (s + t + u) // exactly with s, t, u non-adjacent and in decreasing order (except for // possible zeros). The following code tries to normalize the result. // Ideally, we want _s = round(s+t+u) and _u = round(s+t+u - _s). The // following does an approximate job (and maintains the decreasing // non-adjacent property). Here are two "failures" using 3-bit floats: // // Case 1: _s is not equal to round(s+t+u) -- off by 1 ulp // [12, -1] - 8 -> [4, 0, -1] -> [4, -1] = 3 should be [3, 0] = 3 // // Case 2: _s+_t is not as close to s+t+u as it shold be // [64, 5] + 4 -> [64, 8, 1] -> [64, 8] = 72 (off by 1) // should be [80, -7] = 73 (exact) // // "Fixing" these problems is probably not worth the expense. The // representation inevitably leads to small errors in the accumulated // values. The additional errors illustrated here amount to 1 ulp of the // less significant word during each addition to the Accumulator and an // additional possible error of 1 ulp in the reported sum. // // Incidentally, the "ideal" representation described above is not // canonical, because _s = round(_s + _t) may not be true. For example, // with 3-bit floats: // // [128, 16] + 1 -> [160, -16] -- 160 = round(145). // But [160, 0] - 16 -> [128, 16] -- 128 = round(144). // if (_s == 0) // This implies t == 0, _s = u; // so result is u else _t += u; // otherwise just accumulate u to t. } T Sum(T y) const { Accumulator a(*this); a.Add(y); return a._s; } public: /** * Construct from a \e T. This is not declared explicit, so that you can * write Accumulator a = 5;. * * @param[in] y set \e sum = \e y. **********************************************************************/ Accumulator(T y = T(0)) : _s(y), _t(0) { static_assert(!std::numeric_limits::is_integer, "Accumulator type is not floating point"); } /** * Set the accumulator to a number. * * @param[in] y set \e sum = \e y. **********************************************************************/ Accumulator& operator=(T y) { _s = y; _t = 0; return *this; } /** * Return the value held in the accumulator. * * @return \e sum. **********************************************************************/ T operator()() const { return _s; } /** * Return the result of adding a number to \e sum (but don't change \e * sum). * * @param[in] y the number to be added to the sum. * @return \e sum + \e y. **********************************************************************/ T operator()(T y) const { return Sum(y); } /** * Add a number to the accumulator. * * @param[in] y set \e sum += \e y. **********************************************************************/ Accumulator& operator+=(T y) { Add(y); return *this; } /** * Subtract a number from the accumulator. * * @param[in] y set \e sum -= \e y. **********************************************************************/ Accumulator& operator-=(T y) { Add(-y); return *this; } /** * Multiply accumulator by an integer. To avoid loss of accuracy, use only * integers such that \e n × \e T is exactly representable as a \e T * (i.e., ± powers of two). Use \e n = −1 to negate \e sum. * * @param[in] n set \e sum *= \e n. **********************************************************************/ Accumulator& operator*=(int n) { _s *= n; _t *= n; return *this; } /** * Multiply accumulator by a number. The fma (fused multiply and add) * instruction is used (if available) in order to maintain accuracy. * * @param[in] y set \e sum *= \e y. **********************************************************************/ Accumulator& operator*=(T y) { using std::fma; T d = _s; _s *= y; d = fma(y, d, -_s); // the error in the first multiplication _t = fma(y, _t, d); // add error to the second term return *this; } /** * Reduce accumulator to the range [-y/2, y/2]. * * @param[in] y the modulus. **********************************************************************/ Accumulator& remainder(T y) { using std::remainder; _s = remainder(_s, y); Add(0); // This renormalizes the result. return *this; } /** * Test equality of an Accumulator with a number. **********************************************************************/ bool operator==(T y) const { return _s == y; } /** * Test inequality of an Accumulator with a number. **********************************************************************/ bool operator!=(T y) const { return _s != y; } /** * Less operator on an Accumulator and a number. **********************************************************************/ bool operator<(T y) const { return _s < y; } /** * Less or equal operator on an Accumulator and a number. **********************************************************************/ bool operator<=(T y) const { return _s <= y; } /** * Greater operator on an Accumulator and a number. **********************************************************************/ bool operator>(T y) const { return _s > y; } /** * Greater or equal operator on an Accumulator and a number. **********************************************************************/ bool operator>=(T y) const { return _s >= y; } }; } // namespace GeographicLib #endif // GEOGRAPHICLIB_ACCUMULATOR_HPP geosphere/vignettes/0000755000176200001440000000000014334225370014246 5ustar liggesusersgeosphere/vignettes/geosphere.Rnw0000644000176200001440000004033113472155746016733 0ustar liggesusers\documentclass{article} \usepackage{natbib} \usepackage{graphics} \usepackage{amsmath} \usepackage{indentfirst} \usepackage[utf8]{inputenc} \usepackage{hyperref} \usepackage{hanging} %\VignetteIndexEntry{Introduction to the geosphere package} \SweaveOpts{keep.source=TRUE} \SweaveOpts{png=TRUE, pdf=FALSE} \SweaveOpts{resolution=100} \begin{document} <>= options(keep.source = TRUE, width = 60) foo <- packageDescription("geosphere") @ \title{Introduction to the "geosphere" package \\ (Version \Sexpr{foo$Version})} \author{Robert J. Hijmans} \maketitle \section{Introduction} This vignette describes the R package '\verb@geosphere@'. The package implements spherical trigonometry functions for geographic applications. Many of the functions have applications in navigation, but others are more general, or have no relation to navigation at all. There is a number of functions to compute distance and direction (= bearing, azimuth, course) along great circles (= shortest distance on a sphere, or "as the crow flies") and along rhumb lines (lines of constant bearing). There are also functions that compute distances on a spheroid. Other functions include the computation of the location of an object at a given direction and distance; and the area, perimeter, and centroid of a spherical polygon. Geographic locations must be specified in longitude and latitude (and in that order!) in degrees (i.e., NOT in radians). Degrees are (obviously) in decimal notation. Thus 12 degrees, 10 minutes, 30 seconds = 12 + 10/60 + 30/3600 = 12.175 degrees. The southern and western hemispheres have a negative sign. The default unit of distance is meter; but this can be adjusted by supplying a different radius 'r' to functions. Directions are expressed in degrees (N = 0 and 360, E = 90, S = 180, and W = 270 degrees). If arguments of functions that take several arguments (e.g. points, bearings, radius of the earth), do not have the same length (for vectors) or number of rows (for matrices) the shorter arguments are re-cycled. Many functions in this package are based on formulae provided by Ed Williams (\url{http://www.edwilliams.org/ftp/avsig/avform.txt}, and partly on javascript implementations of these formulae by Chris Veness (\url{http://www.movable-type.co.uk/scripts/latlong.html} ) Most geodesic computations (for a spheroid rather than a sphere) use the GeographicLib by C.F.F. Karney (\url{http://geographiclib.sourceforge.net/}. \section{Great circle distance} There are four different functions to compute distance between two points. These are, in order of increasing complexity of the algorithm, the 'Spherical law of cosines', 'Haversine' (Sinnott, 1984), 'Vincenty Sphere' and 'Vincenty Ellipsoid' (Vincenty, 1975) methods. The first three assume the earth to be a sphere, while the 'Vincenty Ellipsoid' assumes it is an ellipsoid (which is closer to the truth). The results from the first three functions are identical for practical purposes. The Haversine ('half-versed-sine') formula was published by R.W. Sinnott in 1984, although it has been known for much longer. At that time computational precision was lower than today (15 digits precision). With current precision, the spherical law of cosines formula appears to give equally good results down to very small distances. If you want greater accuracy, you could use the distVincentyEllipsoid method. Below the differences between the three spherical methods are illustrated. At very short distances, there are small differences between the 'law of the Cosine' and the other two methods. There are even smaller differences between the 'Haversine' and 'Vincenty Sphere' methods at larger distances. <>= library(geosphere) Lon <- c(1:9/1000, 1:9/100, 1:9/10, 1:90*2) Lat <- c(1:9/1000, 1:9/100, 1:9/10, 1:90) dcos <- distCosine(c(0,0), cbind(Lon, Lat)) dhav <- distHaversine(c(0,0), cbind(Lon, Lat)) dvsp <- distVincentySphere(c(0,0), cbind(Lon, Lat)) par(mfrow=(c(1,2))) plot(log(dcos), dcos-dhav, col='red', ylim=c(-1e-05, 1e-05), xlab="Log 'Law of Cosines' distance (m)", ylab="Law of Cosines minus Haversine distance") plot(log(dhav), dhav-dvsp, col='blue', xlab="Log 'Haversine' distance (m)", ylab="Vincenty Sphere minus Haversine distance") @ The difference with the 'Vincenty Ellipsoid' method is more pronounced. In the example below (using the default WGS83 ellipsoid), the difference is about 0.3% at very small distances, and 0.15% at larger distances. <>= dvse <- distVincentyEllipsoid(c(0,0), cbind(Lon, Lat)) plot(dvsp/1000, (dvsp-dvse)/1000, col='blue', xlab='Vincenty Sphere Distance (km)', ylab="Difference between 'Vincenty Sphere' and 'Vincenty Ellipsoid' methods (km)") @ For the most precise distance computation use the 'distGeo' function. \section{Points on great circles} Points on a great circle are returned by the function 'greatCircle', using two points on the great circle to define it, and an additional argument to indicate how many points should be returned. You can also use greatCircleBearing, and provide starting points and bearing as arguments. gcIntermediate only returns points on the great circle that are on the track of shortest distance between the two points defining the great circle; and midPoint computes the point half-way between the two points. You can use onGreatCircle to test whether a point is on a great circle between two other points. <>= LA <- c(-118.40, 33.95) NY <- c(-73.78, 40.63) data(wrld) plot(wrld, type='l') gc <- greatCircle(LA, NY) lines(gc, lwd=2, col='blue') gci <- gcIntermediate(LA, NY) lines(gci, lwd=4, col='green') points(rbind(LA, NY), col='red', pch=20, cex=2) mp <- midPoint(LA, NY) onGreatCircle(LA,NY, rbind(mp,c(0,0))) points(mp, pch='*', cex=3, col='orange') greatCircleBearing(LA, brng=270, n=10) @ \section{Point at distance and bearing} Function destPoint returns the location of point given a point of origin, and a distance and bearing. Its perhaps obvious use in georeferencing locations of distant sitings. It can also be used to make circular polygons (with a fixed radius, but in longitude/latitude coordinates) <>= destPoint(LA, b=65, d=100000) circle=destPoint(c(0,80), b=1:365, d=1000000) circle2=destPoint(c(0,80), b=1:365, d=500000) circle3=destPoint(c(0,80), b=1:365, d=100000) plot(circle, type='l') polygon(circle, col='blue', border='black', lwd=4) polygon(circle2, col='red', lwd=4, border='orange') polygon(circle3, col='white', lwd=4, border='black') @ \section{Maximum latitude on a great circle} You can use the functions illustrated below to find out what the maximum latitude is that a great circle will reach; at what latitude it crosses a specified longitude; or at what longitude it crosses a specified latitude. From the map below it appears that Clairaut's formula, used in gcMaxLat is not very accurate. Through optimization with function greatCircle, a more accurate value was found. The southern-most point is the antipode (a point at the opposite end of the world) of the northern-most point. <>= ml <- gcMaxLat(LA, NY) lat0 <- gcLat(LA, NY, lon=0) lon0 <- gcLon(LA, NY, lat=0) plot(wrld, type='l') lines(gc, lwd=2, col='blue') points(ml, col='red', pch=20, cex=2) points(cbind(0, lat0), pch=20, cex=2, col='yellow') points(t(rbind(lon0, 0)), pch=20, cex=2, col='green' ) f <- function(lon){gcLat(LA, NY, lon)} opt <- optimize(f, interval=c(-180, 180), maximum=TRUE) points(opt$maximum, opt$objective, pch=20, cex=2, col='dark green' ) anti <- antipode(c(opt$maximum, opt$objective)) points(anti, pch=20, cex=2, col='dark blue' ) @ \section{Great circle intersections} Points of intersection of two great circles can be computed in two ways. We use a second great circle that connects San Francisco with Amsterdam. We first compute where they cross by defining the great circles using two points on it (gcIntersect). After that, we compute the same points using a start point and initial bearing (gcIntersectBearing). The two points where the great circles cross are antipodes. Antipodes are connected with an infinite number of great circles. <>= SF <- c(-122.44, 37.74) AM <- c(4.75, 52.31) gc2 <- greatCircle(AM, SF) plot(wrld, type='l') lines(gc, lwd=2, col='blue') lines(gc2, lwd=2, col='green') int <- gcIntersect(LA, NY, SF, AM) int antipodal(int[,1:2], int[,3:4]) points(rbind(int[,1:2], int[,3:4]), col='red', pch=20, cex=2) bearing1 <- bearing(LA, NY) bearing2 <- bearing(SF, AM) bearing1 bearing2 gcIntersectBearing(LA, bearing1, SF, bearing2) @ \section{Triangulation} Below is triangulation example. We have three locations (NY, LA, MS) and three directions (281, 60, 195) towards a target. Because we are on a sphere, there are two (antipodal) results. We only show one here (by only using int[,1:2]). We compute the centroid from the polygon defined with the three points. To accurately draw a spherical polygon, we can use makePoly. This function inserts intermediate points along the paths between the vertices provided (default is one point every 10 km). <>= MS <- c(-93.26, 44.98) gc1 <- greatCircleBearing(NY, 281) gc2 <- greatCircleBearing(MS, 195) gc3 <- greatCircleBearing(LA, 55) plot(wrld, type='l', xlim=c(-125, -70), ylim=c(20, 60)) lines(gc1, col='green') lines(gc2, col='blue') lines(gc3, col='red') int <- gcIntersectBearing(rbind(NY, NY, MS), c(281, 281, 195), rbind(MS, LA, LA), c(195, 55, 55)) int distm(rbind(int[,1:2], int[,3:4])) int <- int[,1:2] points(int) poly <- rbind(int, int[1,]) centr <- centroid(poly) poly2 <- makePoly(int) polygon(poly2, col='yellow') points(centr, pch='*', col='dark red', cex=2) @ \section{Bearing} Below we first compute the distance and bearing from Los Angeles (LA) to New York (NY). These are then used to compute the point from LA at that distance in that (initial) bearing (direction). Bearing changes continuously when traveling along a Great Circle. The final bearing, when approaching NY, is also given. <>= d <- distCosine(LA, NY) d b <- bearing(LA, NY) b destPoint(LA, b, d) NY finalBearing(LA, NY) @ \section{Getting off-track} What if we went off-course and were flying over Minneapolis (MS)? The closest point on the planned route (p) can be computed with the alongTrackDistance and destPoint functions. The distance from 'p' to MS can be computed with the dist2gc (distance to great circle, or cross-track distance) function. The light green line represents the along-track distance, and the dark green line represents the cross-track distance. <>= atd <- alongTrackDistance(LA, NY, MS) p <- destPoint(LA, b, atd) plot(wrld, type='l', xlim=c(-130,-60), ylim=c(22,52)) lines(gci, col='blue', lwd=2) points(rbind(LA, NY), col='red', pch=20, cex=2) points(MS[1], MS[2], pch=20, col='blue', cex=2) lines(gcIntermediate(LA, p), col='green', lwd=3) lines(gcIntermediate(MS, p), col='dark green', lwd=3) points(p, pch=20, col='red', cex=2) dist2gc(LA, NY, MS) distCosine(p, MS) @ \section{Distance to a polyline} The two function describe above are used in the dist2Line function that computes the shortest distance between a set of points and a set of spherical poly-lines (or polygons). <>= line <- rbind(c(-180,-20), c(-150,-10), c(-140,55), c(10, 0), c(-140,-60)) pnts <- rbind(c(-170,0), c(-75,0), c(-70,-10), c(-80,20), c(-100,-50), c(-100,-60), c(-100,-40), c(-100,-20), c(-100,-10), c(-100,0)) d = dist2Line(pnts, line) plot( makeLine(line), type='l') points(line) points(pnts, col='blue', pch=20) points(d[,2], d[,3], col='red', pch='x', cex=2) for (i in 1:nrow(d)) lines(gcIntermediate(pnts[i,], d[i,2:3], 10), lwd=2, col='green') @ \section{Rhumb lines} Rhumb (from the Spanish word for course, 'rumbo') lines are straight lines on a Mercator projection map (and at most latitudes pretty straight on an equirectangular projection (=unprojected lon/lat) map). They were used in navigation because it is easier to follow a constant compass bearing than to continually adjust direction as is needed to follow a great circle, even though rhumb lines are normally longer than great-circle (orthodrome) routes. Most rhumb lines will gradually spiral towards one of the poles. <>= NP <- c(0, 85) bearing(SF, NP) b <- bearingRhumb(SF, NP) b dc <- distCosine(SF, NP) dr <- distRhumb(SF, NP) dc / dr pr <- destPointRhumb(SF, b, d=round(dr/100) * 1:100) pc <- rbind(SF, gcIntermediate(SF, NP), NP) par(mfrow=c(1,2)) data(wrld) plot(wrld, type='l', xlim=c(-140,10), ylim=c(15,90), main='Equirectangular') lines(pr, col='blue') lines(pc, col='red') data(merc) plot(merc, type='l', xlim=c(-15584729, 1113195), ylim=c(2500000, 22500000), main='Mercator') lines(mercator(pr), col='blue') lines(mercator(pc), col='red') @ \section{Characterizing polygons} The package has functions to compute the area, perimeter, centroid, and 'span' of a spherical polygon. One approach to compute these measures is to project the polygons first. Here we directly compute them based on spherical coordinates (longitude / latitude), except for centroid, which is computed by projecting the data to the Mercator projection (and inversely projecting the result). The function makePoly inserts additional vertices into a spherical polygon such that it can be plotted (perhaps after first projecting it) more correctly in a plane. Vertices are inserted, where necessary, at a specified distance. The function is only beneficial for polygons with large inter-vertex distances (in terms of longitude), particularly at high latitudes. <>= pol <- rbind(c(-120,-20), c(-80,5), c(0, -20), c(-40,-60), c(-120,-20)) areaPolygon(pol) perimeter(pol) centroid(pol) span(pol, fun=max) nicepoly = makePoly(pol) plot(pol, xlab='longitude', ylab='latitude', cex=2, lwd=3, xlim=c(-140, 0)) lines(wrld, col='grey') lines(pol, col='red', lwd=2) lines(nicepoly, col='blue', lwd=2) points(centroid(pol), pch='*', cex=3, col='dark green') text(centroid(pol)-c(0,2.5), 'centroid') legend(-140, -48, c('planar','spherical'), lty=1, lwd=2, col=c('red', 'blue'), title='polygon type') @ \section{Sampling} Random or regular sampling of longitude/latitude values on the globe needs to consider that the globe is spherical. That is, if you would take random points for latitude between -90 and 90 and for longitude between -180 and 180, the density of points would be higher near the poles than near the equator. In contrast, functions 'randomCoordinates' and 'randomCoordinates' return samples that are spatially balanced. <>= plot(wrld, type='l', col='grey') a = randomCoordinates(500) points(a, col='blue', pch=20, cex=0.5) b = regularCoordinates(3) points(b, col='red', pch='x') @ \section{Daylength} You can compute daylenght according to the formula by Forsythe et al. (1995). For any day of the year (an integer between 1 and 365; or a 'Date' object. <>= as.Date(80, origin='2009-12-31') as.Date(172, origin='2009-12-31') plot(0:90, daylength(lat=0:90, doy=1), ylim=c(0,24), type='l', xlab='Latitude', ylab='Daylength', main='Daylength by latitude and day of year', lwd=2) lines(0:90, daylength(lat=0:90, doy=80), col='green', lwd=2) lines(0:90, daylength(lat=0:90, doy=172), col='blue', lwd=2) legend(0,24, c('1','80','172'), lty=1, lwd=2, col=c('black', 'green', 'blue'), title='Day of year') @ \section{References} \begin{hangparas}{3em}{1} \noindent Forsythe, W.C., E.J. Rykiel Jr., R.S. Stahl, H. Wu and R.M. Schoolfield, 1995. A model comparison for daylength as a function of latitude and day of the year. Ecological Modeling 80:87-95. \noindent Sinnott, R.W, 1984. Virtues of the Haversine. Sky and Telescope 68(2): 159 \noindent Vincenty, T. 1975. Direct and inverse solutions of geodesics on the ellipsoid with application of nested equations. Survey Review 23(176): 88-93. Available here: \url{http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf} \end{hangparas} \end{document} geosphere/R/0000755000176200001440000000000014334225313012434 5ustar liggesusersgeosphere/R/centroid.R0000644000176200001440000000333113472155746014404 0ustar liggesusers# Author: Robert J. Hijmans # April 2010 # version 0.1 # license GPL3 # See http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/ .basiccentroid <- function(p) { p2 <- rbind(p[-1,], p[1,]) P <- p[,1] * p2[,2] - p2[,1] * p[,2] area6 <- 6 * sum(P) / 2 x <- sum((p[,1] + p2[,1]) * P) y <- sum((p[,2] + p2[,2]) * P) return(cbind(x, y) / area6 ) } if (!isGeneric("centroid")) { setGeneric("centroid", function(x, ...) standardGeneric("centroid")) } setMethod("centroid", signature(x='data.frame'), function(x) { centroid(as.matrix(x)) }) setMethod("centroid", signature(x='matrix'), function(x) { x <- .pointsToMatrix(x, poly=TRUE) dif1 <- max(x[,1]) - min(x[,1]) rotated <- FALSE if (dif1 > 180) { x2 <- x x2[,1] <- x2[,1]%%(360) - 180 dif1 <- max(x[,1]) - min(x[,1]) dif2 <- max(x2[,1]) - min(x2[,1]) if (dif2 < dif1) { rotated <- TRUE x <- x2 } } x <- mercator(x, r=1) cenM <- .basiccentroid(x) cenG <- mercator(cenM, r=1, inverse=TRUE) if (rotated) { cenG[,1] <- cenG[,1] + 180 cenG[,1] <- .normalizeLonDeg(cenG[,1]) } rownames(cenG) <- NULL return(cenG) } ) setMethod("centroid", signature(x='SpatialPolygons'), function(x) { if ( isTRUE(is.projected(x)) ) { return( coordinates(x)) } x <- x@polygons n <- length(x) res <- matrix(nrow=n, ncol=2) for (i in 1:n) { parts <- length(x[[i]]@Polygons ) parea <- sapply(x[[i]]@Polygons, function(y){ methods::slot(y, "area")} ) hole <- sapply(x[[i]]@Polygons, function(y){ methods::slot(y, "hole")} ) parea[hole] <- -1 j <- which.max(parea) crd <- x[[i]]@Polygons[[j]]@coords res[i,] <- centroid(crd) } return(res) } ) geosphere/R/gcIntersect.R0000644000176200001440000000457613472155746015063 0ustar liggesusers# author Robert Hijmans # October 2009 # version 0.1 # license GPL3 # based on an alogrithm described by Ed Williams # http://www.edwilliams.org/intersect.htm # Not used #gete <- function(lon, lat) { # ex <- cos(lat)*cos(lon) # ey <- -cos(lat)*sin(lon) # ez <- sin(lat) # return(cbind(ex, ey, ez)) #} gcIntersect <- function(p1, p2, p3, p4) { #intersection of two great circles defined by pt1 to pt2 and pt3 to pt4. einv <- function(e) { lat <- atan2(e[,3], sqrt(e[,1]^2 + e[,2]^2)) lon <- atan2(-e[,2], e[,1]) return(cbind(lon, lat)) } eXe5 <- function(lon1, lat1, lon2, lat2) { ex <- sin(lat1-lat2) *sin((lon1+lon2)/2) *cos((lon1-lon2)/2) - sin(lat1+lat2) *cos((lon1+lon2)/2) *sin((lon1-lon2)/2) ey <- sin(lat1-lat2) *cos((lon1+lon2)/2) *cos((lon1-lon2)/2) + sin(lat1+lat2) *sin((lon1+lon2)/2) *sin((lon1-lon2)/2) ez <- cos(lat1)*cos(lat2)*sin(lon1-lon2) return( cbind(ex, ey, ez) ) } eXe3 <- function(e1, e2) { x <- e1[,2] * e2[,3] -e2[,2] *e1[,3] y <- e1[,3] *e2[,1] -e2[,3] *e1[,1] z <- e1[,1] *e2[,2] -e1[,2] *e2[,1] return(cbind(x,y,z)) } eSQRT <- function(e) { return(sqrt(e[,1]^2 + e[,2]^2 + e[,3]^2)) } p1 <- .pointsToMatrix(p1) p2 <- .pointsToMatrix(p2) p3 <- .pointsToMatrix(p3) p4 <- .pointsToMatrix(p4) p1 <- cbind(p1[,1], p1[,2], p2[,1], p2[,2]) p3 <- cbind(p3[,1], p3[,2], p4[,1], p4[,2]) p <- cbind(p1[,1], p1[,2], p1[,3], p1[,4], p3[,1], p3[,2], p3[,3], p3[,4]) p1 <- p[,1:2,drop=FALSE] p2 <- p[,3:4,drop=FALSE] p3 <- p[,5:6,drop=FALSE] p4 <- p[,7:8,drop=FALSE] res <- matrix(NA, nrow=nrow(p1), ncol=4) colnames(res) <- c('lon1', 'lat1', 'lon2', 'lat2') keep <- ! antipodal(p1, p2) | antipodal(p3, p4) keep <- keep & ! apply(p1 == p2, 1, sum) == 2 if (sum(keep) == 0) { return(res) } toRad <- pi / 180 p1 <- p1[keep, , drop=FALSE] * toRad p2 <- p2[keep, , drop=FALSE] * toRad p3 <- p3[keep, , drop=FALSE] * toRad p4 <- p4[keep, , drop=FALSE] * toRad e1Xe2 <- eXe5(p1[,1], p1[,2], p2[,1], p2[,2]) e3Xe4 <- eXe5(p3[,1], p3[,2], p4[,1], p4[,2]) ea <- e1Xe2 / eSQRT(e1Xe2) eb <- e3Xe4 / eSQRT(e3Xe4) eaXeb <- eXe3(ea, eb) ll <- einv(eaXeb) ll2 <- cbind(ll[,1] + pi, -ll[,2]) pts <- cbind(ll, ll2) pts[,1] <- .normalizeLonRad(pts[,1]) pts[,3] <- .normalizeLonRad(pts[,3]) res[keep,] <- pts / toRad return(res) } geosphere/R/greatCircle.R0000644000176200001440000000220413472155746015017 0ustar liggesusers# author Robert Hijmans # October 2009 # version 0.1 # license GPL greatCircle <- function(p1, p2, n=360, sp=FALSE) { p1 <- .pointsToMatrix(p1) p2 <- .pointsToMatrix(p2) p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2], n) p1 <- p[,1:2] p2 <- p[,3:4] n <- pmax(round(p[,5]), 1) if (nrow(p) == 1) { lon <- (1:n * 360 / n) - 180 lat <- gcLat(p1, p2, lon) res <- cbind(lon,lat) if (sp) { lat <- gcLat(p1, p2, 180) res <- list(rbind(cbind(-180, lat), res)) res <- SpatialLines( list( Lines( list( Line (res)), ID=as.character(1)) ), CRS("+proj=longlat +ellps=WGS84")) } } else { res <- list() for (i in 1:nrow(p1)) { lon <- (1:n[i] * 360 / n[i]) - 180 lat <- gcLat(p1[i,], p2[i,], lon) res[[i]] <- cbind(lon, lat) } if (sp) { for (i in 1:length(res)) { lat <- gcLat(p1[i,], p2[i,], 180) res[[i]] <- rbind(cbind(-180, lat), res[[i]]) res[[i]] <- Lines( list( Line (res[[i]])), ID=as.character(i)) } res <- SpatialLines(res, CRS("+proj=longlat +ellps=WGS84")) } } return(res) } #greatCircle(rbind(cbind(5,52), cbind(5,15)), c(-120,37), n=12) geosphere/R/sampleAlong.R0000644000176200001440000000464113472155746015044 0ustar liggesusers# Based on code by Barry Rowlingson #http://r-sig-geo.2731867.n2.nabble.com/how-to-generate-perpendicular-transects-along-a-line-feature-td7583710.html # Some adaptations by Robert Hijmans # January 2016 # version 0.1 # License GPL3 .evenspace <- function(xy, sep, start=0, size, direction=FALSE){ dx <- c(0,diff(xy[,1])) dy <- c(0,diff(xy[,2])) dseg <- sqrt(dx^2+dy^2) dtotal <- cumsum(dseg) linelength <- sum(dseg) pos <- seq(start,linelength, by=sep) whichseg <- unlist(lapply(pos, function(x){sum(dtotal<=x)})) x0 <- xy[whichseg,1] y0 <- xy[whichseg,2] x1 <- xy[whichseg+1,1] y1 <- xy[whichseg+1,2] dtotal <- dtotal[whichseg] further <- pos - dtotal dseg <- dseg[whichseg+1] f <- further/dseg x <- x0 + f * (x1-x0) y <- y0 + f * (y1-y0) r <- data.frame(x, y) # if (direction) { # r$direction <- atan2(y0-y1,x0-x1) # } r } .transect <- function(pts, len){ pts$thetaT = pts$theta+pi/2 dx <- len*cos(pts$thetaT) dy <- len*sin(pts$thetaT) data.frame(x0 = pts$x + dx, y0 = pts$y + dy, x1 = pts$x - dx, y1 = pts$y -dy) } .sampleAlong <- function(x, interval) { if (inherits(x, 'SpatialPolygons')) { line <- methods::as(line, 'SpatialLines') } if (inherits(x, 'SpatialLines')) { requireNamespace('raster') x <- raster::geom(x) allpts <- NULL for (p in unique(x[, 'cump'])) { y <- x[x[, 'cump']==p, c('x', 'y')] pts <- .evenspace(y, interval, direction=FALSE) allpts <- rbind(allpts, pts) } return(allpts) } else { x <- .pointsToMatrix(x) .evenspace(x, interval, direction=FALSE) } } .sampleAlongPerpendicular <- function(x, interval, pdist, np=1 ) { if (inherits(x, 'SpatialPolygons')) { line <- methods::as(line, 'SpatialLines') } if (inherits(x, 'SpatialLines')) { requireNamespace('raster') x <- raster::geom(x) allpts <- NULL for (p in unique(x[, 'cump'])) { y <- x[x[, 'cump']==p, c('x', 'y')] tspts <- .evenspace(y, interval) pts <- NULL for (i in 1:np) { pts1 <- .transect(tspts, i * pdist) pts <- cbind(pts, pts1) } allpts <- rbind(allpts, pts) } return(allpts) } else { x <- .pointsToMatrix(x) y <- .evenspace(x, interval) pts <- NULL for (i in 1:np) { pts1 <- .transect(y, i * pdist) pts <- cbind(pts, pts1) } return(pts) } } geosphere/R/distVincentySphere.R0000644000176200001440000000150213472155746016425 0ustar liggesusers# Author: Robert J. Hijmans # Date : June 2008 # Version 0.8 (taken from Raster package) # Licence GPL v3 # Vincenty formula for a sphere # http://en.wikipedia.org/wiki/Great_circle_distance distVincentySphere <- function(p1, p2, r=6378137) { toRad <- pi / 180 p1 <- .pointsToMatrix(p1) * toRad if (missing(p2)) { p2 <- p1[-1, ,drop=FALSE] p1 <- p1[-nrow(p1), ,drop=FALSE] } else { p2 <- .pointsToMatrix(p2) * toRad } p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2], as.vector(r)) lon1 <- p[,1] lat1 <- p[,2] lon2 <- p[,3] lat2 <- p[,4] x <- sqrt((cos(lat2) * sin(lon1-lon2))^2 + (cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon1-lon2))^2) y <- sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon1-lon2) dist <- p[,5] * atan2(x, y) return ( as.vector(dist )) } geosphere/R/dist2gc.R0000644000176200001440000000130613472155746014134 0ustar liggesusers# based on code by Ed Williams # Licence: GPL # http://www.edwilliams.org/avform.htm#XTE # Port to R by Robert Hijmans # October 2009 # version 0.1 # license GPL3 dist2gc <- function(p1, p2, p3, r=6378137, sign=FALSE) { toRad <- pi / 180 p1 <- .pointsToMatrix(p1) p2 <- .pointsToMatrix(p2) p3 <- .pointsToMatrix(p3) r <- as.vector(r) p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2], p3[,1], p3[,2], r) p1 <- p[,1:2] p2 <- p[,3:4] p3 <- p[,5:6] r <- p[,7] tc <- bearing(p1, p2, a=r, f=0) * toRad tcp <- bearing(p1, p3, a=r, f=0) * toRad dp <- distCosine(p1, p3, r=1) xtr <- (asin(sin(tcp-tc) * sin(dp)) * r) xtr <- as.vector(xtr) if (!sign) xtr <- abs(xtr) xtr } geosphere/R/distHaversine.R0000644000176200001440000000500014032771416015367 0ustar liggesusers# author of original JavaScript code: Chris Vennes # (c) 2002-2009 Chris Veness # http://www.movable-type.co.uk/scripts/latlong.html # Licence: LGPL, without any warranty express or implied # Port to R by Robert Hijmans # October 2009 # version 0.1 # license GPL3 distHaversine <- function(p1, p2, r=6378137) { #* Haversine formula to calculate distance between two points specified by #* from: Haversine formula - R.W. Sinnott, "Virtues of the Haversine", #* Sky and Telescope, vol 68, no 2, 1984 #* http:#//www.census.gov/cgi-bin/geo/gisfaq?Q5.1 # source http://www.movable-type.co.uk/scripts/latlong.html # (c) 2002-2009 Chris Veness toRad <- pi / 180 p1 <- .pointsToMatrix(p1) * toRad if (missing(p2)) { p2 <- p1[-1, ,drop=FALSE] p1 <- p1[-nrow(p1), ,drop=FALSE] } else { p2 <- .pointsToMatrix(p2) * toRad } p = cbind(p1[,1], p1[,2], p2[,1], p2[,2], as.vector(r)) dLat <- p[,4]-p[,2] dLon <- p[,3]-p[,1] a <- (sin(dLat/2))^2 + cos(p[,2]) * cos(p[,4]) * (sin(dLon/2))^2 # to avoid values of 'a' that are a sliver above 1 # which may occur at antipodes # https://stackoverflow.com/questions/45889616/why-does-disthaversine-return-nan-for-some-pairs-of-coordinates# a <- pmin(a, 1) dist <- 2 * atan2(sqrt(a), sqrt(1-a)) * p[,5] return( as.vector(dist)) } # lon1 <- p[,1] # lat1 <- p[,2] # lon2 <- p[,3] # lat2 <- p[,4] # r <- p[,5] # dLat <- (lat2-lat1) # dLon <- (lon2-lon1) # a <- sin(dLat/2) * sin(dLat/2) + cos(lat1) * cos(lat2) * sin(dLon/2) * sin(dLon/2) # dist <- 2 * atan2(sqrt(a), sqrt(1-a)) * r .distHaversine2 <- function(p1, p2, r=6378137) { ## following wikipedia toRad <- pi / 180 p1 <- .pointsToMatrix(p1) * toRad if (missing(p2)) { p2 <- p1[-1, ,drop=FALSE] p1 <- p1[-nrow(p1), ,drop=FALSE] } else { p2 <- .pointsToMatrix(p2) * toRad } p = cbind(p1[,1], p1[,2], p2[,1], p2[,2], as.vector(r)) dLat <- p[,4]-p[,2] dLon <- p[,3]-p[,1] a <- (sin(dLat/2))^2 + cos(p[,2]) * cos(p[,4]) * (sin(dLon/2))^2 a <- pmin(a, 1) dist <- 2 * r * asin(sqrt(a)) return( as.vector(dist)) } # from Thierry de Meeus .distHaversine3 <- function(p1, p2, r=6378137) { toRad <- pi / 180 p1 <- .pointsToMatrix(p1) * toRad if (missing(p2)) { p2 <- p1[-1, ,drop=FALSE] p1 <- p1[-nrow(p1), ,drop=FALSE] } else { p2 <- .pointsToMatrix(p2) * toRad } p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2], as.vector(r)) r*(pi/2-asin(sin((p[,4]))*sin((p[,2]))+cos((p[,3])-(p[,1]))*cos((p[,4]))*cos((p[,2])))) } geosphere/R/span.R0000644000176200001440000000443713472155746013546 0ustar liggesusers# Author: Robert J. Hijmans, r.hijmans@gmail.com # Date : April 2010 # Version 1 # Licence GPL v3 if (!isGeneric("span")) { setGeneric("span", function(x, ...) standardGeneric("span")) } setMethod("span", signature(x='matrix'), function(x, nbands='fixed', n=100, res=0.1, fun, r=6378137, ...) { dif1 <- max(x[,1]) - min(x[,1]) rotated <- FALSE if (dif1 > 180) { x2 <- x x2[,1] <- x2[,1] %% 360 - 180 dif1 <- max(x[,1]) - min(x[,1]) dif2 <- max(x2[,1]) - min(x2[,1]) if (dif2 < dif1) { rotated <- TRUE x <- x2 } } x <- SpatialPolygons(list(Polygons(list(Polygon(x)), 1))) if (missing(fun)) { x <- span(x, nbands=nbands, n=n, res=res, ...) } else { x <- span(x, nbands=nbands, n=n, res=res, fun=fun, ...) } if (rotated & missing(fun)) { x$longitude = x$longitude + 180 } return(x) } ) setMethod("span", signature(x='SpatialPolygons'), function(x, nbands='fixed', n=100, res=0.1, fun, ...) { if (!requireNamespace('raster')) {stop('you need to install the "raster" package to use this function')} if (! nbands %in% c('fixed', 'variable')) { stop('bandwidth should be "fixed" or "variable"') } if (nbands == 'fixed') { n = max(n, 1) } else { if (res <= 0) { stop('res should be larger than zero') } } npol <- length(x@polygons) lonspan <- list() latspan <- list() lon <- list() lat <- list() for (i in 1:npol) { pp <- x[i,] rs <- raster::raster(pp) if (nbands == 'fixed') { dim(rs) <- c(n, n) } else { raster::res(rs) <- res } latitude <- raster::yFromRow(rs, 1:nrow(rs)) longitude <- raster::xFromCol(rs, 1:ncol(rs)) xd <- distGeo(cbind(0,latitude), cbind(raster::xres(rs),latitude), ...) yd <- distGeo(cbind(0,0), cbind(0,raster::yres(rs)), ...) rs <- raster::rasterize(pp, rs, silent=TRUE) rs <- raster::getValues(rs, format='matrix') latspan[[i]] <- as.vector(apply(rs, 1, sum, na.rm=TRUE) * yd) lonspan[[i]] <- as.vector(apply(rs, 2, sum, na.rm=TRUE) * xd) lat[[i]] <- latitude lon[[i]] <- longitude } if (! missing(fun)) { lon = sapply(lonspan, fun) lat = sapply(latspan, fun) return(cbind(lon, lat)) } else { return(c(lonspan=lonspan, latspan=latspan, longitude=lon, latitude=lat)) } } ) geosphere/R/destPoint.R0000644000176200001440000000127014161534117014533 0ustar liggesusers# Author: Robert J. Hijmans # Date : May 2015 # Licence GPL v3 destPoint <- function(p, b, d, a=6378137, f=1/298.257223563, ...) { # calculate destination point given start point, initial bearing (deg) and distance (m) r <- list(...)$r if (!is.null(r)) { # for backwards compatibility return( .old_destPoint(p, b, d, r=r) ) } b <- as.vector(b) d <- as.vector(d) p <- .pointsToMatrix(p) p <- cbind(p[,1], p[,2], b, d) r <- .geodesic(as.double(p[,1]), as.double(p[,2]), as.double(p[,3]), as.double(p[,4]), as.double(a), as.double(f)) r <- matrix(r, ncol=3, byrow=TRUE) colnames(r) <- c('lon', 'lat', 'finalbearing') return(r[, 1:2, drop=FALSE]) } geosphere/R/finalBearing.R0000644000176200001440000000111014161534151015132 0ustar liggesusers# Robert Hijmans # October 2009 # version 0.1 # Licence: GPL3 finalBearing <- function(p1, p2, a=6378137, f=1/298.257223563, sphere=FALSE) { if (sphere) { # for backwards compatibility return(.old_bearing(p2, p1) ) } p1 <- .pointsToMatrix(p1) p2 <- .pointsToMatrix(p2) p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2]) r <- .inversegeodesic(as.double(p[,1]), as.double(p[,2]), as.double(p[,3]), as.double(p[,4]), as.double(a[1]), as.double(f[1])) r <- matrix(r, ncol=3, byrow=TRUE) # colnames(r) <- c('lon', 'lat', 'finalbearing') return(r[, 3]) } geosphere/R/alongTrack.R0000644000176200001440000000155313472155746014666 0ustar liggesusers# based on code by Ed Williams # licence GPL # http://www.edwilliams.org/avform.htm#XTE # Port to R by Robert Hijmans # October 2009 # version 0.1 # license GPL3 alongTrackDistance <- function(p1, p2, p3, r=6378137) { toRad <- pi / 180 p1 <- .pointsToMatrix(p1) p2 <- .pointsToMatrix(p2) p3 <- .pointsToMatrix(p3) p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2], p3[,1], p3[,2], as.vector(r)) p1 <- p[,1:2,drop=FALSE] p2 <- p[,3:4,drop=FALSE] p3 <- p[,5:6,drop=FALSE] r = p[,7] tc <- bearing(p1, p2) * toRad tcp <- bearing(p1, p3) * toRad dp <- distCosine(p1, p3, r=1) xtr <- asin(sin(tcp-tc) * sin(dp)) # +1/-1 for ahead/behind [lat1,lon1] bearing <- sign(cos(tc - tcp)) dist <- bearing * acos(cos(dp) / cos(xtr)) * r if (is.vector(dist)) { dist <- matrix(dist) } colnames(dist) <- 'distance' return(abs(dist)) } geosphere/R/destPointRhumb.R0000644000176200001440000000235313472155746015547 0ustar liggesusers# based on JavaScript code by Chris Vennes # (c) 2002-2009 Chris Veness # http://www.movable-type.co.uk/scripts/latlong.html # Licence: LGPL, without any warranty express or implied # see http://www.edwilliams.org/avform.htm#Rhumb # for the original formulae # Robert Hijmans # October 2009 # version 0.1 # license GPL3 destPointRhumb <- function(p, b, d, r=6378137) { toRad <- pi / 180 b <- as.vector(b) d <- as.vector(d) r <- as.vector(r) p <- .pointsToMatrix(p) p <- cbind(p[,1], p[,2], b, d, r) r <- p[,5] d <- p[,4] / r #angular distance in radians b <- p[,3] * toRad lon1 <- p[,1] * toRad lat1 <- p[,2] lat1[lat1==90|lat1==-90] <- NA lat1 <- lat1 * toRad lat2 <- lat1 + d * cos(b) dLat <- lat2-lat1 dPhi <- log( tan(lat2/2 + pi/4) / tan(lat1/2 + pi/4) ) i <- abs(dLat) > 1e-10 q <- vector(length=length(i)) q[i] <- dLat[i]/dPhi[i] q[!i] <- cos(lat1[!i]) dLon <- d * sin(b) / q # check for points past the pole../ i <- (abs(lat2) > pi/2) & lat2 > 0 lat2[i] <- pi-lat2[i] i <- (abs(lat2) > pi/2) & lat2 <= 0 lat2[i] <- (pi-lat2[i]) lon2 <- (lon1+dLon+pi)%%(2*pi) - pi res <- cbind(lon2, lat2) / toRad colnames(res) <- c('lon', 'lat') return(res) } geosphere/R/antipodal.R0000644000176200001440000000126314161435516014542 0ustar liggesusers# Author: Robert J. Hijmans # October 2009 # version 1.0 # license GPL3 antipodal <- function(p1, p2, tol=1e-9) { p1 <- .pointsToMatrix(p1) p2 <- .pointsToMatrix(p2) p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2]) p[,c(1,3)] <- .normalizeLonDeg(p[,c(1,3)]) diflon <- abs(p[,1] - p[,3]) diflat <- abs(p[,2] + p[,4]) ## FIX by Gareth Davies # (diflat < tol) & (diflon > (180 - tol)) ## FIX by Jonathan Rynd # (diflat < tol) & (abs(diflon%%360 - 180) < tol) (diflat < tol) & ((cos(p[,2] * pi/180) * abs(diflon%%360 - 180)) < tol) } antipode <- function(p) { p <- .pointsToMatrix(p) p[,1] <- .normalizeLonDeg(p[,1] + 180) p[,2] <- -p[,2] return( p ) } geosphere/R/gcLat.R0000644000176200001440000000201413472155746013624 0ustar liggesusers# author Robert Hijmans # October 2009 # version 0.1 # license GPL gcLat <- function(p1, p2, lon) { # Intermediate points on a great circle # source: http://www.edwilliams.org/avform.htm toRad <- pi / 180 d <- distCosine(p1, p2) p1 <- .pointsToMatrix(p1) p2 <- .pointsToMatrix(p2) p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2], as.vector(lon)) p1 <- p[,1:2,drop=FALSE] p2 <- p[,3:4,drop=FALSE] lon <- p[,5] res <- rep(NA, nrow(p)) notanti <- ! antipodal(p1, p2) lon1 <- p1[,1] * toRad lat1 <- p1[,2] * toRad lon2 <- p2[,1] * toRad lat2 <- p2[,2] * toRad lon <- lon * toRad # cannot compute this for a meridian notmeridians <- ! sin(lon1-lon2)==0 keep <- notanti & notmeridians if (sum(keep) == 0) { return(res) } lon1 <- lon1[keep] lat1 <- lat1[keep] lon2 <- lon2[keep] lat2 <- lat2[keep] lon <- lon[keep] res[keep] <- atan((sin(lat1)*cos(lat2)*sin(lon-lon2) -sin(lat2)*cos(lat1)*sin(lon-lon1))/(cos(lat1)*cos(lat2)*sin(lon1-lon2))) return(res / toRad) } geosphere/R/makePoly.R0000644000176200001440000000740713472155746014366 0ustar liggesusers# author Robert Hijmans # April 2010 # version 0.1 # license GPL .makeSinglePoly <- function(p, interval=10000, ...) { res <- p[1,] for (i in 1:(nrow(p)-1)) { if (! isTRUE( all.equal(p[i,], p[i+1,]) )) { d <- distGeo(p[i,], p[i+1,], ...) n <- floor(d / interval) if (n > 0) { pts <- gcIntermediate(p[i,],p[i+1,], n) pts <- rbind(p[i,], pts, p[i+1,]) res <- rbind(res, pts, p[i+1,]) } else { res <- rbind(res, p[i+1,]) } } } if (nrow(res) < 3) stop('cannot make a valid polygon') return(res) } .makeSingleLine <- function(p, interval=10000, ...) { res <- p[1,] for (i in 1:(nrow(p)-1)) { if (! isTRUE( all.equal(p[i,], p[i+1,]) )) { d <- distGeo(p[i,], p[i+1,], ...) n <- floor(d / interval) if (n > 0) { pts <- gcIntermediate(p[i,],p[i+1,], n) pts <- rbind(p[i,], pts, p[i+1,]) res <- rbind(res, pts, p[i+1,]) } else { res <- rbind(res, p[i+1,]) } } } if (nrow(res) < 2) stop('cannot make a valid line') return(res) } makePoly <- function(p, interval=10000, sp=FALSE, ...) { if (inherits(p, 'SpatialPolygons')) { test <- !is.projected(p) if (! isTRUE (test) ) { if (is.na(test)) { warning('Coordinate reference system of SpatialPolygons object is not set. Assuming it is degrees (longitude/latitude)!') } else { stop('Points are projected. They should be in degrees (longitude/latitude)') } # or rather transform them ....? } x <- p@polygons n <- length(x) polys = list() for (i in 1:n) { parts <- length(x[[i]]@Polygons ) partlist <- list() for (j in 1:parts) { crd <- x[[i]]@Polygons[[j]]@coords crd <- .makeSinglePoly(crd, interval=interval, ...) partlist[[j]] <- Polygon(crd) } polys[[i]] <- Polygons(partlist, i) } polys <- SpatialPolygons(polys) if (inherits(p, 'SpatialPolygonsDataFrame')) { rownames(p@data) <- 1:nrow(p@data) polys <- SpatialPolygonsDataFrame(polys, p@data) } polys@proj4string <- p@proj4string return(polys) } else { p <- .pointsToMatrix(p) if (nrow(p) < 3) { stop('cannot make a polygon (insufficent number of vertices)') } if (! isTRUE(all.equal(p[1,], p[nrow(p),]))) { p <- rbind(p, p[1,]) } res <- .makeSinglePoly(p, interval=interval, ...) if (sp) { res <- SpatialPolygons(list(Polygons(list(Polygon(res)), 1))) res@proj4string <- CRS("+proj=longlat +datum=WGS84") } return(res) } } makeLine <- function(p, interval=10000, sp=FALSE, ...) { if (inherits(p, 'SpatialLines')) { test <- !is.projected(p) if (! isTRUE (test) ) { if (is.na(test)) { warning('Coordinate reference system of SpatialPolygons object is not set. Assuming it is degrees (longitude/latitude)!') } else { stop('Points are projected. They should be in degrees (longitude/latitude)') } # or rather transform them ....? } x = p@lines n = length(x) lines = list() for (i in 1:n) { parts = length(x[[i]]@Lines ) partlist = list() for (j in 1:parts) { crd = x[[i]]@Lines[[j]]@coords crd = .makeSingleLine(crd, interval=interval, ...) partlist[[j]] = Line(crd) } lines[[i]] = Lines(partlist, i) } lines <- SpatialLines(lines) if (inherits(p, 'SpatialLinesDataFrame')) { lines <- SpatialLinesDataFrame(lines, p@data) } lines@proj4string <- p@proj4string return(lines) } else { p <- .pointsToMatrix(p) if (nrow(p) < 3) { stop('cannot make a polygon (insufficent number of vertices)') } res <- .makeSingleLine(p, interval=interval, ...) if (sp) { res <- SpatialLines(list(Lines(list(Line(res)), 1))) res@proj4string <- CRS("+proj=longlat +datum=WGS84") } return(res) } } geosphere/R/onGreatCircle.R0000644000176200001440000000166313472155746015324 0ustar liggesusers# Author: Robert J. Hijmans # based on Dr. Rick's advice at: # http://mathforum.org/library/drmath/view/66114.html # August 2010 # version 1 # license GPL3 onGreatCircle <- function(p1, p2, p3, tol=0.0001) { # is p3 an intermediate points on a great circle defined by p1 and p2? toRad <- pi / 180 p1 <- .pointsToMatrix(p1) p2 <- .pointsToMatrix(p2) p3 <- .pointsToMatrix(p3) p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2], p3[,1], p3[,2]) p1 <- p[,1:2, drop=FALSE] * toRad p2 <- p[,3:4, drop=FALSE] * toRad p3 <- p[,5:6, drop=FALSE] * toRad lon1 <- p1[,1] lat1 <- p1[,2] lon2 <- p2[,1] lat2 <- p2[,2] lon <- p3[,1] lat <- p3[,2] newlat <- atan((sin(lat1)*cos(lat2)*sin(lon-lon2) - sin(lat2)*cos(lat1)*sin(lon-lon1)) / (cos(lat1)*cos(lat2)*sin(lon1-lon2))) res <- abs(newlat - lat) < tol meridian <- p1[,1] == p2[,1] & p1[,1] == p3[,1] res[meridian] <- TRUE return(as.vector(res)) } geosphere/R/RcppExports.R0000644000176200001440000000123314166423400015047 0ustar liggesusers# Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 .geodesic <- function(lon1, lat1, azi1, s12, a, f) { .Call(`_geosphere_geodesic`, lon1, lat1, azi1, s12, a, f) } .inversegeodesic <- function(lon1, lat1, lon2, lat2, a, f) { .Call(`_geosphere_inversegeodesic`, lon1, lat1, lon2, lat2, a, f) } .polygonarea <- function(lon, lat, a, f) { .Call(`_geosphere_polygonarea`, lon, lat, a, f) } .geod_intermediate <- function(lon1, lat1, lon2, lat2, n, distance, arc, a, f) { .Call(`_geosphere_geodesic_nodes`, lon1, lat1, lon2, lat2, n, distance, arc, a, f) } geosphere/R/geomedian.R0000644000176200001440000000310313472155746014522 0ustar liggesusers# Author: Robert J. Hijmans # March 2012 # version 1 # license GPL3 .geomedian <- function(xy, w=NULL) { xy <- .pointsToMatrix(xy) if (is.null(w)) { w <- 1 } else if (length(w) != nrow(xy)) { stop('length of weights not correct. It should be: ', nrow(xy)) } w <- w / sum(w) xyw <- cbind(xy, w) xy <- stats::na.omit(xyw) xy <- xyw[,1:2] w <- xyw[,3] est <- geomean(xy, w) fun <- function(p) { if (p[2] > 90 | p[2] < -90) { return(Inf) } else { p[1] = (p[1] + 180) %% 360 - 180 sum( distCosine(xy, p) * w) } } opt <- stats::optim(geomean(xy), fun) if (!is.null(opt$message)) { warning(opt$message) } return(opt$par) } ..geomedian_ndcor <- function(xy, w=NULL, threshold=100, maxiter=100) { requireNamespace('raster') if (inherits(xy, 'SpatialPolygons') | inherits(xy, 'SpatialPoints')) { stopifnot(raster::isLonLat(xy)) xy <- coordinates(xy) } if (is.null(w)) { w <- 1 } else if (length(w) != nrow(xy)) { stop('length of weights not correct. It should be: ', nrow(xy)) } w <- w / sum(w) xyw <- cbind(xy, w) xy <- stats::na.omit(xyw) xy <- xyw[,1:2] w <- xyw[,3] est <- geomean(xy, w) estold <- est iter = 1 while (TRUE) { d <- distCosine(xy, est) x <- sum(w*xy[,1] / d) / sum(w/d) y <- sum(w*xy[,2] / d) / sum(w/d) est <- cbind(x,y) dif <- distCosine(est, estold) if (dif < threshold) { return(est) } else if (iter > maxiter) { warning('maxiter reached') return(est) } estold <- est iter <- iter + 1 } } geosphere/R/distCosines.R0000644000176200001440000000242313472155746015065 0ustar liggesusers# Author: Robert J. Hijmans # Date : June 2008 # Licence GPL v3 # distance based on law of cosines # http://en.wikipedia.org/wiki/Great_circle_distance distCosine <- function(p1, p2, r=6378137) { p1 <- .pointsToMatrix(p1) if (missing(p2)) { p2 <- p1[-1, ,drop=FALSE] p1 <- p1[-nrow(p1), ,drop=FALSE] } else { p2 <- .pointsToMatrix(p2) } pp <- cbind(p1[,1], p1[,2], p2[,1], p2[,2], as.vector(r)) # remove identical points to avoid errors due to floating point math # problem reported by Bill Monahan i <- rowSums(abs(pp[, 1:2, drop=FALSE] - pp[, 3:4, drop=FALSE]) < .Machine$double.eps ^ 0.5) < 2 p <- pp[i, ,drop=FALSE] r <- rep(0, nrow(pp)) if (nrow(p) > 0) { p[,1:4] <- p[,1:4] * pi / 180 r[i] <- acos( sin(p[,2]) * sin(p[,4]) + cos(p[,2]) * cos(p[,4]) * cos(p[,1]-p[,3]) ) * p[,5] } r } # m = matrix(c(-58.65222,-19.65154,-52.985550,-1.484869, -69.652220, 7.348464, -69.652220,7.348464, -1,1 ,-1,1, -1,1.1,-1,1.1, -1,1.2,-1,1.2, -116.65220,72.01513,-121.48560,53.34847), ncol=4, byrow=T) # distCosine(m[,1:2], m[,3:4]) # n <- nrow(p) # d <- vector("double", n) # d <- .C('distance', as.integer(n), as.double(p[,1]), as.double(p[,2]), as.double(p[,3]), as.double(p[,4]), as.double(p[,5]), as.integer(1), d)[[8]] # return(d) geosphere/R/distVincentyEllipsoid.R0000644000176200001440000000573513472155746017137 0ustar liggesusers# author of original JavaScript code: Chris Vennes # (c) 2002-2009 Chris Veness # http://www.movable-type.co.uk/scripts/latlong.html # Licence: LGPL, without any warranty express or implied # Port to R by Robert Hijmans # October 2009 # version 0.1 # license GPL3 distVincentyEllipsoid <- function(p1, p2, a=6378137, b=6356752.3142, f=1/298.257223563) { #/* Vincenty Inverse Solution of Geodesics on the Ellipsoid (c) Chris Veness 2002-2009 #*/ #* Calculate geodesic distance (in m) between two points specified by latitude/longitude #* (in numeric degrees) using Vincenty inverse formula for ellipsoids # source http://www.movable-type.co.uk/scripts/latlong-vincenty.html # (c) 2002-2009 Chris Veness toRad <- pi / 180 p1 <- .pointsToMatrix(p1) * toRad if (missing(p2)) { p2 <- p1[-1, ,drop=FALSE] p1 <- p1[-nrow(p1), ,drop=FALSE] } else { p2 <- .pointsToMatrix(p2) * toRad } p = cbind(p1[,1], p1[,2], p2[,1], p2[,2], as.vector(a), as.vector(b), as.vector(f)) p1 = p[,1:2,drop=FALSE] p2 = p[,3:4,drop=FALSE] res <- vector(length=nrow(p1)) for (i in 1:dim(p1)[1]) { if ( any( is.na( c(p1[i,], p2[i,])))) { #improvement by George Wang and Sebastian P. Luque res[i] <- NA } else if (isTRUE(all.equal(p1[i,], p2[i,]))) { res[i] <- 0 } else { lon1 <- p1[i,1] lat1 <- p1[i,2] lon2 <- p2[i,1] lat2 <- p2[i,2] a = p[i,5] b = p[i,6] f = p[i,7] L <- (lon2-lon1) U1 <- atan((1-f) * tan(lat1)) U2 <- atan((1-f) * tan(lat2)) sinU1 <- sin(U1) cosU1 <- cos(U1) sinU2 <- sin(U2) cosU2 <- cos(U2) lambda <- L iterLimit <- 100 continue <- TRUE while (continue) { sinLambda <- sin(lambda) cosLambda <- cos(lambda) sinSigma <- sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda)) cosSigma <- sinU1*sinU2 + cosU1*cosU2*cosLambda sigma <- atan2(sinSigma, cosSigma) sinAlpha <- cosU1 * cosU2 * sinLambda / sinSigma cosSqAlpha <- 1 - sinAlpha*sinAlpha cos2SigmaM <- cosSigma - 2*sinU1*sinU2/cosSqAlpha if (is.nan(cos2SigmaM)) cos2SigmaM <- 0 # equatorial line: cosSqAlpha=0 (par. 6) C <- f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha)) lambdaP <- lambda lambda <- L + (1-C) * f * sinAlpha * (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM))) iterLimit <- iterLimit - 1 continue <- (abs(lambda-lambdaP) > 1e-12 && iterLimit > 0) } if (iterLimit==0) { res[i] <- NA # failed to converge } else { uSq <- cosSqAlpha * (a*a - b*b) / (b*b) A <- 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq))) B <- uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq))) deltaSigma <- B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)- B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM))) res[i] <- b*A*(sigma-deltaSigma) } } } return(as.vector(res)) } geosphere/R/perimeter.R0000644000176200001440000000344614172661303014565 0ustar liggesusers# Robert Hijmans # April 2010 # version 1 # License GPL3 if (!isGeneric("perimeter")) { setGeneric("perimeter", function(x, ...) standardGeneric("perimeter")) } setMethod("perimeter", signature(x='SpatialPolygons'), function(x, a=6378137, f=1/298.257223563, ...) { x <- x@polygons n <- length(x) res <- vector(length=n) for (i in 1:n) { parts <- length( x[[i]]@Polygons ) perim <- 0 for (j in 1:parts) { if (! x[[i]]@Polygons[[j]]@hole) { crd <- x[[i]]@Polygons[[j]]@coords perim <- perim + perimeter(crd, a=a, f=f, ...) } } res[i] <- perim } return(res) } ) setMethod("perimeter", signature(x='SpatialLines'), function(x, a=6378137, f=1/298.257223563, ...) { x <- x@lines n <- length(x) res <- vector(length=n) for (i in 1:n) { parts <- length( x[[i]]@Lines ) lng <- 0 for (j in 1:parts) { crd <- x[[i]]@Lines[[j]]@coords lng <- lng + perimeter(crd, a=a, f=f, ...) } res[i] <- lng } return(res) } ) setMethod("perimeter", signature(x='data.frame'), function(x, a=6378137, f=1/298.257223563, ...) { perimeter(as.matrix(x), a=a, f=f, ...) } ) setMethod("perimeter", signature(x='matrix'), function(x, a=6378137, f=1/298.257223563, ...) { r <- list(...)$r if (!is.null(r)) { # for backwards compatibility warning('removed argument "r" to use improved method') return( .old_perimeter(x, r=r) ) } n <- nrow(x) d <- .inversegeodesic(as.double(x[-n,1]), as.double(x[-n,2]), as.double(x[-1,1]), as.double(x[-1,2]), as.double(a), as.double(f)) sum(abs(x)) }) .old_perimeter <- function(x, r=6378137, ...) { x <- x[,1:2] if (isTRUE(all.equal(x[1,], x[nrow(x),]))) { x <- x[-nrow(x), ] } y <- rbind(x[-1,], x[1,]) d <- distHaversine(x, y, r=r) return(sum(d)) } geosphere/R/geodesic.R0000644000176200001440000000271714161534066014356 0ustar liggesusers# R implementation of # /* # * This is a C implementation of the geodesic algorithms described in # * # * C. F. F. Karney, # * Algorithms for geodesics, # * J. Geodesy 87, 43--55 (2013); # * https://dx.doi.org/10.1007/s00190-012-0578-z # * Addenda: http://geographiclib.sf.net/geod-addenda.html # * # * See the comments in geodesic.h for documentation. # * # * Copyright (c) Charles Karney (2012-2014) and licensed # * under the MIT/X11 License. For more information, see # * http://geographiclib.sourceforge.net/ # */ # # Robert Hijmans # May 2015 # version 1 # license GPL3 # Solve the direct geodesic problem. geodesic <- function(p, azi, d, a=6378137, f=1/298.257223563, ...) { p <- .pointsToMatrix(p) p <- cbind(p[,1], p[,2], azi, d) r <- .geodesic(as.double(p[,1]), as.double(p[,2]), as.double(p[,3]), as.double(p[,4]), as.double(a), as.double(f)) r <- matrix(r, ncol=3, byrow=TRUE) colnames(r) <- c('longitude', 'latitude', 'azimuth') r } # Solve the inverse geodesic problem. geodesic_inverse <- function(p1, p2, a=6378137, f=1/298.257223563, ...) { p1 <- .pointsToMatrix(p1) p2 <- .pointsToMatrix(p2) p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2]) r <- .inversegeodesic(as.double(p[,1]), as.double(p[,2]), as.double(p[,3]), as.double(p[,4]), as.double(a), as.double(f)) r <- matrix(r, ncol=3, byrow=TRUE) colnames(r) <- c('distance', 'azimuth1', 'azimuth2') r } geosphere/R/midPoint.R0000644000176200001440000000262713472155746014367 0ustar liggesusers# Robert Hijmans # October 2009 # version 0.1 # License GPL3 midPoint <- function(p1, p2, a=6378137, f = 1/298.257223563) { # by Elias Pipping gi <- geodesic_inverse(p1, p2, a=a, f=f); destPoint(p1, gi[,'azimuth1'], gi[,'distance']/2, a = a, f = f) } .old_midPoint <- function(p1, p2) { # author of original JavaScript code: Chris Vennes # (c) 2002-2009 Chris Veness # http://www.movable-type.co.uk/scripts/latlong.html # Licence: LGPL, without any warranty express or implied # Much of the above based on formulae by Ed Williams # http://www.edwilliams.org/avform.htm # Port to R by Robert Hijmans # calculate midpoint of great circle line between p1 & p2. # see http:#//mathforum.org/library/drmath/view/51822.html for derivation # based on http://www.movable-type.co.uk/scripts/latlong.html # (c) 2002-2009 Chris Veness toRad <- pi / 180 p1 <- .pointsToMatrix(p1) * toRad p2 <- .pointsToMatrix(p2) * toRad p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2]) lon1 <- p[,1] lat1 <- p[,2] lon2 <- p[,3] lat2 <- p[,4] dLon <- (lon2-lon1) Bx <- cos(lat2) * cos(dLon) By <- cos(lat2) * sin(dLon) lat <- atan2(sin(lat1) + sin(lat2), sqrt((cos(lat1) + Bx)*(cos(lat1) + Bx) + By*By ) ) lon <- lon1 + atan2(By, cos(lat1) + Bx) lon[is.nan(lon)] <- NA lat[is.nan(lat)] <- NA lon <- (lon+pi)%%(2*pi) - pi res <- cbind(lon, lat) / toRad return(res) } geosphere/R/greatCircleBearing.R0000644000176200001440000000054413472155746016314 0ustar liggesusers# author Robert Hijmans # April 2010 # version 0.1 # license GPL greatCircleBearing <- function(p, brng, n=360) { p <- .pointsToMatrix(p) p <- cbind(p[,1], p[,2], as.vector(brng), n) p2 <- destPoint(p[,1:2], p[,3], 10000000) return(greatCircle(p[,1:2], p2, n=p[,4])) } #greatCircleBearing(rbind(cbind(5,52), cbind(5,15)), 60, n=12) geosphere/R/randomCoordinates.R0000644000176200001440000000101713472155746016247 0ustar liggesusers# author Robert Hijmans # July 2010 # version 0.1 # license GPL # based on suggstions by Michael Orion # http://sci.tech-archive.net/Archive/sci.math/2005-09/msg04691.html randomCoordinates <- function(n) { z <- stats::runif(n) * 2 - 1 t <- stats::runif(n) * 2 * pi r <- sqrt(1-z^2) x <- r * cos(t) y <- r * sin(t) r <- sqrt(x^2 + y^2 + z^2) theta <- acos(z / r) phi <- atan2(y,x) lat <- theta * 180 / pi - 90 lon <- phi * 180 / pi return(cbind(lon,lat)) } geosphere/R/refEllipsoids.R0000644000176200001440000000263013472155746015402 0ustar liggesusers refEllipsoids <- function() { data.frame( ellipsoid = c('Airy (1930)', 'Australian National', 'Bessel 1841', 'Ethiopia, Indonesia, Japan, Korea', 'Namibia', 'Clarke 1866', 'Clarke 1880', 'Everest - Brunei & E. Malasia (Sabah & Sarawak)', 'Everest - India 1830', 'Everest - India 1956', 'Everest - Pakistan', 'Everest - W. Malasia and Singapore 1948', 'Everest - W. Malasia 1969', 'Geodetic Reference System 1980 (GRS 80)', 'Helmert 1906', 'Hough 1960', 'Indonesian 1974', 'International 1924', 'Krassovsky 1940', 'Modified Airy', 'Modified Fischer 1960 (South Asia)', 'South American 1969', 'World Geodetic System 1972 (WGS 72)', 'World Geodetic System 1984 (WGS 84)'), code = c('AA', 'AN', '??', 'BR', 'BN', 'CC', 'CD', 'EB', 'EA', 'EC', 'EF', 'EE', 'ED', 'RF', 'HE', 'HO', 'ID', 'IN', 'KA', 'AM', 'FA', 'SA', 'WD', 'WE'), invf = c(299.3249646, 298.25, 299.1528434, 299.1528128, 299.1528128, 294.9786982, 293.465, 300.8017, 300.8017, 300.8017, 300.8017, 300.8017, 300.8017, 298.2572221, 298.3, 297, 298.247, 297, 298.3, 299.3249646, 298.3, 298.25, 298.26, 298.2572236), a = c(6377563.396, 6378160, 6377397.155, 6377397.155, 6377483.865, 6378206.4, 6378249.145, 6377298.556, 6377276.345, 6377301.243, 6377309.613, 6377304.063, 6377295.664, 6378137, 6378200, 6378270, 6378160, 6378388, 6378245, 6377340.189, 6378155, 6378160, 6378135, 6378137), stringsAsFactors=FALSE ) } geosphere/R/distm.R0000644000176200001440000000106713472155746013721 0ustar liggesusers# Robert Hijmans # April 2010 # version 1 # License GPL3 .distm1 <- function(x, fun) { n = nrow(x) dm = matrix(0, ncol=n, nrow=n) if (n == 1) { return(dm) } for (i in 2:n) { j = 1:(i-1) dm[i,j] = fun(x[i,], x[j,]) } dm <- dm+t(dm) return(dm) } distm <- function(x, y, fun=distGeo) { x <- .pointsToMatrix(x) if (missing(y)) { return( .distm1(x, fun) ) } y <- .pointsToMatrix(y) n = nrow(x) m = nrow(y) dm = matrix(ncol=m, nrow=n) for (i in 1:n) { dm[i,] = fun(x[i,], y) } return(dm) } geosphere/R/distRhumb.R0000644000176200001440000000223113472155746014534 0ustar liggesusers# author of original JavaScript code: Chris Vennes # (c) 2002-2009 Chris Veness # http://www.movable-type.co.uk/scripts/latlong.html # Licence: LGPL, without any warranty express or implied # see http://www.edwilliams.org/avform.htm#Rhumb # for the original formulae # Port to R by Robert Hijmans # October 2009 # version 0.1 # license GPL3 distRhumb <- function(p1, p2, r=6378137) { # distance on a rhumb line toRad <- pi / 180 p1 <- .pointsToMatrix(p1) * toRad if (missing(p2)) { p2 <- p1[-1, ,drop=FALSE] p1 <- p1[-nrow(p1), ,drop=FALSE] } else { p2 <- .pointsToMatrix(p2) * toRad } p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2], as.vector(r)) lon1 <- p[,1] lat1 <- p[,2] lon2 <- p[,3] lat2 <- p[,4] r <- p[,5] dLat <- (lat2-lat1) dLon <- abs(lon2-lon1) dPhi <- log(tan(lat2/2 + pi/4)/tan(lat1/2 + pi/4)) i <- abs(dLat) > 1e-10 q <- vector(length=length(i)) q[i] <- dLat[i]/dPhi[i] q[!i] <- cos(lat1[!i]) #// if dLon over 180 degrees take shorter rhumb across 180 degrees meridian: dLon[dLon > pi] <- 2*pi - dLon[dLon > pi] d <- sqrt(dLat*dLat + q*q*dLon*dLon) return(d * r) } geosphere/R/helper.R0000644000176200001440000000142113472155746014052 0ustar liggesusers# Author: Robert J. Hijmans # April 2010 # version 1 # license GPL3 .normalizeLonDeg <- function(x) { (x + 180) %% 360 - 180 } .normalizeLonRad <- function(x) { (x + pi) %% (2*pi) - pi } .isPolygon <- function(x, fix=FALSE) { x <- stats::na.omit(x) if (nrow(x) < 4) { stop('this is not a polygon (insufficent number of vertices)') } if (length(unique(x[,1]))==1) { stop('All longitudes are the same (not a polygon)') } if (length(unique(x[,2]))==1) { stop('All latitudes are the same (not a polygon)') } if (! all(!(is.na(x))) ) { stop('polygon has NA values)') } if (! isTRUE(all.equal(x[1,], x[nrow(x),]))) { stop('this is not a valid (closed) polygon. The first vertex is not equal to the last vertex') } return(x) } geosphere/R/gcLon.R0000644000176200001440000000262613472155746013645 0ustar liggesusers# author Robert Hijmans # October 2009 # version 0.1 # license GPL3 # based on #http://www.edwilliams.org/avform.htm#Par gcLon <- function(p1, p2, lat) { # longitudes at which a given great circle crosses a given parallel # source: http://www.edwilliams.org/avform.htm toRad <- pi / 180 p1 <- .pointsToMatrix(p1) p2 <- .pointsToMatrix(p2) p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2], lat) p1 <- p[,1:2,drop=FALSE] p2 <- p[,3:4,drop=FALSE] lat <- p[,5] res <- matrix(NA, nrow=nrow(p1), ncol=2) colnames(res) <- c('lon1', 'lon2') anti <- ! antipodal(p1, p2) if (sum(anti) == 0) { return(res) } p1 <- p1[anti, ,drop=FALSE] * toRad p2 <- p2[anti, ,drop=FALSE] * toRad lon1 <- p1[,1] * -1 lat1 <- p1[,2] lon2 <- p2[,1] * -1 lat2 <- p2[,2] lat3 <- lat * toRad l12 <- lon1-lon2 A <- sin(lat1)*cos(lat2)*cos(lat3)*sin(l12) B <- sin(lat1)*cos(lat2)*cos(lat3)*cos(l12) - cos(lat1)*sin(lat2)*cos(lat3) C <- cos(lat1)*cos(lat2)*sin(lat3)*sin(l12) lon <- atan2(B,A) lon3 <- matrix(NA, nrow=length(lon1), ncol=2) i <- (abs(C) > sqrt(A^2 + B^2)) | (sqrt(A^2 + B^2) == 0) lon3[i,] <- NA i <- !i dlon <- rep(NA, length(A)) dlon[i] <- acos(C[i]/sqrt(A[i]^2+B[i]^2)) lon3[i,1] <- .normalizeLonRad(lon1[i]+dlon[i]+lon[i]) lon3[i,2] <- .normalizeLonRad(lon1[i]-dlon[i]+lon[i]) res[anti,] <- -1 * lon3 / toRad return(res) } geosphere/R/gcIntersectBearing.R0000644000176200001440000000442013472155746016337 0ustar liggesusers# author Chris Veness, Robert Hijmans # based on formulae by Ed Willians at # http://www.edwilliams.org/avform.htm#Intersection # October 2009 # version 0.1 # license GPL3 gcIntersectBearing <- function(p1, brng1, p2, brng2) { #crs13 true bearing from point 1 and the crs23 true bearing from point 2: toRad <- pi / 180 p1 <- .pointsToMatrix(p1) * toRad p2 <- .pointsToMatrix(p2) * toRad p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2], as.vector(brng1), as.vector(brng2)) lon1 <- p[,1] lat1 <- p[,2] lon2 <- p[,3] lat2 <- p[,4] lat1[lat1==90|lat1==-90] <- NA lat2[lat2==90|lat2==-90] <- NA brng13 <- p[,5] * toRad brng23 <- p[,6] * toRad dLat <- lat2-lat1 dLon <- lon2-lon1 dist12 <- 2*asin( sqrt( sin(dLat/2)*sin(dLat/2) + cos(lat1)*cos(lat2)*sin(dLon/2)*sin(dLon/2) ) ) lat3 <- lon3 <- vector(length=length(nrow(lon1))) i <- rep(TRUE, length(dist12)) i[dist12 == 0] <- FALSE brngA <- acos( ( sin(lat2) - sin(lat1)*cos(dist12) ) / ( sin(dist12)*cos(lat1) ) ) brngA[is.na(brngA)] <- 0 # protect against rounding brngB <- acos( ( sin(lat1) - sin(lat2)*cos(dist12) ) / ( sin(dist12)*cos(lat2) ) ) g <- (sin(lon2-lon1) > 0) brng12 <- vector(length=length(g)) brng21 <- brng12 brng12[g] <- brngA[g] brng21[g] <- 2*pi - brngB[g] brng12[!g] <- 2*pi - brngA[!g] brng21[!g] <- brngB[!g] alpha1 <- (brng13 - brng12 + pi) %% (2*pi) - pi #// angle 2-1-3 alpha2 <- (brng21 - brng23 + pi) %% (2*pi) - pi #// angle 1-2-3 g <- sin(alpha1) == 0 & sin(alpha2) == 0 h <- (sin(alpha1) * sin(alpha2)) < 0 i <- !(g | h) & i lon3[!i] <- lat3[!i] <- NA alpha1 <- abs(alpha1) alpha2 <- abs(alpha2) alpha3 <- acos( -cos(alpha1)*cos(alpha2) + sin(alpha1)*sin(alpha2)*cos(dist12) ) dist13 <- atan2( sin(dist12)*sin(alpha1)*sin(alpha2), cos(alpha2)+cos(alpha1)*cos(alpha3) ) lat3[i] <- asin( sin(lat1[i])*cos(dist13[i]) + cos(lat1[i]) * sin(dist13[i]) * cos(brng13[i]) ) dLon13 <- atan2( sin(brng13)*sin(dist13)*cos(lat1), cos(dist13)-sin(lat1)*sin(lat3) ) lon3[i] <- lon1[i]+dLon13[i] lon3 <- (lon3+pi) %% (2*pi) - pi # // normalise to -180..180 degrees int <- cbind(lon3, lat3) / toRad colnames(int) <- c('lon', 'lat') int <- cbind(int, antipode(int)) rownames(int) <- NULL return(int) } geosphere/R/regularCoordinates.R0000644000176200001440000000173113472155746016433 0ustar liggesusers# author Robert Hijmans # July 2010 # version 0.1 # license GPL # Based on pascal code by Nils Haeck, simdesign.nl # http://mathforum.org/kb/message.jspa?messageID=3985660&tstart=0 regularCoordinates <- function(N) { N <- round(N) if (N < 1) {stop('N should be >= 1')} # subdivision angle beta <- 0.5 * pi / N # line segment length A <- 2 * sin(beta/2); # endcap points <- rbind(c(0, 0, 1), c(0, 0, -1)) # rings R <- sin(1:N * beta) Z <- cos(1:N * beta) M <- round(R * 2 * pi / A) for (i in 1:N) { j <- 0:(M[i]-1) Alpha <- j/M[i] * 2 * pi X <- cos(Alpha) * R[i] Y <- sin(Alpha) * R[i] points <- rbind(points, cbind(X, Y, Z[i])) if (i != N) { points <- rbind(points, cbind(X, Y, -Z[i])) } } r <- sqrt(points[,1]^2 + points[,2]^2 + points[,3]^2) theta <- acos(points[,3] / r) phi <- atan2(points[,2], points[,1]) lat <- theta * 180 / pi - 90 lon <- phi * 180 / pi return(cbind(lon,lat)) } geosphere/R/plotPoly.R0000644000176200001440000000356313472155746014426 0ustar liggesusers# Author: Robert Hijmans # April 2010 # version 0.1 # license GPL # inspired by an example in Software for Data Analysis by John Chambers (pp 250-1) # but adjusted to follow great circles, rather than straight (2D) lines. .doArrows <- function(p, line, fraction, length, interval, ...) { if (fraction >= 1) { graphics::lines(line, ...) } else { dist <- distGeo(p[-nrow(p),], p[-1,]) * (1 - fraction) bearing <- bearing(p[-nrow(p),], p[-1,]) p0 <- destPoint(p[-nrow(p),], bearing, dist) for (i in 1:nrow(p0)) { line = .makeSinglePoly(rbind(p0[i,], p[i+1,]), interval=interval) graphics::lines(line) } } bearing = finalBearing(p[-nrow(p),], p[-1,]) bearing = (bearing + 180) %% 360 pp = destPoint(p[-1,], bearing, interval) x0 <- pp[,1] y0 <- pp[,2] x1 <- p[,1][-1] y1 <- p[,2][-1] # delta = sqrt(mean((x1-x0)^2 + (y1-y0)^2, na.rm=TRUE)) # delta = delta * (par("pin")[1] / diff(range(x, na.rm=TRUE))) graphics::arrows(x0, y0, x1, y1, code=2, length=length, ...) } plotArrows <- function(p, fraction=0.9, length=0.15, first='', add=FALSE, ...) { asp=1 if (inherits(p, 'Spatial')) { bb = t(bbox(p)) interval = distm(bb)[2][1] / 1000 if (! add) { plot(bb, asp=asp, type='n') } p = p@polygons n = length(p) for (i in 1:n) { parts = length(p[[i]]@Polygons ) sumarea = 0 for (j in 1:parts) { pp = p[[i]]@Polygons[[j]]@coords line = .makeSinglePoly(pp, interval=interval) .doArrows(pp, line, fraction, length, interval=interval, ...) } graphics::points(pp[1,1], pp[1,2], pch=first, cex=2) } } else { interval = max(distm(p), na.rm=TRUE) / 1000 line = .makeSinglePoly(p, interval=interval) if (! add) { plot(line, asp=asp, type='n') } .doArrows(p, line=line, fraction, length, interval=interval, ...) graphics::points(p[1,1], p[1,2], pch=first, cex=2) } } geosphere/R/gcIntermediate.R0000644000176200001440000000632114172663435015520 0ustar liggesusers# author Robert Hijmans # October 2009 # version 0.1 # license GPL .interm <- function(p1, p2, n) { toRad <- pi / 180 if (antipodal(p1, p2)) { return(rep(Inf, nrow(p1))) } if (isTRUE(all.equal(p1, p2))) { return(cbind(rep(p1[,1], nrow(p1)), rep(p1[,2], nrow(p1)) )) } d <- distCosine(p1, p2, r=1) lon1 <- p1[,1] * toRad lat1 <- p1[,2] * toRad lon2 <- p2[,1] * toRad lat2 <- p2[,2] * toRad n <- max(round(n), 1) f <- 1:n / (n+1) A <- sin((1-f)*d) / sin(d) B <- sin(f*d) / sin(d) x <- A*cos(lat1)*cos(lon1) + B*cos(lat2)*cos(lon2) y <- A*cos(lat1)*sin(lon1) + B*cos(lat2)*sin(lon2) z <- A*sin(lat1) + B*sin(lat2) lat <- atan2(z,sqrt(x^2+y^2)) lon <- atan2(y,x) cbind(lon,lat)/toRad } .breakAtDateLine <- function(x) { r <- range(x[,1]) r <- r[2] - r[1] if (r > 200) { dif <- abs(x[-nrow(x),1] - x[-1,1]) tr <- which(dif==max(dif)) x1 <- x[1:tr, ,drop=FALSE] x2 <- x[(tr+1):nrow(x), ,drop=FALSE] if (x1[tr,1] < 0) { x1[tr,1] <- -180 x2[1,1] <- 180 } else { x1[tr,1] <- 180 x2[1,1] <- -180 } if (nrow(x1) <= 1) { res <- x2 } else if (nrow(x2) <= 1) { res <- x1 } else { res <- list(x1, x2) } return(res) } return(x) } gcIntermediate <- function( p1, p2, n=50, breakAtDateLine=FALSE, addStartEnd=FALSE, sp=FALSE, sepNA=FALSE) { # Intermediate points on a great circle # source: http://www.edwilliams.org/avform.htm p1 <- .pointsToMatrix(p1) p2 <- .pointsToMatrix(p2) p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2], as.vector(n)) res <- list() for (i in 1:nrow(p)) { x <- .interm(p[i,1:2,drop=FALSE], p[i,3:4,drop=FALSE], p[i,5]) if (addStartEnd) { x <- rbind(p[i,1:2,drop=FALSE], x, p[i,3:4,drop=FALSE]) } if (breakAtDateLine) { res[[i]] <- .breakAtDateLine(x) } else { res[[i]] <- x } } if (sp) { for (i in 1:length(res)) { if (! is.list(res[[i]])) { res[[i]] <- Lines( list( Line (res[[i]])), ID=as.character(i)) } else { res[[i]] <- Lines( list( Line (res[[i]][[1]]), Line(res[[i]][[2]])), ID=as.character(i)) } } res <- SpatialLines(res, CRS("+proj=longlat +ellps=WGS84")) } else if (nrow(p) == 1 ) { res <- res[[1]] } else if (sepNA) { r <- res[[1]] for (i in 2:length(res)) { r <- rbind(r, c(NA,NA), res[[i]]) } return(r) } return(res) } .geodIntermediate <- function(p1, p2, n=50, breakAtDateLine=FALSE, addStartEnd=TRUE, sepNA=FALSE) { a=6378137 f=1/298.257223563 p1 <- .pointsToMatrix(p1) p2 <- .pointsToMatrix(p2) p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2], as.vector(n)) res <- list() for (i in 1:nrow(p)) { x <- .geod_intermediate(p[i,1], p[i,2], p[i,3], p[i,4], p[i,5], -1, TRUE, a, f) x <- .interm(p[i,1:2,drop=FALSE], p[i,3:4,drop=FALSE], p[i,5]) if (!addStartEnd) { x <- x[-c(1, nrow(x)), ,drop=FALSE] } if (breakAtDateLine) { res[[i]] <- .breakAtDateLine(x) } else { res[[i]] <- x } } if (nrow(p) == 1 ) { res <- res[[1]] } else if (sepNA) { r <- res[[1]] for (i in 2:length(res)) { r <- rbind(r, c(NA,NA), res[[i]]) } return(r) } return(res) } geosphere/R/daylength.R0000644000176200001440000000326514334225267014554 0ustar liggesusers# Author: Robert J. Hijmans, r.hijmans@gmail.com # License GPL3 # Version 0.1 January 2009 daylength <- function(lat, doy) { if (inherits(doy, "Date") || inherits(doy, "character")) { doy <- as.character(doy) doy <- as.numeric(format(as.Date(doy), "%j")) } else { doy <- (doy-1) %% 365 + 1 } lat[lat > 90 | lat < -90] <- NA #Forsythe, William C., Edward J. Rykiel Jr., Randal S. Stahl, Hsin-i Wu and Robert M. Schoolfield, 1995. #A model comparison for daylength as a function of latitude and day of the year. Ecological Modeling 80:87-95. P <- asin(0.39795 * cos(0.2163108 + 2 * atan(0.9671396 * tan(0.00860*(doy-186))))) a <- (sin(0.8333 * pi/180) + sin(lat * pi/180) * sin(P)) / (cos(lat * pi/180) * cos(P)) a <- pmin(pmax(a, -1), 1) DL <- 24 - (24/pi) * acos(a) return(DL) } .daylength2 <- function(lat, doy) { if (inherits(doy, "Date") || inherits(doy, "character")) { doy <- as.character(doy) doy <- as.numeric(format(as.Date(doy), "%j")) } else { doy <- (doy-1) %% 365 + 1 } lat[lat > 90 | lat < -90] <- NA doy <- (doy-1) %% 365 + 1 # after Goudriaan and Van Laar RAD <- pi/180 # Sine and cosine of latitude (LAT) SINLAT <- sin(RAD * lat); COSLAT <- cos(RAD * lat); # Maximal sine of declination;} SINDCM <- sin(RAD * 23.45) #{Sine and cosine of declination (Eqns 3.4, 3.5);} SINDEC <- -SINDCM * cos(2*pi*(doy+10)/365) COSDEC <- sqrt(1-SINDEC*SINDEC); #The terms A and B according to Eqn 3.3;} A <- SINLAT*SINDEC; B <- COSLAT*COSDEC; C <- A/B; #Daylength according to Eqn 3.6; arcsin(c) = arctan(c/sqrt(c*c+1))} DAYL <- 12* (1+(2/pi)* atan(C/sqrt(C*C+1))) return(DAYL) } geosphere/R/dist2Line.R0000644000176200001440000000540513472155746014436 0ustar liggesusers# Author: George Wang & Robert J. Hijmans # August 2010 # version 1 # license GPL3 .spDistPoint2Line <- function(p, line, distfun) { test <- !is.projected(line) if (! isTRUE (test) ) { if (is.na(test)) { warning('Coordinate reference system of SpatialPolygons object is not set. Assuming it is degrees (longitude/latitude)!') } else { stop('Points are projected. They should be in degrees (longitude/latitude)') } # or rather transform them ....? } x <- line@lines n <- length(x) res <- matrix(nrow=nrow(p), ncol=4) colnames(res) <- c("distance","lon","lat","ID") res[] <- Inf for (i in 1:n) { parts <- length(x[[i]]@Lines ) for (j in 1:parts) { crd <- x[[i]]@Lines[[j]]@coords r <- cbind(dist2Line(p, crd, distfun), i) k <- r[,1] < res[,1] res[k, ] <- r[k, ] } } return(res) } dist2Line <- function(p, line, distfun=distGeo) { p <- .pointsToMatrix(p) if (inherits(line, 'SpatialPolygons')) { line <- methods::as(line, 'SpatialLines') } if (inherits(line, 'SpatialLines')) { return( .spDistPoint2Line(p, line, distfun) ) } line <- .pointsToMatrix(line) line1 <- line[-nrow(line), ,drop=FALSE] line2 <- line[-1, ,drop=FALSE] seglength <- distfun(line1, line2) res <- matrix(nrow=nrow(p), ncol=3) colnames(res) <- c("distance","lon","lat") for (i in 1:nrow(p)) { xy <- p[i,] # the shortest distance of a point to a great circle crossdist <- abs(dist2gc(line1, line2, xy)) # the alongTrackDistance is the length of the path along the great circle to the point of intersection # there are two, depending on which node you start # we want to use the min, but the max needs to be < segment length trackdist1 <- alongTrackDistance(line1, line2, xy) trackdist2 <- alongTrackDistance(line2, line1, xy) mintrackdist <- pmin(trackdist1, trackdist2) maxtrackdist <- pmax(trackdist1, trackdist2) crossdist[maxtrackdist >= seglength] <- NA # if the crossdist is NA, we use the distance to the nodes nodedist <- distfun(xy, line) warnopt = getOption('warn') options('warn'=-1) distmin1 <- min(nodedist, na.rm=TRUE) distmin2 <- min(crossdist, na.rm=TRUE) options('warn'= warnopt) if (distmin1 <= distmin2) { j <- which.min(nodedist) res[i,] <- c(distmin1, line[j,]) } else { j <- which.min(crossdist) # if else to determine from which node to start if (trackdist1[j] < trackdist2[j]) { bear <- bearing(line1[j,], line2[j,]) pt <- destPoint(line1[j,], bear, mintrackdist[j]) res[i,] <- c(crossdist[j], pt) } else { bear <- bearing(line2[j,], line1[j,]) pt <- destPoint(line2[j,], bear, mintrackdist[j]) res[i,] <- c(crossdist[j], pt) } } } return(res) } geosphere/R/areaPolygon.R0000644000176200001440000000557014161540713015050 0ustar liggesusers# Robert Hijmans # April 2010 # version 1 # license GPL3 if (!isGeneric("areaPolygon")) { setGeneric("areaPolygon", function(x, ...) standardGeneric("areaPolygon")) } setMethod('areaPolygon', signature(x='data.frame'), function(x, a=6378137, f=1/298.257223563, ...) { areaPolygon(as.matrix(x), a=a, f=f, ...) } ) setMethod('areaPolygon', signature(x='SpatialPolygons'), function(x, a=6378137, f=1/298.257223563, ...) { test <- is.projected(x) if ( isTRUE (test) ) { if (is.na(test)) { warning('Coordinate reference system of SpatialPolygons object is not set. Assuming it is degrees (longitude/latitude)!') } else { stop('The coordinate reference system is not longitude/latitude.') } # or rather transform them ....? } x <- x@polygons n <- length(x) res <- vector(length=n) for (i in 1:n) { parts <- length(x[[i]]@Polygons ) sumarea <- 0 for (j in 1:parts) { crd <- x[[i]]@Polygons[[j]]@coords ar <- areaPolygon(crd, a=a, f=f, ...) if (x[[i]]@Polygons[[j]]@hole) { sumarea <- sumarea - ar } else { sumarea <- sumarea + ar } } res[i] <- sumarea } return(res) } ) setMethod('areaPolygon', signature(x='matrix'), function(x, a=6378137, f=1/298.257223563, ...) { r <- list(...)$r if (!is.null(r)) { # for backwards compatibility warning('remove argument "r" to use an better algorithm') return( .old_areaPolygon(x, r=r) ) } # calling geographiclib x <- .polygonarea(as.double(x[,1]), as.double(x[,2]), as.double(a), as.double(f)) abs(x[3]) }) .old_areaPolygon <- function(x, r=6378137, ...) { # Based on code by Jason_Steven (http://forum.worldwindcentral.com/showthread.php?p=69704) # Reference: Bevis, M. and G. Cambareri, 1987. Computing the area of a spherical polygon of arbitrary shape. Mathematical Geology 19: 335-346 haversine <- function(y) { (1-cos(y))/2 } x <- .pointsToMatrix(x, poly=TRUE) x <- makePoly(x) # for some corner cases # rotate? dif1 <- max(x[,1]) - min(x[,1]) if (dif1 > 180) { x2 <- x x2[,1] <- x2[,1] %% 360 - 180 #dif1 <- max(x[,1]) - min(x[,1]) dif2 <- max(x2[,1]) - min(x2[,1]) if (dif2 < dif1) { x <- x2 } } x <- x * pi / 180 r <- r[1] j <- 1:nrow(x) k <- c(2:nrow(x), 1) i <- x[j,1] != x[k,1] j <- j[i] k <- k[i] lam1 <- x[j,1] lam2 <- x[k,1] beta1 <- x[j,2] beta2 <- x[k,2] cosB1 <- cos( beta1 ) cosB2 <- cos( beta2 ) hav <- haversine( beta2 - beta1 ) + cosB1 * cosB2 * haversine( lam2 - lam1 ) a <- 2 * asin( sqrt( hav ) ) b <- pi / 2 - beta2 c <- pi / 2 - beta1 s <- 0.5 * ( a + b + c ) t <- tan( s / 2 ) * tan( ( s - a ) / 2 ) * tan( ( s - b ) / 2 ) * tan( ( s - c ) / 2 ) excess <- abs( 4 * atan( sqrt( abs( t ) ) ) ) excess[lam2 < lam1] <- -excess[lam2 < lam1] arsum <- abs( sum( excess ) ) * r * r return(arsum ) } geosphere/R/bearing.R0000644000176200001440000000254414161534017014175 0ustar liggesusers# Author: Robert J. Hijmans # Date : March 2010 / May 2015 # Version 2.0 # Licence GPL v3 bearing <- function(p1, p2, a=6378137, f=1/298.257223563) { p1 <- .pointsToMatrix(p1) if (missing(p2)) { if (nrow(p1) < 2) { return(NA) } p2 <- p1[-1, ,drop=FALSE] p1 <- p1[-nrow(p1), ,drop=FALSE] addNA <- TRUE } else { p2 <- .pointsToMatrix(p2) addNA <- FALSE } p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2]) r <- .inversegeodesic(as.double(p[,1]), as.double(p[,2]), as.double(p[,3]), as.double(p[,4]), as.double(a[1]), as.double(f[1])) r <- matrix(r, ncol=3, byrow=TRUE) if (addNA) { c(r[, 2], NA) } else { r[, 2] } } .old_bearing <- function(p1, p2) { toRad <- pi / 180 p1 <- .pointsToMatrix(p1) * toRad p2 <- .pointsToMatrix(p2) * toRad p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2]) p1 <- p[, 1:2, drop=FALSE] p2 <- p[, 3:4, drop=FALSE] keep <- ! apply(p1 == p2, 1, sum) == 2 res <- rep(NA, length=nrow(p1)) if (sum(keep) == 0) { return(res) } p1 <- p1[keep, , drop=FALSE] p2 <- p2[keep, , drop=FALSE] dLon <- p2[,1] - p1[,1] y <- sin(dLon) * cos(p2[,2]) x <- cos(p1[,2]) * sin(p2[,2]) - sin(p1[,2]) * cos(p2[,2]) * cos(dLon) azm <- atan2(y, x) / toRad azm <- (azm+360) %% 360 i <- azm > 180 azm[i] <- -1 * (360 - azm[i]) res[keep] <- azm return(res) } geosphere/R/gcMaxLat.R0000644000176200001440000000255413472155746014303 0ustar liggesusers# Based on formulae by Ed Williams # http://www.edwilliams.org/avform.htm # Port to R by Robert Hijmans # October 2009 # version 0.1 # License GPL3 gcMaxLat <- function(p1, p2) { toRad <- pi / 180 p1 <- .pointsToMatrix(p1) p2 <- .pointsToMatrix(p2) p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2]) p1 <- p[,1:2,drop=FALSE] p2 <- p[,3:4,drop=FALSE] anti <- antipodal(p1, p2) same <- apply(p1 == p2, 1, sum) == 2 use <- !(anti | same) res <- matrix(rep(NA, nrow(p1)*2), ncol=2) colnames(res) <- c('lon', 'lat') if (length(use)==0) { return(res) } pp1 <- p1[use, , drop=FALSE] pp2 <- p2[use, , drop=FALSE] b <- .old_bearing(pp1, pp2) * toRad lat <- pp1[,2] * toRad # Clairaut's formula : the maximum latitude of a great circle path, given a bearing and latitude on the great circle maxlat <- acos(abs(sin(b) * cos(lat))) / toRad ml <- maxlat - 0.000000000001 maxlon <- mean(gcLon(pp1, pp2, ml)) res[use,] <- cbind(maxlon, maxlat) # lon <- pp1[,1] * toRad # maxlon <- rep(NA, length(maxlat)) # i <- maxlat==0 # j <- b < pi & !i # k <- !j & !i # maxlon[j] <- lon[j] - atan2(cos(b[j]), sin(b[j]) * sin(lat[j])) # maxlon[k] <- lon[k] + pi - atan2(cos(b[k]), sin(b[k]) * sin(lat[k])) # maxlon <- -1 * ((maxlon+pi)%%(2*pi) - pi) # res[use,] <- cbind(maxlon, maxlat)/ toRad return(res) } geosphere/R/distGeo.R0000644000176200001440000000123014161534041014150 0ustar liggesusers# Author: Robert J. Hijmans # Date : May 2015 # Licence GPL v3 distGeo <- function(p1, p2, a=6378137, f=1/298.257223563) { p1 <- .pointsToMatrix(p1) if (missing(p2)) { if (nrow(p1) == 1) return(0) if (nrow(p1) == 0) return(NULL) p2 <- p1[-1, ,drop=FALSE] p1 <- p1[-nrow(p1), ,drop=FALSE] addNA <- TRUE } else { p2 <- .pointsToMatrix(p2) addNA <- FALSE } p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2]) r <- .inversegeodesic(as.double(p[,1]), as.double(p[,2]), as.double(p[,3]), as.double(p[,4]), as.double(a), as.double(f)) r <- matrix(r, ncol=3, byrow=TRUE) if (addNA){ c(r[,1], NA) } else { r[,1] } } geosphere/R/horizon.R0000644000176200001440000000022513472155746014264 0ustar liggesusers horizon <- function(h, r=6378137) { x = cbind(as.vector(h), as.vector(r)) h = x[,1] r = x[,2] b = 0.8279 sqrt( 2 * r * h / b ) } geosphere/R/bearingRhumb.R0000644000176200001440000000221113472155746015176 0ustar liggesusers# author of original JavaScript code: Chris Vennes # (c) 2002-2009 Chris Veness # http://www.movable-type.co.uk/scripts/latlong.html # Licence: LGPL, without any warranty express or implied # see http://www.edwilliams.org/avform.htm#Rhumb # for the original formulae # Port to R by Robert Hijmans # October 2009 # version 0.1 # license GPL3 bearingRhumb <- function(p1, p2) { toRad <- pi / 180 p1 <- .pointsToMatrix(p1) * toRad p2 <- .pointsToMatrix(p2) * toRad p <- cbind(p1[,1], p1[,2], p2[,1], p2[,2]) p1 <- p[, 1:2, drop=FALSE] p2 <- p[, 3:4, drop=FALSE] keep <- ! apply(p1 == p2, 1, sum) == 2 res <- rep(NA, length=nrow(p1)) if (sum(keep) == 0) { return(res) } lon1 <- p1[keep, 1, drop=FALSE] lat1 <- p1[keep, 2, drop=FALSE] lon2 <- p2[keep, 1, drop=FALSE] lat2 <- p2[keep, 2, drop=FALSE] dLon <- (lon2-lon1) dPhi <- log(tan(lat2/2 + pi/4)/tan(lat1/2+pi/4)) i <- (abs(dLon) > pi) j <- i & dLon > 0 dLon[j] <- -(2*pi-dLon[j]) j <- i & dLon <= 0 dLon[j] <- dLon[j] <- (2*pi+dLon[j]) b <- atan2(dLon, dPhi) b <- b / toRad b <- (b+360) %% 360 res[keep] = b return(res) } geosphere/R/mercator.R0000644000176200001440000000077113472155746014416 0ustar liggesusers# Author: Robert J. Hijmans # April 2010 # version 0.1 # license GPL3 mercator <- function(p, inverse=FALSE, r=6378137) { toRad <- pi / 180 if (inverse) { p <- .pointsToMatrix(p, checkLonLat=FALSE) p[ ,2] <- pi/2 - 2 * atan(exp(-p[,2] / r)) p[ ,1] <- p[,1] / r colnames(p) <- c('lon', 'lat') return( p / toRad ) } else { p <- .pointsToMatrix(p) * toRad p[,2] <- log( tan(p[,2]) + (1 / cos(p[,2]))) p <- p * r colnames(p) <- c('x', 'y') return( p ) } } geosphere/R/distMeeus.R0000644000176200001440000000214213472155746014536 0ustar liggesusers# R code by Robert Hijmans # based on Java script code by # Stephen R. Schmitt (copyright, 2004) # http://web.archive.org/web/20070108024032/http://home.att.net/~srschmitt/script_greatcircle.html # algorithm taken from "Astronomical Algorithms" by Jean Meeus distMeeus <- function(p1, p2, a=6378137, f=1/298.257223563) { toRad <- pi / 180 p1 <- .pointsToMatrix(p1) * toRad if (missing(p2)) { p2 <- p1[-1, ,drop=FALSE] p1 <- p1[-nrow(p1), ,drop=FALSE] } else { p2 <- .pointsToMatrix(p2) * toRad } F <- ( p1[,2] + p2[,2] ) / 2 G <- ( p1[,2] - p2[,2] ) / 2 L <- ( p1[,1] - p2[,1] ) / 2 sinG2 <- ( sin( G ) )^2 cosG2 <- ( cos( G ) )^2 sinF2 <- ( sin( F ) )^2 cosF2 <- ( cos( F ) )^2 sinL2 <- ( sin( L ) )^2 cosL2 <- ( cos( L ) )^2 S <- sinG2 * cosL2 + cosF2 * sinL2 C <- cosG2 * cosL2 + sinF2 * sinL2 w <- atan( sqrt( S/C ) ) R <- sqrt( S*C )/w D <- 2 * w * a H1 <- (3*R - 1)/(2*C) H2 <- (3*R + 1)/(2*S) dst <- D*( 1 + f*H1*sinF2*cosG2 - f*H2*cosF2*sinG2 ) # remove NaN for when p1[i,]==p2[i,] dst[which(w==0)] <- 0 return ( as.vector(dst) ) } geosphere/R/pointsToMatrix.R0000644000176200001440000000431713472155746015606 0ustar liggesusers# Author: Robert J. Hijmans & Jacob van Etten # October 2009 # version 1 # license GPL3 .pointsToMatrix <- function(p, checkLonLat=TRUE, poly=FALSE) { if (inherits(p, 'SpatialPoints')) { test <- !is.projected(p) if (! isTRUE (test) ) { if (is.na(test)) { warning('Coordinate reference system of SpatialPoints object is not set. Assuming it is degrees (longitude/latitude)!') } else { stop('Points are projected. They should be in degrees (longitude/latitude)') } # or rather transform them ....? } p <- coordinates(p) } else if (is.data.frame(p)) { p <- as.matrix(p) } else if (is.vector(p)){ if (length(p) != 2) { stop('Wrong length for a vector, should be 2') } else { p <- matrix(p, ncol=2) } } else if (is.matrix(p)) { if (ncol(p) != 2) { stop( 'A points matrix should have 2 columns') } cn <- colnames(p) if (length(cn) == 2) { if (toupper(cn[1]) == 'Y' | toupper(cn[2]) == 'X') { warning('Suspect column names (x and y reversed?)') } if (toupper(substr(cn[1],1,3) == 'LAT' | toupper(substr(cn[2],1,3)) == 'LON')) { warning('Suspect column names (longitude and latitude reversed?)') } } } else { stop('points should be vectors of length 2, matrices with 2 columns, or inheriting from a SpatialPoints* object') } if (! is.numeric(p) ) { p[] <- as.numeric(p) } if (checkLonLat & nrow(p) > 0) { if (length(stats::na.omit(p[,1])) > 0) { if (min(p[,1], na.rm=TRUE) < -360) { stop('longitude < -360') } if (max(p[,1], na.rm=TRUE) > 360) { stop('longitude > 360') } if (min(p[,1], na.rm=TRUE) < -180) { warning('longitude < -180') } if (max(p[,1], na.rm=TRUE) > 180) { warning('longitude > 180') } } if (length(stats::na.omit(p[,2])) > 0) { if (min(p[,2], na.rm=TRUE) < -90) { stop('latitude < -90') } if (max(p[,2], na.rm=TRUE) > 90) { stop('latitude > 90') } } } if (poly) { if (! isTRUE(all.equal(p[1,], p[nrow(p),]))) { p <- rbind(p, p[1,]) } i <- p[-nrow(p),1] == p[-1,1] & p[-nrow(p),2] == p[-1,2] i <- which(isTRUE(i)) if (length(i) > 0) { p <- p[-i, ,drop=FALSE] } .isPolygon(p) } return(p) } geosphere/R/old_destPoint.R0000644000176200001440000000231313472155746015403 0ustar liggesusers# author of original JavaScript code: Chris Vennes # (c) 2002-2009 Chris Veness # http://www.movable-type.co.uk/scripts/latlong.html # Licence: LGPL, without any warranty express or implied # Based on formulae by Ed Williams # http://www.edwilliams.org/avform.htm # Port to R by Robert Hijmans # October 2009 # version 0.1 # License GPL3 .old_destPoint <- function(p, b, d, r=6378137) { # calculate destination point given start point, initial bearing (deg) and distance (km) # see http:#//www.edwilliams.org/avform.htm#LL # source http://www.movable-type.co.uk/scripts/latlong.html # (c) 2002-2009 Chris Veness toRad <- pi / 180 b = as.vector(b) d = as.vector(d) r = as.vector(r) p <- .pointsToMatrix(p) p = cbind(p[,1], p[,2], b, d, r) lon1 <- p[,1] * toRad lat1 <- p[,2] * toRad b <- p[,3] * toRad d = p[,4] r = p[,5] lat2 <- asin( sin(lat1)*cos(d/r) + cos(lat1)*sin(d/r)*cos(b) ) lon2 <- lon1 + atan2(sin(b)*sin(d/r)*cos(lat1), cos(d/r)-sin(lat1)*sin(lat2)) lon2 <- (lon2+pi)%%(2*pi) - pi #// normalise to -180...+180 lon2[is.nan(lon2)] <- NA lat2[is.nan(lat2)] <- NA res <- cbind(lon2, lat2) / toRad colnames(res) <- c('lon', 'lat') return(res) } geosphere/R/lengthLine.R0000644000176200001440000000150113472155746014663 0ustar liggesusers# Author: Robert J. Hijmans # August 2016 # version 1 # license GPL3 lengthLine <- function(line) { if (inherits(line, 'SpatialPolygons')) { requireNamespace('raster') line <- raster::geom(methods::as(line, 'SpatialLines')) } else if (inherits(line, 'SpatialLines')) { requireNamespace('raster') line <- raster::geom(line) } else { line <- cbind(object=1, part=1, cump=1, line[, 1:2]) colnames(line)[4:5] <- c('x', 'y') } ids <- unique(line[,1]) len <- rep(0, length(ids)) for (i in 1:length(ids)) { d <- line[line[,1] == ids[i], ] parts <- unique(d[,2]) for (p in parts) { dd <- d[d[,2] == p, ,drop=FALSE] for (j in 1:(nrow(dd)-1)) { len[i] <- len[i] + distGeo(dd[j, c('x', 'y'), drop=FALSE], dd[j+1, c('x', 'y'), drop=FALSE]) } } } return(len) } geosphere/R/geomean.R0000644000176200001440000000123513472155746014211 0ustar liggesusers# Author: Robert J. Hijmans # February 2012 # version 1 # license GPL3 geomean <- function(xy, w=NULL) { xy <- .pointsToMatrix(xy) if (is.null(w)) { w <- 1 } else if (length(w) != nrow(xy)) { stop('length of weights not correct. It should be: ', nrow(xy)) } w <- w / sum(w) xyw <- cbind(xy, w) xy <- stats::na.omit(xyw) xy <- xyw[,1:2] w <- xyw[,3] xy[,1] <- xy[,1] + 180 xy <- xy * pi / 180 Sx <- mean(sin(xy[,1]) * w) Cx <- mean(cos(xy[,1]) * w) x <- atan2(Sx, Cx) x <- x %% (2 * pi) - pi Sy <- mean(sin(xy[,2]) * w) Cy <- mean(cos(xy[,2]) * w) y <- atan2(Sy, Cy) cbind(x,y) * 180 / pi } geosphere/MD50000644000176200001440000001545514335012510012547 0ustar liggesusersc69db0907b2f003d2b424d1638908e2f *ChangeLog b7f3d1e70d1efb22ac70ca821c98ec83 *DESCRIPTION 823071db3a642bdc2d26dacadcff50ea *NAMESPACE 50a25b096efd5ca6d1c4786db65d7d0c *R/RcppExports.R 5e4491aab79aa215a938d6e6561b2e37 *R/alongTrack.R c603e867d2d36b565c0223b52c1c769e *R/antipodal.R c85737b543ca52765261f0d48c44ff6e *R/areaPolygon.R b32846602a0f755c189e48bae7d59a06 *R/bearing.R 495cb8e6ca1422490b1c6058f9450a46 *R/bearingRhumb.R aeefe269b66e57f93cdd2acf0547321f *R/centroid.R 1743d120f033b849e8e77ca463d7c815 *R/daylength.R 1e9e4acd9a27238f46135af46902db60 *R/destPoint.R 19e711a9e49bbc7200d3d6a92af583c5 *R/destPointRhumb.R 825ed606555476f8b20a40c25b34a63b *R/dist2Line.R 7f333bbd90b64c3aa7f9d34b39ed539d *R/dist2gc.R ef4a2cf12c3ed6b1f6c685ad3c9640d6 *R/distCosines.R 30118ba1a360d8679c7f8885f76a2f32 *R/distGeo.R e46f596d3547a7918d737a7d1c4b43ff *R/distHaversine.R 0fc2aa7858bca0fcde0168aecafc3582 *R/distMeeus.R b76298022a9e7e04a41bed4963e4f31d *R/distRhumb.R d86e0dbc3e707a4e765afa6d4ecc7b76 *R/distVincentyEllipsoid.R c91231d7fd536e01af2bcebf5266f40c *R/distVincentySphere.R e5d8a111f45a8958d3c1550365ac8be1 *R/distm.R a8fd9e76e34b8ba76855fb68e0268c5b *R/finalBearing.R 71f5cb986eea1e42b7af9a26f358fd6d *R/gcIntermediate.R 7907332e1c86fd152dba4944eeac4c5e *R/gcIntersect.R df3e5ff050196f694dcb830909576d54 *R/gcIntersectBearing.R 4983e28ab7a610326903f3f8c968e346 *R/gcLat.R 9ee61a5e62351c7c8693abbf7a25b103 *R/gcLon.R 3195f1d7d786a931e8f07307bab61d62 *R/gcMaxLat.R d0057355a3a1dfd076e94db19a958e77 *R/geodesic.R 2081dca1de87b02dd38dee2d21857e58 *R/geomean.R e05b9ce8c5b6851519e138156fa0527d *R/geomedian.R e83d7662049f48f412d7f54a5766c3c8 *R/greatCircle.R 2818b0933c09267f0c05b1ae07bec869 *R/greatCircleBearing.R 088fe0172bbf3794e16cecc29e17a3ee *R/helper.R ea4c7189b67965e4517e648f27e062b2 *R/horizon.R a6cb94430b50c900a10f0d8fce1b6102 *R/lengthLine.R 2fe3bf69af5f16df458a3e21ae436978 *R/makePoly.R 323eadc05c03f5d11b51558ec412640d *R/mercator.R 430c0a96d811acc0eb31638a108ef44b *R/midPoint.R 13f88662ae5bcb6f0584facd6bd57e29 *R/old_destPoint.R caba5729f0e9429c56c9e6dd6c0d4b3c *R/onGreatCircle.R 70aa176635f101570c71808e71c4353a *R/perimeter.R e50d15fc59606d5967fbaaf2ff495739 *R/plotPoly.R b559f888e8e8f24ae56d5b221acf337b *R/pointsToMatrix.R 63372c1d29b6fd85bc82e2695ef831cf *R/randomCoordinates.R ad94d2fb3c7bab9fcc660132ae3534bb *R/refEllipsoids.R a0903ff2b54c613bedcd723a0b3784f7 *R/regularCoordinates.R 4400c83027e73243e6d8e9f30075dda2 *R/sampleAlong.R ff01ac40ecb1cd5d7051ffbfe7c2d64d *R/span.R cb4924f3573383fca290a0a8e2ca5294 *build/partial.rdb ebb888c3d8f202c0d52c834836f1610d *build/vignette.rds 990871f1c55db0d5b160d786c86e6850 *data/merc.RData 464a29b93751536caa7f2cf583124960 *data/wrld.RData 538f4c2b1ae4ddf2242766b02f340b1d *inst/doc/geosphere.R 5090e95e97f748525ed9905c51309b22 *inst/doc/geosphere.Rnw 781b4ea31d3580da498b20cc768a376c *inst/doc/geosphere.pdf 6d96299e3d47a6bc59572c331080d5c6 *man/alongTrackDistance.Rd e3149675013c8042a7e4b1d189ebb502 *man/antipode.Rd 2c3927acdf4de92b9470bea1cb288079 *man/area.Rd 3c1e67195e91c173dab816fa1ef556a5 *man/bearing.Rd 759fd642d8d30a6e4df829f4ad83e96d *man/bearingRhumb.Rd 9f635d7f7c92d5a35ca58634f9d4aca0 *man/centroid.Rd 5313bdcb42b9f847a3cfe5a6662122f1 *man/data.Rd 919193497deae5b71e7b2ce8586aa695 *man/daylength.Rd bb669fa8d574e4635055b22f1d50f4c6 *man/destPoint.Rd 8c9abb053076948c843bb6aee5bc8255 *man/destPointRhumb.Rd 308ded364b826af6300a8fdd4ef87ef9 *man/dist2gc.Rd 01a22370f20c44a9caaa72f910c6e514 *man/dist2line.Rd c5f5fb73bb34f9a26752da3e52111dba *man/distCosine.Rd dd141627647789d50a684905fcc436a0 *man/distGeo.Rd fe4749f348de0dfc5e40628e2e0d3359 *man/distHaversine.Rd 18bf5b4b4721eaa101e44787e6c3cb0e *man/distMeeus.Rd 6b58e5faa130ae3e37cfe14ca51c94b0 *man/distRhumb.Rd e885d31e77b4c95b3fc5f38b1ffc2524 *man/distVincentyEllipsoid.Rd e4e1780d70108de0d7bd8e9fc864490b *man/distVincentySphere.Rd afa1c56dd3db517d3d1605943a1c1826 *man/distm.Rd 4b6f1d4603bc1b515b02b5e00f33b356 *man/finalDirection.Rd 3c4b544ec73c1fe20b6071539c427a0a *man/gcIntersect.Rd 45cb5bd7816f9245b501a0cc194185e4 *man/gcIntersectBearing.Rd 6cb89752de06fa903cd398aeff8f7eba *man/gcLat.Rd 4765b6196ab47333898170efd8dfccb2 *man/gcLon.Rd ac3f7fabfe8b312bb0a432305d2d4d15 *man/gcMaxLat.Rd 6fa655576b9ef5b129e1f4d840772857 *man/geodesic.Rd 48cb8c3ad419c5c376828521bcae65c2 *man/geomean.Rd 1255b86af896a11f3c47dbe2d85bc285 *man/geosphere-package.Rd 4e7069024be6c2df3c285532b4a09a3f *man/greatCircle.Rd 1fb55c4fcc4dc6832a62ed972ed21e72 *man/greatCircleBearing.Rd 2fe4ad438c887c4afa1b6ab8ec397c8e *man/horizon.Rd b5f2fe72f907c3f528e62213eb87a231 *man/intermediate.Rd f4041cf233eff9ff59f433466b12c72b *man/lengthLine.Rd f914ee7fb7d8814771cc6b9030d80874 *man/makepoly.Rd bb5594fa360f7bd43ce0e5a3e7669765 *man/mercator.Rd 1f4501ca3c843ed15e7fad9ede71fbd7 *man/midPoint.Rd 59e5771608c5cd49199e43247d7322c5 *man/onGreatCircle.Rd d6584b12201babdd088d975b602765a3 *man/perimeter.Rd 9c6d6bf5d20a721a18e2ecc43b93b53c *man/plotArrows.Rd a62b2968097c05ee51730cf47c42bd02 *man/randomCoordinates.Rd 03ee9e2645c0d185463b1b7d39096280 *man/refEllipsoids.Rd e5a815ce847782faf61535d948b2681f *man/span.Rd a4f1af295fda57e6a3112e05ad49f5d0 *src/Accumulator.cpp 0aa8161898fd7d220aa8c9a6e55cfd7e *src/Accumulator.h 14444100183ec4ed312b7c62a692d236 *src/AlbersEqualArea.cpp 613e27b027ce4a7d01e20f1c17ad1a17 *src/AlbersEqualArea.h b02a5ff1471c0c641e0f9552a6a02915 *src/Config.h 298f0446b13a6e9bc1c81482b4f4a0be *src/Constants.h 90d20576585033f5e1a408983bda06e1 *src/DST.cpp 84d4f37b1a949a3ae8a6bf560fa84846 *src/DST.h ce5de9c97ef81cad6376a983e51e0d3e *src/Ellipsoid.cpp ba65b0b4b14faebc65ffcb360435575b *src/Ellipsoid.h e453f945a85b765e7077192a0a904c3f *src/EllipticFunction.cpp 270b441b7b7219a5a7a626793cf35d97 *src/EllipticFunction.h fe66f14773c201cfde8caf60ba62d13f *src/Geodesic.cpp 5e03c52f08e49ada7587c69cde93b875 *src/Geodesic.h d626029da193038b914444ec50aff59e *src/GeodesicExact.cpp cd6c9f983799b305fd0fdad2fbc2d351 *src/GeodesicExact.h 859bd28e47472e5c05c9c6c0122d561c *src/GeodesicLine.cpp 992e0cade521fe85ceddc6918af16540 *src/GeodesicLine.h 3b472239ba504d61d695d3dba9f30ec6 *src/GeodesicLineExact.cpp 73dd836a7fb8b8fd3a28a003bbea5903 *src/GeodesicLineExact.h 382eb547fdb12d134f16ee34551e5ee5 *src/Math.cpp b3c07ab34c65495e5a3b9a1dcc5d885f *src/Math.h e653d09c1005ae3c416a1aba45e1c89c *src/PolygonArea.cpp c3c9f2cd934cfb88631a7357973ef315 *src/PolygonArea.h 6d92db3e300129c111b323857275d933 *src/RcppExports.cpp 4e696b8deb94baf24c9afbd3d0f034b0 *src/Rhumb.cpp 6c7010c04e7686a0204a6077c0fd024d *src/Rhumb.h 1eaf3edd3970b709c5d9bad53230e5bc *src/TransverseMercator.cpp 405c21a9998da0d1411f02f47bc038d0 *src/TransverseMercator.h c92e9a174ac3b5529402c9795b612356 *src/a_dist.c bd73d1d0cd6efd059299b606e3f86c99 *src/a_geodesic.cpp e7ed3cfd2ceb132ccd9e7c342ba7f0a0 *src/a_util.c 02b3ab8677d52f791681845435a5252a *src/a_util.h d554906e5117a31c97b4ed41eecafb09 *src/kissfft.h 5090e95e97f748525ed9905c51309b22 *vignettes/geosphere.Rnw geosphere/inst/0000755000176200001440000000000014334225370013213 5ustar liggesusersgeosphere/inst/doc/0000755000176200001440000000000014334225370013760 5ustar liggesusersgeosphere/inst/doc/geosphere.R0000644000176200001440000002031314334225370016063 0ustar liggesusers### R code from vignette source 'geosphere.Rnw' ################################################### ### code chunk number 1: foo ################################################### options(keep.source = TRUE, width = 60) foo <- packageDescription("geosphere") ################################################### ### code chunk number 2: geosphere.Rnw:58-71 ################################################### library(geosphere) Lon <- c(1:9/1000, 1:9/100, 1:9/10, 1:90*2) Lat <- c(1:9/1000, 1:9/100, 1:9/10, 1:90) dcos <- distCosine(c(0,0), cbind(Lon, Lat)) dhav <- distHaversine(c(0,0), cbind(Lon, Lat)) dvsp <- distVincentySphere(c(0,0), cbind(Lon, Lat)) par(mfrow=(c(1,2))) plot(log(dcos), dcos-dhav, col='red', ylim=c(-1e-05, 1e-05), xlab="Log 'Law of Cosines' distance (m)", ylab="Law of Cosines minus Haversine distance") plot(log(dhav), dhav-dvsp, col='blue', xlab="Log 'Haversine' distance (m)", ylab="Vincenty Sphere minus Haversine distance") ################################################### ### code chunk number 3: geosphere.Rnw:76-79 ################################################### dvse <- distVincentyEllipsoid(c(0,0), cbind(Lon, Lat)) plot(dvsp/1000, (dvsp-dvse)/1000, col='blue', xlab='Vincenty Sphere Distance (km)', ylab="Difference between 'Vincenty Sphere' and 'Vincenty Ellipsoid' methods (km)") ################################################### ### code chunk number 4: geosphere.Rnw:89-102 ################################################### LA <- c(-118.40, 33.95) NY <- c(-73.78, 40.63) data(wrld) plot(wrld, type='l') gc <- greatCircle(LA, NY) lines(gc, lwd=2, col='blue') gci <- gcIntermediate(LA, NY) lines(gci, lwd=4, col='green') points(rbind(LA, NY), col='red', pch=20, cex=2) mp <- midPoint(LA, NY) onGreatCircle(LA,NY, rbind(mp,c(0,0))) points(mp, pch='*', cex=3, col='orange') greatCircleBearing(LA, brng=270, n=10) ################################################### ### code chunk number 5: geosphere.Rnw:109-117 ################################################### destPoint(LA, b=65, d=100000) circle=destPoint(c(0,80), b=1:365, d=1000000) circle2=destPoint(c(0,80), b=1:365, d=500000) circle3=destPoint(c(0,80), b=1:365, d=100000) plot(circle, type='l') polygon(circle, col='blue', border='black', lwd=4) polygon(circle2, col='red', lwd=4, border='orange') polygon(circle3, col='white', lwd=4, border='black') ################################################### ### code chunk number 6: geosphere.Rnw:125-139 ################################################### ml <- gcMaxLat(LA, NY) lat0 <- gcLat(LA, NY, lon=0) lon0 <- gcLon(LA, NY, lat=0) plot(wrld, type='l') lines(gc, lwd=2, col='blue') points(ml, col='red', pch=20, cex=2) points(cbind(0, lat0), pch=20, cex=2, col='yellow') points(t(rbind(lon0, 0)), pch=20, cex=2, col='green' ) f <- function(lon){gcLat(LA, NY, lon)} opt <- optimize(f, interval=c(-180, 180), maximum=TRUE) points(opt$maximum, opt$objective, pch=20, cex=2, col='dark green' ) anti <- antipode(c(opt$maximum, opt$objective)) points(anti, pch=20, cex=2, col='dark blue' ) ################################################### ### code chunk number 7: geosphere.Rnw:146-161 ################################################### SF <- c(-122.44, 37.74) AM <- c(4.75, 52.31) gc2 <- greatCircle(AM, SF) plot(wrld, type='l') lines(gc, lwd=2, col='blue') lines(gc2, lwd=2, col='green') int <- gcIntersect(LA, NY, SF, AM) int antipodal(int[,1:2], int[,3:4]) points(rbind(int[,1:2], int[,3:4]), col='red', pch=20, cex=2) bearing1 <- bearing(LA, NY) bearing2 <- bearing(SF, AM) bearing1 bearing2 gcIntersectBearing(LA, bearing1, SF, bearing2) ################################################### ### code chunk number 8: geosphere.Rnw:169-189 ################################################### MS <- c(-93.26, 44.98) gc1 <- greatCircleBearing(NY, 281) gc2 <- greatCircleBearing(MS, 195) gc3 <- greatCircleBearing(LA, 55) plot(wrld, type='l', xlim=c(-125, -70), ylim=c(20, 60)) lines(gc1, col='green') lines(gc2, col='blue') lines(gc3, col='red') int <- gcIntersectBearing(rbind(NY, NY, MS), c(281, 281, 195), rbind(MS, LA, LA), c(195, 55, 55)) int distm(rbind(int[,1:2], int[,3:4])) int <- int[,1:2] points(int) poly <- rbind(int, int[1,]) centr <- centroid(poly) poly2 <- makePoly(int) polygon(poly2, col='yellow') points(centr, pch='*', col='dark red', cex=2) ################################################### ### code chunk number 9: geo5 ################################################### d <- distCosine(LA, NY) d b <- bearing(LA, NY) b destPoint(LA, b, d) NY finalBearing(LA, NY) ################################################### ### code chunk number 10: geosphere.Rnw:213-224 ################################################### atd <- alongTrackDistance(LA, NY, MS) p <- destPoint(LA, b, atd) plot(wrld, type='l', xlim=c(-130,-60), ylim=c(22,52)) lines(gci, col='blue', lwd=2) points(rbind(LA, NY), col='red', pch=20, cex=2) points(MS[1], MS[2], pch=20, col='blue', cex=2) lines(gcIntermediate(LA, p), col='green', lwd=3) lines(gcIntermediate(MS, p), col='dark green', lwd=3) points(p, pch=20, col='red', cex=2) dist2gc(LA, NY, MS) distCosine(p, MS) ################################################### ### code chunk number 11: geosphere.Rnw:232-241 ################################################### line <- rbind(c(-180,-20), c(-150,-10), c(-140,55), c(10, 0), c(-140,-60)) pnts <- rbind(c(-170,0), c(-75,0), c(-70,-10), c(-80,20), c(-100,-50), c(-100,-60), c(-100,-40), c(-100,-20), c(-100,-10), c(-100,0)) d = dist2Line(pnts, line) plot( makeLine(line), type='l') points(line) points(pnts, col='blue', pch=20) points(d[,2], d[,3], col='red', pch='x', cex=2) for (i in 1:nrow(d)) lines(gcIntermediate(pnts[i,], d[i,2:3], 10), lwd=2, col='green') ################################################### ### code chunk number 12: geosphere.Rnw:249-269 ################################################### NP <- c(0, 85) bearing(SF, NP) b <- bearingRhumb(SF, NP) b dc <- distCosine(SF, NP) dr <- distRhumb(SF, NP) dc / dr pr <- destPointRhumb(SF, b, d=round(dr/100) * 1:100) pc <- rbind(SF, gcIntermediate(SF, NP), NP) par(mfrow=c(1,2)) data(wrld) plot(wrld, type='l', xlim=c(-140,10), ylim=c(15,90), main='Equirectangular') lines(pr, col='blue') lines(pc, col='red') data(merc) plot(merc, type='l', xlim=c(-15584729, 1113195), ylim=c(2500000, 22500000), main='Mercator') lines(mercator(pr), col='blue') lines(mercator(pc), col='red') ################################################### ### code chunk number 13: geosphere.Rnw:277-291 ################################################### pol <- rbind(c(-120,-20), c(-80,5), c(0, -20), c(-40,-60), c(-120,-20)) areaPolygon(pol) perimeter(pol) centroid(pol) span(pol, fun=max) nicepoly = makePoly(pol) plot(pol, xlab='longitude', ylab='latitude', cex=2, lwd=3, xlim=c(-140, 0)) lines(wrld, col='grey') lines(pol, col='red', lwd=2) lines(nicepoly, col='blue', lwd=2) points(centroid(pol), pch='*', cex=3, col='dark green') text(centroid(pol)-c(0,2.5), 'centroid') legend(-140, -48, c('planar','spherical'), lty=1, lwd=2, col=c('red', 'blue'), title='polygon type') ################################################### ### code chunk number 14: geosphere.Rnw:299-304 ################################################### plot(wrld, type='l', col='grey') a = randomCoordinates(500) points(a, col='blue', pch=20, cex=0.5) b = regularCoordinates(3) points(b, col='red', pch='x') ################################################### ### code chunk number 15: geosphere.Rnw:313-321 ################################################### as.Date(80, origin='2009-12-31') as.Date(172, origin='2009-12-31') plot(0:90, daylength(lat=0:90, doy=1), ylim=c(0,24), type='l', xlab='Latitude', ylab='Daylength', main='Daylength by latitude and day of year', lwd=2) lines(0:90, daylength(lat=0:90, doy=80), col='green', lwd=2) lines(0:90, daylength(lat=0:90, doy=172), col='blue', lwd=2) legend(0,24, c('1','80','172'), lty=1, lwd=2, col=c('black', 'green', 'blue'), title='Day of year') geosphere/inst/doc/geosphere.Rnw0000644000176200001440000004033113472155746016445 0ustar liggesusers\documentclass{article} \usepackage{natbib} \usepackage{graphics} \usepackage{amsmath} \usepackage{indentfirst} \usepackage[utf8]{inputenc} \usepackage{hyperref} \usepackage{hanging} %\VignetteIndexEntry{Introduction to the geosphere package} \SweaveOpts{keep.source=TRUE} \SweaveOpts{png=TRUE, pdf=FALSE} \SweaveOpts{resolution=100} \begin{document} <>= options(keep.source = TRUE, width = 60) foo <- packageDescription("geosphere") @ \title{Introduction to the "geosphere" package \\ (Version \Sexpr{foo$Version})} \author{Robert J. Hijmans} \maketitle \section{Introduction} This vignette describes the R package '\verb@geosphere@'. The package implements spherical trigonometry functions for geographic applications. Many of the functions have applications in navigation, but others are more general, or have no relation to navigation at all. There is a number of functions to compute distance and direction (= bearing, azimuth, course) along great circles (= shortest distance on a sphere, or "as the crow flies") and along rhumb lines (lines of constant bearing). There are also functions that compute distances on a spheroid. Other functions include the computation of the location of an object at a given direction and distance; and the area, perimeter, and centroid of a spherical polygon. Geographic locations must be specified in longitude and latitude (and in that order!) in degrees (i.e., NOT in radians). Degrees are (obviously) in decimal notation. Thus 12 degrees, 10 minutes, 30 seconds = 12 + 10/60 + 30/3600 = 12.175 degrees. The southern and western hemispheres have a negative sign. The default unit of distance is meter; but this can be adjusted by supplying a different radius 'r' to functions. Directions are expressed in degrees (N = 0 and 360, E = 90, S = 180, and W = 270 degrees). If arguments of functions that take several arguments (e.g. points, bearings, radius of the earth), do not have the same length (for vectors) or number of rows (for matrices) the shorter arguments are re-cycled. Many functions in this package are based on formulae provided by Ed Williams (\url{http://www.edwilliams.org/ftp/avsig/avform.txt}, and partly on javascript implementations of these formulae by Chris Veness (\url{http://www.movable-type.co.uk/scripts/latlong.html} ) Most geodesic computations (for a spheroid rather than a sphere) use the GeographicLib by C.F.F. Karney (\url{http://geographiclib.sourceforge.net/}. \section{Great circle distance} There are four different functions to compute distance between two points. These are, in order of increasing complexity of the algorithm, the 'Spherical law of cosines', 'Haversine' (Sinnott, 1984), 'Vincenty Sphere' and 'Vincenty Ellipsoid' (Vincenty, 1975) methods. The first three assume the earth to be a sphere, while the 'Vincenty Ellipsoid' assumes it is an ellipsoid (which is closer to the truth). The results from the first three functions are identical for practical purposes. The Haversine ('half-versed-sine') formula was published by R.W. Sinnott in 1984, although it has been known for much longer. At that time computational precision was lower than today (15 digits precision). With current precision, the spherical law of cosines formula appears to give equally good results down to very small distances. If you want greater accuracy, you could use the distVincentyEllipsoid method. Below the differences between the three spherical methods are illustrated. At very short distances, there are small differences between the 'law of the Cosine' and the other two methods. There are even smaller differences between the 'Haversine' and 'Vincenty Sphere' methods at larger distances. <>= library(geosphere) Lon <- c(1:9/1000, 1:9/100, 1:9/10, 1:90*2) Lat <- c(1:9/1000, 1:9/100, 1:9/10, 1:90) dcos <- distCosine(c(0,0), cbind(Lon, Lat)) dhav <- distHaversine(c(0,0), cbind(Lon, Lat)) dvsp <- distVincentySphere(c(0,0), cbind(Lon, Lat)) par(mfrow=(c(1,2))) plot(log(dcos), dcos-dhav, col='red', ylim=c(-1e-05, 1e-05), xlab="Log 'Law of Cosines' distance (m)", ylab="Law of Cosines minus Haversine distance") plot(log(dhav), dhav-dvsp, col='blue', xlab="Log 'Haversine' distance (m)", ylab="Vincenty Sphere minus Haversine distance") @ The difference with the 'Vincenty Ellipsoid' method is more pronounced. In the example below (using the default WGS83 ellipsoid), the difference is about 0.3% at very small distances, and 0.15% at larger distances. <>= dvse <- distVincentyEllipsoid(c(0,0), cbind(Lon, Lat)) plot(dvsp/1000, (dvsp-dvse)/1000, col='blue', xlab='Vincenty Sphere Distance (km)', ylab="Difference between 'Vincenty Sphere' and 'Vincenty Ellipsoid' methods (km)") @ For the most precise distance computation use the 'distGeo' function. \section{Points on great circles} Points on a great circle are returned by the function 'greatCircle', using two points on the great circle to define it, and an additional argument to indicate how many points should be returned. You can also use greatCircleBearing, and provide starting points and bearing as arguments. gcIntermediate only returns points on the great circle that are on the track of shortest distance between the two points defining the great circle; and midPoint computes the point half-way between the two points. You can use onGreatCircle to test whether a point is on a great circle between two other points. <>= LA <- c(-118.40, 33.95) NY <- c(-73.78, 40.63) data(wrld) plot(wrld, type='l') gc <- greatCircle(LA, NY) lines(gc, lwd=2, col='blue') gci <- gcIntermediate(LA, NY) lines(gci, lwd=4, col='green') points(rbind(LA, NY), col='red', pch=20, cex=2) mp <- midPoint(LA, NY) onGreatCircle(LA,NY, rbind(mp,c(0,0))) points(mp, pch='*', cex=3, col='orange') greatCircleBearing(LA, brng=270, n=10) @ \section{Point at distance and bearing} Function destPoint returns the location of point given a point of origin, and a distance and bearing. Its perhaps obvious use in georeferencing locations of distant sitings. It can also be used to make circular polygons (with a fixed radius, but in longitude/latitude coordinates) <>= destPoint(LA, b=65, d=100000) circle=destPoint(c(0,80), b=1:365, d=1000000) circle2=destPoint(c(0,80), b=1:365, d=500000) circle3=destPoint(c(0,80), b=1:365, d=100000) plot(circle, type='l') polygon(circle, col='blue', border='black', lwd=4) polygon(circle2, col='red', lwd=4, border='orange') polygon(circle3, col='white', lwd=4, border='black') @ \section{Maximum latitude on a great circle} You can use the functions illustrated below to find out what the maximum latitude is that a great circle will reach; at what latitude it crosses a specified longitude; or at what longitude it crosses a specified latitude. From the map below it appears that Clairaut's formula, used in gcMaxLat is not very accurate. Through optimization with function greatCircle, a more accurate value was found. The southern-most point is the antipode (a point at the opposite end of the world) of the northern-most point. <>= ml <- gcMaxLat(LA, NY) lat0 <- gcLat(LA, NY, lon=0) lon0 <- gcLon(LA, NY, lat=0) plot(wrld, type='l') lines(gc, lwd=2, col='blue') points(ml, col='red', pch=20, cex=2) points(cbind(0, lat0), pch=20, cex=2, col='yellow') points(t(rbind(lon0, 0)), pch=20, cex=2, col='green' ) f <- function(lon){gcLat(LA, NY, lon)} opt <- optimize(f, interval=c(-180, 180), maximum=TRUE) points(opt$maximum, opt$objective, pch=20, cex=2, col='dark green' ) anti <- antipode(c(opt$maximum, opt$objective)) points(anti, pch=20, cex=2, col='dark blue' ) @ \section{Great circle intersections} Points of intersection of two great circles can be computed in two ways. We use a second great circle that connects San Francisco with Amsterdam. We first compute where they cross by defining the great circles using two points on it (gcIntersect). After that, we compute the same points using a start point and initial bearing (gcIntersectBearing). The two points where the great circles cross are antipodes. Antipodes are connected with an infinite number of great circles. <>= SF <- c(-122.44, 37.74) AM <- c(4.75, 52.31) gc2 <- greatCircle(AM, SF) plot(wrld, type='l') lines(gc, lwd=2, col='blue') lines(gc2, lwd=2, col='green') int <- gcIntersect(LA, NY, SF, AM) int antipodal(int[,1:2], int[,3:4]) points(rbind(int[,1:2], int[,3:4]), col='red', pch=20, cex=2) bearing1 <- bearing(LA, NY) bearing2 <- bearing(SF, AM) bearing1 bearing2 gcIntersectBearing(LA, bearing1, SF, bearing2) @ \section{Triangulation} Below is triangulation example. We have three locations (NY, LA, MS) and three directions (281, 60, 195) towards a target. Because we are on a sphere, there are two (antipodal) results. We only show one here (by only using int[,1:2]). We compute the centroid from the polygon defined with the three points. To accurately draw a spherical polygon, we can use makePoly. This function inserts intermediate points along the paths between the vertices provided (default is one point every 10 km). <>= MS <- c(-93.26, 44.98) gc1 <- greatCircleBearing(NY, 281) gc2 <- greatCircleBearing(MS, 195) gc3 <- greatCircleBearing(LA, 55) plot(wrld, type='l', xlim=c(-125, -70), ylim=c(20, 60)) lines(gc1, col='green') lines(gc2, col='blue') lines(gc3, col='red') int <- gcIntersectBearing(rbind(NY, NY, MS), c(281, 281, 195), rbind(MS, LA, LA), c(195, 55, 55)) int distm(rbind(int[,1:2], int[,3:4])) int <- int[,1:2] points(int) poly <- rbind(int, int[1,]) centr <- centroid(poly) poly2 <- makePoly(int) polygon(poly2, col='yellow') points(centr, pch='*', col='dark red', cex=2) @ \section{Bearing} Below we first compute the distance and bearing from Los Angeles (LA) to New York (NY). These are then used to compute the point from LA at that distance in that (initial) bearing (direction). Bearing changes continuously when traveling along a Great Circle. The final bearing, when approaching NY, is also given. <>= d <- distCosine(LA, NY) d b <- bearing(LA, NY) b destPoint(LA, b, d) NY finalBearing(LA, NY) @ \section{Getting off-track} What if we went off-course and were flying over Minneapolis (MS)? The closest point on the planned route (p) can be computed with the alongTrackDistance and destPoint functions. The distance from 'p' to MS can be computed with the dist2gc (distance to great circle, or cross-track distance) function. The light green line represents the along-track distance, and the dark green line represents the cross-track distance. <>= atd <- alongTrackDistance(LA, NY, MS) p <- destPoint(LA, b, atd) plot(wrld, type='l', xlim=c(-130,-60), ylim=c(22,52)) lines(gci, col='blue', lwd=2) points(rbind(LA, NY), col='red', pch=20, cex=2) points(MS[1], MS[2], pch=20, col='blue', cex=2) lines(gcIntermediate(LA, p), col='green', lwd=3) lines(gcIntermediate(MS, p), col='dark green', lwd=3) points(p, pch=20, col='red', cex=2) dist2gc(LA, NY, MS) distCosine(p, MS) @ \section{Distance to a polyline} The two function describe above are used in the dist2Line function that computes the shortest distance between a set of points and a set of spherical poly-lines (or polygons). <>= line <- rbind(c(-180,-20), c(-150,-10), c(-140,55), c(10, 0), c(-140,-60)) pnts <- rbind(c(-170,0), c(-75,0), c(-70,-10), c(-80,20), c(-100,-50), c(-100,-60), c(-100,-40), c(-100,-20), c(-100,-10), c(-100,0)) d = dist2Line(pnts, line) plot( makeLine(line), type='l') points(line) points(pnts, col='blue', pch=20) points(d[,2], d[,3], col='red', pch='x', cex=2) for (i in 1:nrow(d)) lines(gcIntermediate(pnts[i,], d[i,2:3], 10), lwd=2, col='green') @ \section{Rhumb lines} Rhumb (from the Spanish word for course, 'rumbo') lines are straight lines on a Mercator projection map (and at most latitudes pretty straight on an equirectangular projection (=unprojected lon/lat) map). They were used in navigation because it is easier to follow a constant compass bearing than to continually adjust direction as is needed to follow a great circle, even though rhumb lines are normally longer than great-circle (orthodrome) routes. Most rhumb lines will gradually spiral towards one of the poles. <>= NP <- c(0, 85) bearing(SF, NP) b <- bearingRhumb(SF, NP) b dc <- distCosine(SF, NP) dr <- distRhumb(SF, NP) dc / dr pr <- destPointRhumb(SF, b, d=round(dr/100) * 1:100) pc <- rbind(SF, gcIntermediate(SF, NP), NP) par(mfrow=c(1,2)) data(wrld) plot(wrld, type='l', xlim=c(-140,10), ylim=c(15,90), main='Equirectangular') lines(pr, col='blue') lines(pc, col='red') data(merc) plot(merc, type='l', xlim=c(-15584729, 1113195), ylim=c(2500000, 22500000), main='Mercator') lines(mercator(pr), col='blue') lines(mercator(pc), col='red') @ \section{Characterizing polygons} The package has functions to compute the area, perimeter, centroid, and 'span' of a spherical polygon. One approach to compute these measures is to project the polygons first. Here we directly compute them based on spherical coordinates (longitude / latitude), except for centroid, which is computed by projecting the data to the Mercator projection (and inversely projecting the result). The function makePoly inserts additional vertices into a spherical polygon such that it can be plotted (perhaps after first projecting it) more correctly in a plane. Vertices are inserted, where necessary, at a specified distance. The function is only beneficial for polygons with large inter-vertex distances (in terms of longitude), particularly at high latitudes. <>= pol <- rbind(c(-120,-20), c(-80,5), c(0, -20), c(-40,-60), c(-120,-20)) areaPolygon(pol) perimeter(pol) centroid(pol) span(pol, fun=max) nicepoly = makePoly(pol) plot(pol, xlab='longitude', ylab='latitude', cex=2, lwd=3, xlim=c(-140, 0)) lines(wrld, col='grey') lines(pol, col='red', lwd=2) lines(nicepoly, col='blue', lwd=2) points(centroid(pol), pch='*', cex=3, col='dark green') text(centroid(pol)-c(0,2.5), 'centroid') legend(-140, -48, c('planar','spherical'), lty=1, lwd=2, col=c('red', 'blue'), title='polygon type') @ \section{Sampling} Random or regular sampling of longitude/latitude values on the globe needs to consider that the globe is spherical. That is, if you would take random points for latitude between -90 and 90 and for longitude between -180 and 180, the density of points would be higher near the poles than near the equator. In contrast, functions 'randomCoordinates' and 'randomCoordinates' return samples that are spatially balanced. <>= plot(wrld, type='l', col='grey') a = randomCoordinates(500) points(a, col='blue', pch=20, cex=0.5) b = regularCoordinates(3) points(b, col='red', pch='x') @ \section{Daylength} You can compute daylenght according to the formula by Forsythe et al. (1995). For any day of the year (an integer between 1 and 365; or a 'Date' object. <>= as.Date(80, origin='2009-12-31') as.Date(172, origin='2009-12-31') plot(0:90, daylength(lat=0:90, doy=1), ylim=c(0,24), type='l', xlab='Latitude', ylab='Daylength', main='Daylength by latitude and day of year', lwd=2) lines(0:90, daylength(lat=0:90, doy=80), col='green', lwd=2) lines(0:90, daylength(lat=0:90, doy=172), col='blue', lwd=2) legend(0,24, c('1','80','172'), lty=1, lwd=2, col=c('black', 'green', 'blue'), title='Day of year') @ \section{References} \begin{hangparas}{3em}{1} \noindent Forsythe, W.C., E.J. Rykiel Jr., R.S. Stahl, H. Wu and R.M. Schoolfield, 1995. A model comparison for daylength as a function of latitude and day of the year. Ecological Modeling 80:87-95. \noindent Sinnott, R.W, 1984. Virtues of the Haversine. Sky and Telescope 68(2): 159 \noindent Vincenty, T. 1975. Direct and inverse solutions of geodesics on the ellipsoid with application of nested equations. Survey Review 23(176): 88-93. Available here: \url{http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf} \end{hangparas} \end{document} geosphere/inst/doc/geosphere.pdf0000644000176200001440000067650414335012510016445 0ustar liggesusers%PDF-1.5 % 1 0 obj << /Type /ObjStm /Length 4416 /Filter /FlateDecode /N 84 /First 673 >> stream x\ksDZ_1"~b罛Jʒr亾q P -sfvz @eRT 1=>=2UVi*+ozTQEN/իJJkM"Cptg{2mC hq2ޣqLXYٖڢXemh,<(.*ہO)ۣ2.]bhZ9tbYV9ЉS ^zS.zF:~{ʷl* z8C;DAء$BR aZ0DU-ZN LT:*"A!m❊}b-~;j9{h.vTGޡTaR8%-&t6;L5 b u-jPv=dV{j^cAB>u`nFUǥ9V(V?jbܬOX+?>?ɳb3[ZңɷWkV}5]&Wil^jh?W3ֺ%sXVQu/ѓ՟&?6úY.&6W/wՇftru>[ $Coj̝m3̬i]b7mo`QM|o#wL^NI9[6Vzr9\.͇ˇ bkMb]`q%-/Vӫ&2b,fÙ^k Rh1x14k2`p = vԳ&ۯV˳325ys4uN&ݏM^oחwԵn}U]S.Ζw|ftZoX64BNNZq8V|t-ڴ-t]^Nzc<,Xq 4^ gĖIs1+a[P-)WжT+MA;u{ۂmAfMRܻfAf\_ >z햠GSI5q*3j5f nAC4ܳGO1htG ."-VHe6aly !|3?_:yL^&NGb Ln.t4͇a03\hK5uױoa`Ú=Vo !P%䊘ܳ2φ{_|.2^l^ᎷD"(hUoh},~Fqݫ[EUx(|^,<6d;U_0"U=2Lwݞtw01N|X;Ǯg!Ľ*Z#wG[Nh!d.\ԡRn `ֽn\1w_?9hw U;p}-U>TU8Zw09{'pzՇRO>4<{/V 0-.b96_&~x/_<VYsu6Jx4&O:oxcAo۾s;NCm~ݚ!;Zp&#B5W?gk O)B2)[Ipf/ j巕߲nַ9v4wE &;ZxZ `N, ˂-:6BXpyl³g -<[`A-Y.6FMǷl $e`"Ev-md\Yx%o;1TrA;r߱.0v#}UO^rA9zKRҤҦҥҧ22KejS[V:թNmujS[ښ֤&5LM)9!8z8bK K+S,.a$0_IáR^Vxpi+h;$`^0 /m O[QNx;ᅧbRXAܣF>  DT_ C{Z‚cL6/HP/xW@IgLt9MСpYvu>)z#$rc- fq# 7bLZ`Ɋ`B 1r8QFL,#v;͈}{,0ʜbȬ6mĘ, İLb0QB SG 2b0Y,C# 6{gt͈53peĘ2NRe;]>h0i &'3k H.ᔻޘ؄FO),p4Ccv s0:4X5i|ÄT̅u*ͤnz+7W 6ML&gk.ˑZ`k FA6]>@29U\SS0twSڦJV^ZŖ#;?Fՙ ( &U3if|F(;ޥEAW[,a"Ns_ ƍPHm6B!VmBhDq( GX>a#Pܗ#?B!x ^%5 ^E<R%x#jĩb8UTlTq]8Uhq, &[q8UqqTũ"SE8.Nq\*8Uqqũ"SE8.Nq\*x/VվX@5̗cFSp/Z i HZAL- FtX1ّXhTmڶrmm[V3LGNڢS0Vl3̀Օkk6à[:זckKjb.mo4DȍN|Cm=|<( mjqm\UW(t}楏 )^76{5=?c)=tm6O 9i)ཱིUb2? #`T o \B|SQFh~V=ñWD3֠*/7w1=ԏKtCpj`.g̥m8XVU079©s BV[s{EU0W\Ws= V\~Ys`̵0Y~@uU պ*j]H ZWR"ToO@U ՊFІomX  1@bPA.G0 UӊA,Ρz! @]ޯ9mkp7Xpo3N7` plyK3fg%};j{55ɰ+]}SM=kTثOjk|^[o%݀N-nh0j~]GI:ec}tdc}tdc}tdmIl&f-Y􄘵bROtI'f-81kiuUǎg@] *VBljț&}_8]vKkrXj [DnŔ5}9Pgx9Y ^'?nYϫ*"`޲}Z_لGճw[%ű+XOƖQG2;~qiэ^dL_-ۻ caqn1, =i0aqn1,=Pmvpam8qF**  fx0ވŘ8\ 9JTKu &` ח:t9QOPvLqvb}۞({*A O 0964(K7L iv[,%5IIlͯn|$-bs\)Qs!vya=HL{6L/5޼_ԓYͦfdZcmǶc6/of?{W;f4}^˷bo W؍kBӪ<$_MrӡIJL{|s9W\MO/)9endstream endobj 86 0 obj << /Filter /FlateDecode /Length 1932 >> stream x}XK۸W( 3[$k'z6C6 aS fvT FMf16a#DUe&TUl?6ɣ ͥowJh=a<ƙL8OfIfÏ2R]"E%KV{ſn22nKd [?x#L%hl)8T*T_{0!H? I#I] Ud|ӰGgN?a)R$MIӍLJs2e'AZ\5i"K۝q*$1ID'9 ".elTh&$jX;fd# }=y<M:gؘ";{wo* ҼTIdOΜL;AС9#1{h臓3.=7pGϭyC"VROL>Ȩy;.fy?zuȣVGg3=&FP uxwΟЎeip^ΟK5RF4 bu$ \;P0@TE#"epЅq.X)8|Ǝk}ZKy^;|NgOd"q j/n4TP|7GuuGIXvp=j#+Qg!*-Đ[Z }b̚-[TȰlHlƳ,^,)8 •Xob̘'8 wS!f"@79y ۈ5~ƴt.\ھ.%5NXx$ 7@[x~pa|="o䙜(t_cY˛GgvP#|"j_`:P,ku]eq_/_Y|4N9XoEߩ}D^$ݰ]3P(ګ\cܟ8Si {3Za>jeғBAb_tr d{fu[ OW|](UH&CJ`޷!8/@47e:O]S,mN/ӓ d'ۑX1a:5V#+?O$E 7t-2;`B*>0:j=ĈT۫|,}EU}bFMļ{ ZTЕA+P&_cixAWߏg#G-* ._xmz٦q 9Nگ !Ja^T0ecFlϰqY4#3i Cyt谩}f5QЖi^k/łSCi!Ҽ|GYOg46pYћiwDz{RRdE1`^s`͇Û9~ endstream endobj 87 0 obj << /Filter /FlateDecode /Length 1618 >> stream xڽXKs6Whr՚ ٩;djOrhzHXĔ"U>w%Ytdz1>]@~}ջ0\'X,^8JSHi  3 RՏ3qߵ[^ vJbP.9Hu1.M ۬xbΎGŎ ^Vl霡٘eRKM(Cc#1hp=q]R%멭+$fC t?z`1}0oqa2 iZzCRpE,SFuW;Z}DMw`6dޘ:U8ü$$0v;*7?(s-Rzh2tC![Ocw&NįЄ T>״.ir, L398E0# &d_D`4$ OTV{& Z&tm^׸EH=Xvdqlq6xc Hn^L+sdsE;%,H4l9O" 3=̌~4VnT8zHXGd=y$T쥓@Rp9)9~ %4|Ͼ}k އ˳<0{e`:6DR7"=GO̾^Suw{բ~aЍ49vc?-h< Q!d.)a\2"Q5%o^Z7%o 0%{Upn}:c`M? ߚ}wf q|omlެ.p׸B\+a_Qhʯ ~ʂ\B]r[_fȎ1&‹pK Y\3Z"/NVb\z{Mr1?HUq4<ƳK4?8w7f;ya}{7#{o̓\u"=_^Mʨ`Q4a @·?Dlu3%.cyB& M=/ٰg-> stream x {8xHՎ]vώU1?pħm$F~b˹B2fq#q ,K_Y6h%T˲$׽U\ǫǁ*ZU.\úq\5*tW+tEL8jsu9WG?*"\wY+ wߍل-k QBWqr5]>%JIJ}gku]KzW!+Еx%GWnꅛL2圏ۑl160] 2]W@W^(s?Е| rvf3\|Wj"BW+tWpWpWpWpWpWpWpWpWpWpWpWpWpWpWpWpWpWpWpWpU ] j \!6U+t5Ѧ*`pgU 0+}03 *`pgaٺ/G9ݹ3+"38qJ 0,|8x‹!XnGmq3 jt<&b;\i(\+tg%AWx9^π 媼r38q_I]v^4k"BWnuu) .eן'tgph1I-1y''x‹f9πg?Oe]FUxt[WSyGtvt&U++t<^iէU֭+πUi:' +t,l)N>7K<ǻ|D#]υ{Z,WbOLW#;qbGӎ[y}PcVWMxnj]]NrU`g3ԣ|WYKMn3\/IXe=ۧ 㢦ؾnd#֝uS╥g DZGRʚ/j _GU3;&kvr/]|8+ܹ0>r]yU-]3륫Z+rf[ slPX}g a=L\u|;ar 7AyQ);a^T"o(w~xES+[@SU+KπChS k▞*yΝs(\6ZA+CFW+ȝ=peڙWtv+SV3=3;{W] vu\xte᪗gPSRОz+YO2gegV]3]Jnj3̭Ѡv:jQU8tg=WEWsmֆ3+ng= uWpWm4pË2WX,એgO!ytjZ4ijUX_v ]{ 5t kL3,eW_hpUΩ.0%W̓7>Gv t~5W0WtJZY*˖s{l"Ϡ_*s~OgL|?` [~S/bj:3չ:+rQ=?(M44s%_j@}J>SgݿHB]7ݲza tUJ(R[s[RVpkhSe0r=K~Y%)%^ a_$+tٔ㍲|楻#9EuHY6#4u䔕i\r>h,WtZEūsR;K4]%u8Ers3T5+uʝJ:]M⯜yjX:ͻsO>h.!|Zv6טL=м<&cxD3|0s2@/{l=Y PH*ǝ˖J:W!ҷS7Vyƺ2] tei\saMWY0a_Wpmnmfƺ 㟫fYfZ]9W>x:\\My!*ڰW3-g^MմN˓g0SFj:]T*]Y?-Wj*N쯬<5r5Y>h9` UDmKPsWxj{@́{jٗѷ㸙 "Ɛpo]:^+aegծc.O՞5<5>g}pEXUσ> 3,,AWyxƒEɶv] <2/g@Wxtg@WpWpWpWpWKJ_1 ՠF**ʆ}WNh/j4K/uV僚i3L_VREK5q+RpZIdl?,RWmX]W 6a>8+t5ˏ(tu*|psռ+zy|yQ}8ճٕ" Sh_*\+hy3;s23u*26uȡfJ~|Q>hS$ɥ/ֵ Ɖ]bFW̋2)*jڡ=5,eSs?`StodJz]ͣѩ Ѡnb@Y2Y\v~ qq% 箟VU>]Wb`g\肜kL6sjr1w6XT>T3&SՙZuU:vX_%:u+14֗Q(h`d8"AI0e>g>(֊ZS{SAx ҷ혿Q;֞,2}(v18)1qUz}2֐;lorU誊A <V47ZZkU9ʒl aǡU!Ǻ٣ЕŋZ@ Z83 ]9q%DZte"rgt4j&%:<|4 W^ԩ/tʪִw@Ws_܏tuo{ |B~LlxcVKy:t xl 닙1E>(c[Kѷc$y䯘_m:zU3aGOʾW] )x6BW bwqBWq;+t5HX{5~<"^~8!pSގn^Ls? ] ~}W$G7$G7|P3^]+Z0WIYS|]9UGA4}ǯЧEWR]w(}'C Eg+]mAG/?>/&U8TmUESuȮG{9N; şʿ%r6zz;w<"j~kxZ% j\ߤN%W w~w凓lWK*^sW\粒S WJ,sT|l:QoXkWb!;\-.ǒG1ދ*$K]Ս ccUJ+?W*o1\VvCrfPu3{Ac}px䣅ƫvo S!&j\3a hyǕ \JZue> BuRdsh՛X<(/۟ ]5x'5]z~_6 ˒ꙿ*MxpVG{o4-QZ~kȻbJMj] ~r=?R3&G^"6Txqzˣh3LX3(Fs uݍ4Nc%7ݍ4S)-'-o慿_/˃רiq5U͠iU͍n~⥋([lLR|izs0{/}? Bgendstream endobj 89 0 obj << /Filter /FlateDecode /Length 591 >> stream xڥTK0WD{i"6Ǐ<$E!m\MJ~vۖ (J|R|I.Oa UpHC) ׸gf2hޖj#>opDnLoX&$ Y..D\S-[lp*,V½}m@O9+^?kE޴uMRuY@ڱ=yzdw[_0A!pHiEy1-L[1S5pmB8/ L.ImzT2%\7b؂d~zKv}0?HWCi/WW z]i~4ᛢ02)h7QLŹ7}Q&BLH$a,bFiP,"]! ;XFoM› (5br(Yl@B!"sOgD(j5YRu{11'/¯QL ~39!O&.h.=KO.׀HbxAF|<xendstream endobj 90 0 obj << /BitsPerComponent 8 /ColorSpace [ /Indexed /DeviceRGB 40 500 0 R ] /Filter /FlateDecode /Height 600 /Subtype /Image /Type /XObject /Width 600 /Length 5824 >> stream x흋z⼵6Ӛ ={&|WXK=Ʉz֧e!B!B!Bb*IMRyrCV|~B!jHh _q|ʸ A+@oGvoGߎ|f^!gߎB(<ڿ<$+$"Ԛ;b0E, nړVBB! ȑqg?BB!B!|yyyܤ.Õ޾+s A8\!qTX,$ֿ)!qbBEiYQ]i=,΀$S)0PE+̦+bPHB!*b:z$) h("^!bE+:X E+*GcF U\jWp%UMT1 5zUt1 1_M( ^E,7Jq\MD4υ:a?dxuI.!躰k uPpWU+`}nz W+aT+ƃrjkWkx0ypzȢ~\X,B..֥\MϠ9D;B +>4(Ax`ˁSr*\8Ak*pN +_n^٧P@ W,B.<.!cB+Wp_!ƃ Hc`XwY \pWp \Y؂+"ryJLpWp+~<Wȅł+W(XN[=k է~;dZ][W5Y)\ %;X]YXW[7@/ Wr +:WpnǃOc\,B.,ָ>/9+\ۑ4XOYÐp8`PpG&PoJ+BKO =N=peΐW\>$ Xꢚ+ƃL8.:J+UpW=$yW;wWȅs+"N`m>\"Qy}EBjO犺(2]$^5EpJ]TE]reꢖ*z+di>WڸdB#u XnJ_wXuD:zWG\@ Y+o Wȅ pSi ^!eN+$Trgp#橳j'CV 1{폇VGàuڶOzj E+̛fWEU@\9.C+M.z9ŗW|ʼBpE㻗^x\ۿkyUhi[<]W!WUPiu[ \!iu;|aR8UϪ)lv/UУAFѪ,\Wȁi<VErkpD,+d9콏p&v0y5}0 ;^_VpZ\ժ.\M` X=S dU>gRz=| -Sςդn!y00U> V: QWU9~U*JvW] ,┗Od<$vۋ•U1pe<TqSnƃpEWpEr+5, _}W[`b<8W)fB̓qVȔq<w/g1d_"^1O/1O?AU`XQjBozs^X 0M`K*\1}\_ +K:n8/_%dQƃm\{YmU fH*j6C\EIEo f8W}*B&E@|ї_D&^e+|g2_􉭂 Ah\EY򥃓\W*/;Ib\Iv^>{oq۪ z&!^xefQ%ulf"\re&Ro+ASN[v]T*`®tpI%ղ/ WpWpWu® \yع®;~bj]:vE[PS;PmpzHWpu㦉Tylx]Wp; :CVV\?aqNkBfW*sdWqpx0sjn|Y\}0|0 WJ][ Wͼ@pWaEEWBt.0Г񠮋7?WW ,pqq|=\! EWcj[u?rc=W ,\\ Yui})x%rE>>:W'$5A3\խA\!.l u^WЄ+Az\-~W 9. WWH4JLCf<W,8qY:\\_ѱpxJesWes>Eu+W)\!t+`x_Q*2Lϼ Wo_~(0:CJT hEQ8jƺ(a*LuQlU\vYpWp56 ε6\_O9WJdb7 ~WP,Q* ᪢W"'/%(B \A_}w  W֣Aƃp5e)xD+EIpjPrW/ Wv^9uUd\9[Z]x0&wTR\[lQ*RjWer޹ ryj};\E:tyWs䲫W`Wr\4v Էh`==ΠYIOj P=_U2`īxuڶ⚾-\]bW֥rU6? gAn:!{!4ABjW^$/ ]¾#5ZGַKGZ2ƘIbQț^ 2 %Obm}u6UV5vڹb̛Q\ 4UT72oA:mu4W%te5TyyW)Дy0!{u&FUЃV^onKګMvlǍz+Mo۹bD[C릊MjkzN3ZyK[Rw_b}m;_^~|4WMjw!LFQ%˶:,2#dצ3;UsŘQeݭUSS@-BXYxʘ.\ ~!Wqv"\e&JpuЌɕwCH\eASgȃ*TV-Q<(r{\]4oel۹bD!LGj߮oKWIպ+nj.Zڵ"u2w3ʺ\p%t]̓^"uQShJvju[\]sx&/dL[yse[uyےɊy2Eb y2,` B b By2!Ĵ~\%(DI,B !|;·#B5\b?dBQ¤Y"fB!u67d~;R0COQeyu]Q[a񋇝̈Zؽ~>. _wZHAgwBq y+}O#pp5H;;+i݉{#*}UpUyi*:_C=͛lS͏Զ?j@2{_׷dY7տkr[0|񩓤mMuBsuHF]Qriچ•5׃UT}6i>y_R]o<[1pރ7BZk"gojaC+}M_TǦe }BZՆm˷}\ʻ+߾Nֻx Zoθu&K>q֭T}Hse5]ߐ5*MTI+iao .=9~AvurLJyr5W .qIYAqu݈y.WgaیīnlNQO[j^\v(^fO+괪씺)^³W:ބxM ~]tGZ~q.͸0W6w ]\רMukre˹ף.W;(Q6^!ץ.j6ΪWd@@Mm+}Gr2S,ͻM݌\;lν]qu]*J<,ŨhsR^z88}%ӶiG]C 2߉o~Ux ѧQ> stream xڝVMo6Wf C_hS`m[,e-1PYr%i}Җ(tp8||8 <4<+^2hT+,6bb%,_uǍ'WJRf, * S"!SQ~byw }?jc0*a3*ͨeWZq jmv|P?ʄoB+E \1g02dȣ$ "Nþ"z, Yn%5U3T~>3J Z"C MRMD(qذR5 ǩ JN8 As8[[П- h5AxX&.2M!g asDezc$\thåjH'1eWx%bM%ēKʻewJ,d!?5CDl.I%uڱG|,LpM;M %OSۂ.BAU|78Q>u1>d"hHx3հW)7#w EX}1_X;]^WٹZAV/nAm4 XXN5j:MiC+Hb/]TH fR[ᄅ,zc+m;S `o @çҔX Jo8e őB=xƠ 5}\w p"ϧ]$;=^b'7 PIS<ĹaUIcOŴ'@j?FP'cc%Iȡ "A|(԰%T(LB Zjiv>mFudAwNr@)eWb4J ch .^A~/VM$ݍE hm+}s(7c>ON~>P(RJ'$R3S m& &T3Q` 7^S)%,N2B)c&|m^dS/F"#~e6z %%YQ\ (R14愖) 3&n?D endstream endobj 92 0 obj << /BitsPerComponent 8 /ColorSpace [ /Indexed /DeviceRGB 63 501 0 R ] /Filter /FlateDecode /Height 600 /Subtype /Image /Type /XObject /Width 600 /Length 12046 >> stream x mݖ쵣(J\Rg'ZTGW飊 fUx˳3]]@P( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP(˝upA(B"WrE!W\+ +rE\Q"WB(j\#EJܼ4s:`aqABI;܎<6W J!4$t3DѹHlzn0!p߻հj:|l\cw{+.x^³̹ _,4XaIEj~-զn2J 6 5SnaCqu{]14Q恮]=,1eX5 \ au!uGv0~J5W]zn0-aWWw~7fֱI);֏;oVغsh\bk̕q1eB 32\T7vH’ksR@rsʕ ଻|u*)T쨯Sxh#gūpkhf {-RV8Pxl}eGѦ~\ŧAfޛ]"S8e Is>mfyQƟu@;h~Ʒ#ʗc.h6%Qc`KReFcp(%g4R?<܀L纷Ujbya!{j*e+>0{ړg<-RR͌ģOJЂ\ r,r6bAamѓa̭8XP<1? ڢ+*2d/#^+J[іxdݨ9+vHoqGKabP+ cLoզm,h[κHGG#Z".39Zq  ks vŒYr!7Z6eq ;l vW;U[p/sT+Bu D 6]Unqep: {MW2ٍVB (>ٹ2xU|) SpKћ+h\/NYrJS%#K.ޚ+nW2w+ ݣs`eEApG͆cd+ !0̬vR*uaj 2;FqehTs܃\(}X2Ua+#4zWqwCV Vs+˴ 8 8dИp,$^냒+9wO:; 2?asq\H4g/H\Dp97\(OM(E/C_e<* +0O UQַC{b|ЇfIi)M AݘLЩ-тA=-args5 G11WjzAG:i U.7'oJxEzKʭI PL|f9*q% 5򾈇6u@kxSoh@St"Ŵ ͑Pҡ;;[sXu ]rs-N-MΚps.D,7~eUZ=@`Ǒ8Sd){ VgU( ęJhN/ ((:Ev5`EZ*H\2*9`U`w{5Wݯ`BB[F'Y~~*!o""PXjaTAC G*Zu\uIIKJTA(XTB,-$Ga)VyoO: c@e%EwIgK ),{9%sخlRWW 97P YkLPu]&*,2ͫ|S[Ѹ3~*V6Xο,ZWB@S\BJfE+YZ)3tvo+UrhOpQiC pEӖkiaԂ*h@id hР|\=xSs±\Z9qVhgxC*W0ac5!W/4=U a'JTMꡈdJ!0+}qۏooS%t3kwo@K2# UG_ ZUoxRKyj鴒;N}EAIVw.?|!߿jmؤE> 'i< %D$_U3jikn_]'K/ꭚHDwҪ 77rtc8L_˞K憐rvw[N,@%7Yef~@woHWwݽӲAGf4bdL๖8W_߾9Ǯ֢ iDn׽n>uԉ2ⰁD8DBbn%o{]U+QK ڔύP-m5 8X(m%EeFqPCI\c>/T. 9&PZ_eaզGkWUKm*b7dV8Aw\Y 剽^< MfZڭE^lyuiz:hÚװWi:Aa"7C aOM8nlrh%WP =aY`.=_ٹOvj>F~]2Ch;YK2 \Rz" ]I eT24"B8gQ('+k5Z㖇 >"Y쿒x\~}W0oVq]|d23;D ~WX ]797_1A\93{tʭ zuW|(䪑+?ݮF$LjT'vJ(y,HDN"MUY^ Nڠ< 3K"=u8u}+![LFpL|G*jW\קOG濾 *,EW@ RIo6m))£Pyoz%R ۩D'JBF&1O\N]/GYXv`{8KƺSQ4Ml+@%W_+W/~t / ,/+lL][Umr鷿3_ӧ?8W}r\rO -Z#WtX=WY}ͯoo_~.?p_h!=Ք2D`{`ȝ*Rˊ\|n˿yj 7Huz߃ckeU>_/PVO+mRZM]Mk3Xr-NϞݫONZ=L;AeFw.\x͟}"r6-ijud%Í:4tV謮 17VM&&Lũr\E٦ \Ӟ٤BD U?IBD_BX퍌8֫)Q\EYPeoxU\RΒ 痤{tDd}Y6ʹt1ZrNRu.|U5X~)P$tK:2ՆОj}4.(KĚhU4PBIJC/; :/KUE΂m [%T;j@>պWBU_]D]9Vnvtf (W5\Ja}>FU)K G̠yZW"1o^Vη!B,/]f[k%d r<y11Q1ֲ#Vc:6w ΁:eCsB+ʤ|-݇ 5,PX qs-K `V#8r=BI/ϣj NDFcM%+1H2DJpe9WVy$Wr=+"*!9O脲I7J=4F"k}EP?uۂ 7'E eAb or0j@•2bׂliOLwN}w2x֨}+Zeo-<"VP q/]j^wbUFY@ CaG }2P~`˹2ȸXiMOrlm*ql}u p/Mڬtk)iV^tO&˕&.sr0zwth#pp UDjvUd>?/HλA_q@"FdRƻ @teZ (u3UOrt*D k Y!> Oo"+M'b*+U^X[f bڵ_*szlBY/F-.\ȉ(,QX4m>UPWz"=!Q+(RڑAPox-z1J Rb0Yr2׮pڬ6&k=BΗ+JrPavwFa>WYԼN$BFxGE?GQBVX b_ z/p{< dYn:uF_+G",+e 5 #ށwA+*\^dX">_dQ UGcn&w#n*p!5;( kPv õ'jHP uаJT6ÿ4Jq :V0PB׃U8U!A(7 ͓a;3@7U),ju )y^_9t'tЀUq_^.Abi@ґ2B9 V߁%%: /Ε\vTCfrڹ(WM÷?;Xv@ :2B\eFB$t!a ƒttNtokaKr`O,"C 9k'KcEDֺ+?H18X( g= R_Ấ 䪩tcWL ځ[iw\}~t*Yha"C{u`,:+L}5ʼn5e:),rUI 8N0`UvBdKpKXiD&S0v$] A-UΙ :+Qz 2D_rUT#;'@t=0&`>W`\'Vv`Ǡl@Xl-қ޷, \j93`Aߎ:]\8W]zCWșgY_uJLП>u=et"٨ٛ/T:h3^ꌕ̎)Յ:Ad8?ªseo_ӹ2?W&P\m@y\1wԼUnG!sKp.ӊ%Xv_dz@zO =rĻtuBI4S}\(\`e { =e$sp 0\ Wbv PcaL=puƕupzo *G)*lQeZȳ9o˄alm94TCaqlDA,ZrBƪYIwWG+/UO~i䡘kО ʽ[oj V{$F#X"4KtdyաG"ۃ+ߨX|Ɛ}^/?9WMؙBw^p!G~$*4sYS=su\i- n?k5W!bxӛ𯾾rX ~p5PCM\Fb㡗w˛JwW\}F_J6~6m1)g]SxgyPL FU2Xx Al%"`!+Q_ 4UL5/<NFߟ[:{cJջƯ^ /AaCu-q"^@$8w6*."juH^2+5OKz2Hb(VW)y }u:m}eBRK r^;WN+Bw#&.)U_5=:ɚ&*1ۇ;}Դ1p6inבT#(*iBbHǸYWzmM.Czr+(ڗ3k=yRڒ+O KW8i8bpTO|- `?ܗX᪹Z[+41d}ZlU8/Tl b-&BZϣ̦m*sA!U~s&7Ss`m@Cɀ\E_߾ 5#hb2>ԹÐCG.>ce_pWj;~uޡW`1c9X\vs"R\^'_߾0w w>UTa*h#%:U |YLķӇՇ/ v6F7WJXs#ᶳ>X9+*t.#N8ndzi:諯:X25ڪӅ5.]9CR\E,U伋Bfe-{#,^/R~{Wb?v\eXZ Aucqwn%Tn'qur6pnUr `I+3+{jVQkVŰ p j*5VnղD3nXꦯWAT'(W9-,Y{g2~Ҟa[3X;j BH|}{=.'ϣ9:p-Ww1O{G\BJ-gsS}V߿0b O\!&Y+B|gRWI_9.5s(]([g>XǮ:+U\,d5keWʠY>-5f<%출7]au7p_q)/L@:Hzm- ;Xʬ;NLae rӱ ;`-UW\]ʎ - mKNL  rT~| X@ľ/hʯ72gwWX][\5LMk&iKE8+=pOO͗_πl W레 "zWWSUKø |02! 5v+_E 3'&ʤP>n\}m6!2%DO$- WU9x6uy\tJKk$i9 fq6^0rk$Ե6R+{y$C? uj 7- ]D1vzDwx&eslz,XZ;z X\vpuBm+`s̐8 ~G:!~e!#-9\ J0WF DoʸB v3L]n1%tgIlN7 q?W۾m\u w\ى (*2UR׾[&ôEJ[3$\-3W=95ckGγ9#ʺt6Np{$mq5@Å`EޢjU-e}SdR54c8pwAhWEyZ02 KݯT8Y=YYs4QsL |O=pUW\) 4rhoWbY愅.aYvvҬaN9Ie!wN\Uq\ʐ.Z̝VU'Wp#M~f\U$?ps+7en\aXur&C62\;Q綃Hͦr vk"3BU"*Nח6jT!-p $'!o : -*Ϧ᪸am"mLV%gϡr~p\`AUmS$X{7ieT2*rJ].…%&TAWj@G?٫wW ^+cp?\a [?iq%Y[q(l1*iWUk*r_z*9dF-ybmߙ+x\m)ea;͕Y\EqJٯp%#\T#ݭ%cUӿr%Ř1\!lGυDťUwЇ|H N0iK4;8fW ʹ*tjV W;N[чʍWa%:!`~v؍P*F=cP;?ӣp톺aJ10BNxSW#;؂\& Xr#udi,gCc:W =^\;UEDP} 3XJ諡j}=;'k#p5kF\ mt$ T _,aEƸW*|=:[/@2vTVLU&EbM.{g⪟-T;v6󓫞\al:_ ԄrujƊ\ˁ +TQѣ X@xN%f%` `N]^h9|eAAnVЅʴ{A%Xmu_,r5Y4wYr֒C\z'tJjiɺ$( W5X֩WvSr5m^d9S%W\ͫ - +qu3ah;\4d&:۞@#@]h r-vElhWdeټr We\)S&Y ˱qup?l\r)b"p{<ŤSQQrU]qnq$팋f\:<C:se(I;O\, r?`Ŏ\ʘJNTO +][IrEީߋĽU_\ko/;jT+ w>ͮ"VՐgBӫUqd*$=_߾9` 1'Vpqc+&qۧ7ܧ/w.?|a_Wfc׷`@[jU=Hs \0h6ߎ]a5sŘWygq.<"WOeā\+lՕs"rŔ՗_C s>Ќ۟|P3+jɸz׋W&5k/h}ak W$b5W6C_ U+W_ &a"XC@8r!W|| 9$HB+F@Y"W|>q\=pl'$\5€;V\ 1\ (z{UطM>bGF\m`g"R H=Z|WxN㒙.~KUj]ujwcX!x9K#~E.ְˉ,m&rVS`?u"h'; +z d@*@#:Jv Jصhy!u7y+Y~jY՞a4vnq\JaGj\N6eՠX^o%XjT&M5(l#q5p[xנW!/9g\ C1MsEf],0Z1($BKRwa~cy  Gf 8>⨼KkМӕ:WO3,/ l|*QXEw; ՇEN-B?n훨))6"WY Wˎqq5`h+ ?!מ sBfcMzkb|\yiEZ/$^\Q"WB(\+rE!WrE.c+5+ "W\Q\+rE(B+ +rE!WhY} hQ+rE"\+rE W\+rE( BP( BP( BP( Bi/߯o_v~K^*;7;mw#_~rpwϿ{]xϻbUsTۉyFߖ}>5]Tv>Mj;q==\˿G/}PqTӉyJ.o=7/wߔTztyoRsTy/AGןwuNL{r{n{;je7\W=1Mayxklg[N6}Yƫ_*=}UWsW{tg>okmw7*\] >GJ6W>3Wky-R(!>B_Q(9Ey/tQRڬϿx!XSZxHo:>"VrH ;a}\Y^l]r BP( BP( BP( BP( BP( BP(Lendstream endobj 93 0 obj << /Filter /FlateDecode /Length 519 >> stream xڍT]k0}ۜW,fkJ)K:^fp~$[rlPK AW=su&YbSh QΉV) mh\`d~< [[5 z9><-]jߊǸSʔ&V7+k]s(<pWAaԬ8uw]9̦k+!l+@/nڼޝ=LΖ.ì`*.QPZFy.0hDpf!b+!W.ZRP#N4ih/i=H}#[6M=u\a0 Mg7r r/nqdDq%E1 G~Wwx6~G^> stream x WHF"d,ڋc7W !-G3RK!&%""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""(x\|ppEpE"\ W"\p+\W.}Irv2+zÕ&b}zn HGWM4p+gߕ*pU"D}tՅpԢ N|"S80U>5]a*?]aʳ-QWrNKjZЊ TBd\JJ+P5<Ȋ U^hEr*IY]JoWRte9v*aX~]ʯ,]WҖat+uX]q}s+yX]JCW V:\*,o`KW3\u |UX`;W,5Xj WTb`yr*3c`ኂ2B)qR8K^`qP W+p+! VW+\ W+pp+p+p+v9s7~oUVWGwUFW/v?q|N\ qIY1p+ݼt,\Aj6v"MWpuyqy|?~9j\ %pqLVT\9XX9utX[di2Xi2WGV`} WZ\UV`2X} ʝv Wzse2-W W>e+EV.`)2Xy_b+X•(#,\i*+c\KU+\ipu+cu)jKUkW W1]5AUJ ]mq5\JՀ\,upUUU{ !FKܕʥ+v``)jq!<]mqu+Õ?Wg*ʯ\ ̕2uW W^]%\ Wm/x*ʧ W]%\ƕʑ+ *ʗY W2\yqu>+J&2\peq\U WU-Xz*ʑ+Orʄ]ۄ]Y0WIڕX᪨+(\qeXzyE`Uqu!+W Cê*t7ީz# W\%EWvʑ2-WvrAV WUuwJjo\yreB9axC *rrr WE`}[2 ?o=Lq3u J&*jcwveUE'ڷ^g Wgr{݉v8y5"ZyU~^UU1$VNkQL{L*j&=XaĴ pՄ2F/ϯV8W=7m]U`WESW3pUwn\'2^#vǝa°j)'x\On1;=gjU3Wg,FWdBvBE̫Kw\ecUd js!4e{-Ww~}DU~0ЅPdy5ՁUՕe0ׅb\pc`ſ ʹJj=UU\VG_ty5+U}?+)ݙ>EJB`Y~VN/U FUAW۲p˖5xB\28$3ʹ*ʱr᪄+ aYVn/b\%\8\ ,t]]^]JBr:坕D\]Ju}\z` Zz%t?]9JԵҰW W]pU˖B(pv\a)•J ĸwҽ.͠JUoKw`X*JUW+,E; 3-UzXBB΢WJݮpXJ(:9Zp%2\r(Xr]*%`գks=UÁ *,,E;X⸊* W `eUl\s *X-TY5pPU4W` \%\9pU <¹Ī W>bՃUUqUqXCU⺒ULWʰjZg+_+\u"+\\UUqUiXeURUUXWzjZ`,\*•wXFV5UU]:^G֠0j**骪ZbUXSe uUcUMXSUUzU¡5WUq\wUYuYJaDzzokZqՅ:",:֢v5Y c#]ꢽ W+/UfU?.+UUV\mn9ZfUՋO' V\=X\V~êΪVnU,y]; UVNHj6v>Hj`k XYZ_X.-_b6AW˺abUo|.t\Wei}Y#\શ>^:W+\ W+p+ Wp+\pE:|Y ^`lVpVpVpY 8 [[vfv[_M}JHe57KOsNƖfWmGl'jOq|jpVm}%v$At*_}I=|cVe+ɶ#YJTͷcyr*~ևC8k+ɷy[ɰyv$Auja?bW4|<,QmfVCrP2a;o7uUrP2Ɩ{cqogm(:fؑeGfn>ӌ^Mۛly[v$Asw][LexR<ώd9(OP‡scG?͵#9JTJiGmG9NDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD$&>+"\Q1W> stream xڽVMo6ЭM)HHC-A+k!#n}gH xc4 ߼f$~suTʈdp)5ybBd_'J3#RItddJ3i )Ւ\ؕ]n‰+;\]<)ha-~&8y]$sWMMiڍӻTX_Z4+yưn]Hn4\ scw.ᲖCsl- S^(JE 6` Gqkdkh$|`M3 %n-c? M?;o!e9p{[MMnIsIPvǵJ1M]_m&_d~,_ܠ66oW'KKI7WoT߼6[pA{)\$/( ,B_ Eendstream endobj 96 0 obj << /BitsPerComponent 8 /ColorSpace [ /Indexed /DeviceRGB 36 503 0 R ] /Filter /FlateDecode /Height 600 /Subtype /Image /Type /XObject /Width 600 /Length 11947 >> stream x흋8n)wvcN6] $;)Q笷T ` BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP'\v⊯+ "W\Q\+rE(B"WrE!W\+ s'+brҜȎFʂƍwxGynB4hgA #~r8VÒW]H,.=q;(s`%'YZM*elj)ѧ Sqx]14Q恮򑮞t2v< WR!:FqwZfم1b4 NwΏ`+K3Y6Gڝ|+eؚ3s 1jLqcFƺ\ucHgJD;W(%kH(7g\yκW7hBʎJ܇<6rfZ^ZXC58te hs+FgFs%OP75(Ḑ88e`f1h/<mfyQƟuB;h~Ʒ#ʗc.h6%Qs`%e218Nʒw3Hڎ܀L纷Ujbya!ϗD'xk ?ث;m f #Ҹ'tOR !ӞĔ=oH%JN+TKev&"|@Q[ 22o?}/qAZ$3qMwh[κGm(Z".3E{ct oBjaj0ccLݐ naJ8ߝ^Rjg0*p eچGDHSȲf W;a8W]'nndϊWFZ:N@1/gʸ{2U Th^\ABk)+C"\YTҠە̝Jqh'"Xv+ t Oi8#fCұr ԕ|FlcGfVJhe\)aj-8e'_w+ ۡQqr`aEx. +_+Ke ``5Ǹ2NL8 RK0:S*ppWe >hse])WGUv[D'0d9w:ʕHsfi0Qm0'\w>nu&2]`;J{z ̡ǣBdz;P`5!L i4C5 p<:՞ܲ-Dٮ&wCAg&\5./6 .rr=a`w"~~Yy ݾ#-LZ2 TFVq ): >~5-˥sog2[R)W kq y_e*M&;lWV4Z7fr/c;~|[Mmn&b`e6({@f$C}3 {pA oWj)oU_-VRcBҩ9(6iʿWVUxDd0pă *ҡc?>t{@[8-c ka{z&'ݿM \5]NײgRYQWnˉMV _R9`pZ_dx$!mFJ.? lFɊIjx 7m~jัi⢕\A 2V +;1S˽#`ݯk]]bm'kIq6W0\+PJO!r ՞z5LFd6T7cY2#I~JFbCOH>qV.?Wv?+7Qn%_!̌N.+l\٥WXCtpͮW/p՘ D=:VXM}^$U!F`?rȕnWc%XvKOPY̑>"~!vGmmPx 3%KAY:Mb%X}u+!ۚ乍*ToIw VLVUW*@(RIo6񴭦)£Pyoj_Bn"PC:uU@d"B]d4fU.WYܥ( +b*d@u4R\|ep0, Dk \MeGɖ%]/!@?b;rULsq^ +qpZ\y +59%!{Y h+gh3B' '"}JZZJU ѱZ>`ݢb$P4aTvU4 @Zg*#49hEcW2 V=߹lrUb}jл]D󻈺r(& WB*q)r,'*7P4r>jGY>ɄM4gXK^:r*`)8\Dϛպ(]N{ŪkJ6PVZmxxkDuT&HbIJ#Vc:6w ΉZFh 5 7K+ltF+xְ^M]GT\ qs-K UsAV#8VV@% ^GpemțJ? W0#]+pVy$Wr=+"*!ʜ'tB٤?c#õ"w`mIlQEYBxv?g"pkliOLwN}w2x֨}+Z%j<"VP pűWit.gs{P/m;1Ǫ#, e㡰3r>+̠/.Xc9W ;ZM%έ.@u`-8"-*ҋirxKj\g"ݯ!HpG&!`*o \k*2їS$Uݠooq@"ʤBwE} y-` ˴pPXg >@qҢ{qa@ :Oaww_0DV x~{e/Һ"Zq"\ت}7fgVЮR&kcz1V…² ƔܖQZ_% p~\=\B'VJ;TpU}H]\,Yl+Y'H dɽ^n53WhڰF9߮(UB!wMXiJ_eJpMV3t•(^3<+Wh D :QnĔ}npDWh.KJ<ˋd|mqOz`)Wil+2U-|Fg!+jњF w-a}4OaB{7b\!prX.$xB)F[v^ar!BR3U@*FdmAD:W+^`!A* h$}5B q`u31C-c.A0%+g 87 ݫV%T, H:R&\!AXRX⩸jè8\kЮ~LW3}4|dzU+m /!*3"#+<*4}yUW)s0qGN$ {sC=' L:c%ٱ=P( l_'e\k:W\ˢz X( @8pW?U@_3. \J[}z})eZkAE3ah)g +7HKWW9+Dʠ g2+m S-#yS*]fP5l^:Wa\^wr׫L`qUqgRc-ٜٷzkW^ W;CIe?jVn'[ -\A Ԓx6VuO&Uo RXJ@N"w6B{.*>؊X- `ИΕlL%FWoT,>c>o|yy?>`y&C(a+aJKB zJѤ $\|T\]Wcrڿw{i+g0q>]!pW\92b3!rܯ]TWWgM\Fb㡗w˛JwW\}F_nկL7DБ mȞ*d*,iw|çW^i 5yϕu=jsm׉+߂HkB\+n>e V SBg9G4|9IqWa6\,E \.N| '2׊M\mjx {k,-Ԏn2 ]]e\Q۠vNhM E{ʄrb.0&s z[DB6VQ_ 4UL5^Nrm-½18ÛlgP]i:BT3@ۼZB7uJeZ /K8 Jnde9A/1OKz2Hb(V׮SDrR])JBR7K r^;WN+Bw#&.)U_5=5M0XUbw/!iuc:)lV+=בZdxlr4BbHǸW{&ChVsVrvz>"O߮bv}t;:UIS,vUJuhl>s3H=x SN݅jZnMV4[՟WbX-7?~,XP>J\qpцm*ݛp?TrrU^UNÓ4E|Pk#h\ijaN1QX+pWj3=Cv]̠(9r%r6 fL}G4kgo]*ZN2u×KqFFO-!+D^[v vȺn/e(C&l>Zzw2:+YNu׷+`cvE4n6IavIJ'd+ʒҏ%7qu`wwq/MYtIurG"%կl\e*{0$ȕ•+hDYr&}bhYt=P>XǮ:+U\,d5־ ǯʠY,5f<%=?nػ:WaWFSR&`:Hzm- ;Xʬ;NLae`#cv'.ZN՛ºAQAe!-raP<:}~.J\3)`e˪bRʋF(*9{~ sƱү]p05 s ,D{Xau뻿^ޛWG5UkA& ]u\iLUoo*X^0;AL~vΜMI|q^Wxbn>XΆ>H R'\U}Lԁƕ־IV2(1k@l\0r{AVZ)ەMW>2$rʇ2*5/=S2Tn /()D pHn$zP)u5]m7 ЯU,RupQ7Y(ʐ+'8McO nL\aF6@wjtpzqUwWAE) z`a4V*q_ q*ё,Ru1jR336Q~OP^Y֧s Xq _\eKL}ě\U?[l/32v6󓫞\al:_ ԄsuiƊ\ٗV(GK#WJ `.]^h9|eAAnVЅʴ{A%Xmu_,r5Y4wYr֒C\zf:U5d=zqf.-ܜq\m"p-j^uՍXh\\ CMgqn{CvMD*hx-^s,`3י,~d鸼r We\Ň\.KUY ˱qupu<l,/՞SU$W{ >+W%H]'ۻ'W%\a2,*G2θhELS%ݫ08 ̕9c*NVHrż\2;h"qV*Ry aQ {?Fbb+IW+\eInՔ\|_<WZI2VyP\Nj3y_8bG\p?=~Yiɸ1&qۧ7/q,^1O|0f9xnp}Koǡ9b|ͫvqvā\+l՝oE \X_}5p(`8(~󋢯\QsM_4|Sm? נW!/9\ Ci&9PK. zPY y}M%i::Wb%f_EX{`BE 8*R_8$4teg6ӌ% )|yaPϙT< NyUst6Ƚ:WcS筒|}5r2&W*Kq@u gO8W{O bpr8'kv:֤l&JμWk6&H+X/rz!$\B(B"WrE!W\+ +rEʁe^('`B(\+rE!WrE+ 'WB(B\Q+ʳed-xңqDC"Wd+rE"W$\+rEP( BP( BP( BP( I||Ao/9z=>s>}~c>}яʎ?UQm'n}y}[rט˻;z9hS}އv{n{1|/^*:*UPqTӉyJ^no߿ow骬?TztyRsTyoAGןwuNL{r{n{je7\W=1Ma>)O/;G؄+ l髷W3TztymS W_vm`\nyK[qs>|G~(ӽEk-'n}8;t+܏^ǩ=3Vԟ۞7BP( BP( BP( BP( BP( BP( BP( BP(+_5GRUTdB({qro_?}}?D/kI E/_~~"럯\M_\Zr?BѹVvu-x/[׃ւխ+1 =/|U_A|ln}f4~[PB\}CPr+Ey/tQRڬ߮x)XSZyHDʋR]qVcxr˯_+J9wUqG,o6.9BP( BP( BP( BP( BP( BP(I endstream endobj 97 0 obj << /Filter /FlateDecode /Length 1220 >> stream xڥW[o6~CR@ XX=hIKlEȉ$|;v"s`(8M Sx,7jBN؄ORTˡRnM 7UW*}eA%֝9͜OaƑaP! +g6Yc[ n{gzNt0b)RYv6h3)*X[X·~5`@AM)y%:T"Gp V05'Ml/70RdW}G:jBt+V:[2ʄ N-g `?`>$7+S7QS XჾB`heNci +8lX[(>b>,YC/qegxFbsDO]LpŪro{ӂ0N0ܫֻ N1O㯨WBT<={ʄ_Vs}lV#E ϖj`LœPEh8!tY_e %p=E<}oe>qe›}? =¸Rݭ/ 3lzߖkn/~3}evy7{6ߪ$[%:g8湔ݟ8aӯ8OH>l8Ʋե͆'NdɭY;`k 4i~% Bx\Qch-p“X];%8ŏM?o&yG)AW>(LSDendstream endobj 98 0 obj << /Filter /FlateDecode /Length 1133 >> stream xڝWێF}[dWU&7ډe((1c#akv>U 3Fy1Pt>T5Ԅ+&ӄK"OzLV9:K\yGA^N%ڬnͫ>. ep\p9qPl `qTOJg7 xf&4s=茆Tñ6R. (H0Ұ\8gK@}y'sf5eJ4ʍGGcUHop:)ӼI+z۝7MQl DxjBꦥ wYQbw .>˭v@_9޵۔ =%6v| uM=w8:XBWfa]xͬ텞5/]y tJm'[x$h:SDb;Зżv7ad ?ƊS7p/7  ER1<^[endstream endobj 99 0 obj << /BitsPerComponent 8 /ColorSpace [ /Indexed /DeviceRGB 34 504 0 R ] /Filter /FlateDecode /Height 600 /Subtype /Image /Type /XObject /Width 600 /Length 12743 >> stream x {;r? 68 gKR.mze}l[zT* BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BP( BO@9l_+rE!WrE+ "W\Q\+rE(B"WrE!W N)"Wƥ9P6r;,,nhq0IqsjF)Dl ztl l$=/8.c5,W>w<'Τ/˲oKp\̹ `Kn*R; WU,5aO]0+X=W[Ρ2?*i3)jSǃp%b/S@d}[eلjb4 NwC<1XL֚{ˎWڍUH9/6YgAb2^.r ƐƔ4,Y?7PJּhQY4sV7hB|t֕xk:>W7m<p76k6qʰJx3v#MSdq$fhV0+qwq^EkG5ܝ3~fmؘm Mb[5W谁zaou*?Z˖EcᏚhx#DE/f7Oal?Є$XE>)LDGwΕ.y~[OoFGfA9qOD. \M,uW:dX;j7A(;S-|'ƖAV͚㚈IcG+Hϼ=>z.qje5Ikg{#Vfۈ cV8:BP5{\: wS a9 ?*APOľE|2`9X!7Zkl"tzH :]0}^䨽5`j\Yk LsuU Dչ?PlZ{ʸ9 :*4N )"\AֹS#\EΩᑥNUɊ"%JD;札Rũٿn>\)/ lTq ԕ|oc!̬v I ~XYֲ1aS~~Q\yNtɈo`|ePXZ~+cEix4r}$2N5p/H/qR fWw-1g) YOVv>xQwAd&Pw\d&+E H˹&s1KnĖP^:[S\jV WYa(fVe Bq= 41=`~mt0MP ը4_1z՝$hR]1ܘLM*8n WBg\^IsE0p>+5ΠơVH뤹2TVBjX'9+ʮ@of|ȭIl_[a [Y/ܶjW9XW~0橨fO㬃hP; @+xk= 'Vj%^v=c5GӧpvmԪE;*Ҭ6\RYne=}QeE~e_YJR1wƷ{5)DeYAspL1X(O7[&8W9V_Pub>0X3`seWAIWf dsx+iWmaX%+fZ,Klϔ\ TX{]z[d#j8 WE%ůKH*ܭ( 8'ʾ8rbN6X! QXΘDwl4? >\p.V5X%Czъ)s rS1(Z +rLe*MN*ٖU_ G۠rZ,ɕ~\K`%lML96{v+Fon,+;"Ɍ ;2 [WXxLQC%y\w꫹JjP[:9mײ}}|VW*hY2V-P(p٧Ă *ҡc?t{@[rԕ9Tt/!`@ѥcFԁK*a8M_KUs,[>TvUf$tsC|3'l.6Bea]I6st)u޲ mؼ~]ұI]4ZKw"t(׏N#KM5p8&&K% "EmGyDpQ"؇UWw^Jg0 &ʵ)BH]aQ-e\bڕݖկ\] %~2.!>n\- 9&PZ_eaզS7(JVMVkf@].c2K7lDOFl E W9,* {{6o(eZ5Kiz:h_zmkXBB3torw7X>X=Avc!2&:\ezDձ1 ?T]:j.o,v2 Օ u±k5&"h &+reP>+!\YWz!{¬J, eS_V*|F(ǎmpaI#g>C5XO& 7AB`eXK^:re묏 rL\I_-'oZK_Cਲ਼{*GYn'jª8Pfbk-bıbaj@SrU=Rtl VIjtF+xaIy12 c%W`wƹao*+Xb"u凌+_e?ߣDSsskI֡^`%2P'9QrUʕg=F;WC"'p0Dz #) qr-Y_9-3ϵΉvpxv?f\Y vm9=82o@ OO_A7QHrhhawDmBa9~$uば~lO'VA]ڣ&݈N̲=oUAW[3GR:!XcWs;-ZM%έ+rzMڬtk.if ߚW_pmMBԌN6TĀ{w+bJL8́C8vUDߚpw\ݦTKs(8 lTwsoq@"ƊBuE}u@+g>B2-\rS^$>Al rt0dž+u~O,a7/X"?ҮW(PHY~X.S\h̍)hqiZwXV ]v|h 93+g-Wr˅\L\($:s";!ZJ%XIgv,V um^w/)) \uˢ&QCr̟*~Ŭ;p~W{0WeZkA)U_eᓬX`E]⑴rg+{U~_q3wN{p0\ Wf!19KG*ӡ+߀Y= kJѪC\ G^BڹrUl[1a`ghR_- CO 6jD++HDN,ZA ZO&Uo RXJ@N"o4shkP\>vw}3>Okq\+;DVI),ۃ'ߨ8|Ɛ^•_!81x`,.PXrԹZ(b r/kxQ-ƕV)+߂HkB\+'n?V [B8GHc`e[AK*h CjWkU/Uz,~UR1i?$WQFqF^ J.7'V(#~D2HvV ]u .=-Ua /W& u1$9Rn6 XaC}TzNhwIXMy2_`+U7MV3X :4byOϲ+sܿu ANIڎw6/&jQXG1#͡9H^P+Ad <\TWEЭm% nk-$WN+B#/}j"+[]aU}ӄJW&}N͸h8.pJn|MNWՕO ꦰ:rqNUy7%p/l:dd (T )!BgufSCm5*suU=yqW9~S?4"i %zs%dGf&C3\Vއǀ}/(zYD 8㸚h _Mj} CͫN4RW~6}E}gbM‹w,cj5kb'[WBu+ pYDyvNjdM-3J]UFVF7lC8e~O\b5L_火UXs㷢'_mL~B?L>yOYV ͉Snqڎ+Lz M Ԝhzm+tW]a@t(d, &v@h:WSvWf[{o.e{1u@]uGƻn!W$!\| ce4wQTBL1{~ 񍹹 Kv5IFb'B W?xh~c\}kRjkC?s5nAy:4 N[ø "ܷ 7U+{!Uh¨l կ}\!l^*yW XnfY=)6|'ln sJ=5bc`qQ´)R*Si8އsUӳ+Wd%Sjf?bt^ =avN_UvtཋD0"Հ 7?bxWr 1|/kJRΐz X0oB 5aeNՔD5&\(s̐|쀫юX9!WX+qu{*1qhБiru`ʸB|Ws:\M>%ƊmHn\eE*n9vu (*C}2Uø6G$g.++˄?#f<oA&WK '.3 #+\MnV5n_T^- { h޽bwi}p >@xU[NF*zW{ seYٜgcUrVu왫,5 JR}eM^yO85bBxfؽsf +D$]6;Sr{cEY~l2K f#Uر}g;Hp93`-qUْrU9U'Gh k ;Qo•}6WNW r*,/+ոeP9܆=mr!Đeaoegjk=+OW‹uZfUBߛWťk] zh|~-(ꏡnI8>Wx8* >_o`!oB71+$$}b0#`Unn%#AwQJs5w;jq~xVZ(+0+]K<\ wr 2*5:IUJ`ĻoCpNhYr*2:*Ε'W], +J*j_+g(:5$(jPC\mnV_uV[\^d9]K*: Fbdpr&VGjZG&b:~?|C#)~PιZ+]*8 ⟁x\!gGfsT,{+!W+K/ŐIU]b̟YNW \U/'W>B+Jʸ¾N+Ǥ1AqJFzt\3G0je:&W&ݯ>H pE}$:d\X=֬ }/OGW\]ZQaիnzZ[r!( ;NG2R7:`m՟Iz<{t/rA0?_g?c< yk<pߟL_Vry 0T>.&jq oncvB }}*iQ;j!ʇh|Uau ~cf]FiC6zC`6N;|^jqu$u\==ٗn8WWnNԋmcrDz޸/`M-_oJ_v6:o}-n&>v)4nh5^v[gk^ڗjQadt}+}&uu } k ˡ2TCP\ xʐe\ei kW\m?ʨV9}f7v O;P^ &s\\X'rur%TMΡ6 :}xv̼qW#=W9KK6mbBv= 5f|Cp԰m&rZ[`?tD4Vm)92i~ӫiw`d*鼮f;fȣ)]_K?W6๰XbS/nG\M?[여9ҭT|)6Puy^ds(U9=*zq5v_=Xd^>-4z.}5rӲ&W*Kq@u d?YML[ bpitsPܩ1Wr煸%_{k\y)9kH)'$C\Q"WB(\+rE!WrEv7B9+5+ "W\Q\+rE(B8\Q\Q+crEyiQ+rE"\+rE W\+rE( BP( BP( BP( Bi_ߟ2>~rO/*tu'Tۅ۞m#?{Ηwߦ>T.X|m6އ׷|O*$ujp3q>ݞٟ?TT]W@ŧ.m}(y}z{/WeJ?]iVj>zgnqu]tro ~qb̓ =sxٖ]rr\5>iMω/yzt͚[[.al|髷4W?TVD3=뗥6?Cu[ -n{>~jG~*=Ek-n{>:r+?]}S{]g<p37BP( BP( BP( BP( BP( BP( BP( BP(+?O5(\QV7O߁w^Do?/bw߮| }+7W~?3WOPtnt<]*?ru+x'bsuJL;n?ycǑխόk-"BɱWop+EI?j;Wo\,bMif!}+Ku=[}'s_+J9wU^ףt5&9BP( BP( BP( BP( BP( BP(endstream endobj 100 0 obj << /Filter /FlateDecode /Length 1046 >> stream xڭVm6 _ozaVC;lhahAgN#%ٗEHGI2шryqRFeTVҜR84.~WdMN֫BDT\,Z?</U -),#X1bm߯}H*gȄѴ3m<Ɖ ~Ϡ@II1+G1|kM6*e2~r!$*K9ôn&dX#2+) JI Ua{0i[Cݘ|T;SNzCe&.6Yg|XPl91ld;ޅDkC; <-lڣsR<OG64{tAO7ewh'ULMUlC ҷǍ+Hj.3_>61?-0.S$0LjC^CWѸVOq]?<6nPKc t'd?}JH!]bbr(CWU Ǝôp3u1( ucp ƌ 4/sA܍9i/3ᬣ_̏vҹ&NZZVv?VH(Q> stream xڕVn0+tRH,#hz(z7LJ4v[#8}EC33ϳ_5U^xL5Y7UPHlYn{"h_onaD2bj@xʙsh-HNhZzK-)5;UʧGTy q3`#X`cH%<UXӵ@.(kt(]6K8AsFcT,MeY@V&QLFO)c~:<0z a \E7!26vId-7* د~HdbE RHC/SE(YfjVRJ xvk+p##J'p1{9#2qX֛9<9>ȡғICϑ4LDQ'l$D¤IK(UܰȅlטDZPЛ7E}-+M"\%㨧|tdyo ť:B ż*JQnWSfD9_mHayV:[/b ~fS>K|@M'L vM>w#-/`N"p[\- p;mZƷ# HLy׋/68endstream endobj 102 0 obj << /BitsPerComponent 8 /ColorSpace [ /Indexed /DeviceRGB 56 505 0 R ] /Filter /FlateDecode /Height 600 /Subtype /Image /Type /XObject /Width 600 /Length 7850 >> stream x {q.۽]mMSNZ^UE0y$ WTEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ@T O+.pZ35k\) J@iZ\@HJ t*aȓ+be_ɂ|Wr+*\T8\) &.:pFNRwi62P+b`_E*r W;:JFRj"W [*us}2ʔ4;\yrEJy\Q\r:V @(i*rEY`5 W"W 8H+r V8rUXI5SUX5&n"WʢdÁ]?ԱȐW$Wsr u㊴x,rVߞW-_dyj_2.ap$V\~;jvX{\sՠEp Xɷ[UE{1:ko/ H5_ d巷Clwǻ)9W+WI<xXr. |ni:ܽK/0>Ǚ=vyXϕf(d@\W_޿=?bYtstp`(n}p0VE \.#tX'k9 _Ujhә,*r%ެ;x8qQUkWA&G>\"W^qu۳ 5tPe'nv- 8@ \eLVqƕP{uDWw'M܊WSP >\"WVYU\͎{~Ȋ|WN'zR aYUB\f]{^qKj{d hN^JqeA^"Wce* l+\I,mPʕ1|\iJrC|bսJ\Jz |buͽO{B߷SU@4`lwcfԝz߰ ~{wd|a`\WZ%߆~$WNX9@5Vrv Uya*rxr`\a*8TU>\!?q%qA~PU&!T"W C+`(w灪K g4qup\ٛk=l惟'Ku/s%WW-_T-^_z0Ǐ\)T1#N\SuUvϿ+ni>|Rõ_ZW@g@Tԯ?Wphtvd\A?(\C>x``-NXrSƿC$1#;+Aʥ__?OwiLUS0g8I!^֢of?SL20{;+h9.zցTzݏywe׬դIfbkL_){.&"PՁiޱZ>7.jeU4m.]] aj26#R/bB'J3NmYNj [wsG ^n%S{hU\Qa57o8je^+6-A3WGZ׶WRʻf).nΪcs514Hf?U q.x\M;9b6W$U~0\M5ƁU)[ i:?#-ft9vg>VINX5Q5e*f>HuGTŃB5_V3/U1p.Ўwa!&|?U†$m +`ϖ]RΠva/qI)Tijҏ:^jvITO6>*\nCۺ=PvSLsG2zJN{ J-Wmem5_}<j?TE3mv)iEf:ǘᤃG crRw2%VJ1WȂ+U-*QԹoJP`!q{FP!9Op%S%]RIs99:TKb,\ e"OWCO]b*9jĨ"W޹ *԰kLHu Kb`ijڴU TZ[UTU A+5H*\a]J2Z[IT31r* [vTTs1Dp\mV^^mVD"WNӊ**#DK_lbfƕwTSeK";#Krtm#q-T)_V-TEWeXEpȱR}'U8|DWX)O DT7t+2ȕU󊒫ވH$ysUmZeLX+AQQ;Z`%@< r5\̀UaRrU:U\@+%z\5 * eXV4W)q5 "Wv-J!WF+\)UrU5ȕ""jac3-UCU\\%w8 EUL\숙0P VUqU)QY:ڂ\R18 "J+Ʈj**r* J2E=WaVpU,t|YJjLL \iz?`֮"+sUڔo,8j!re%4Y0 >ޜܴQfX)檴-\)yli_.^~ZX䅕ZJ+-% JBϵuc-Z9WnwSሇ-GXE>o|ni:ܽm~l)B\ x B,w\/afnJ7ʢqvL ~um%V#W"Xuk&dx{Z>~#-a!ASmf7%9\~l)]U?x宭kWKb  dh,ǖ.@hs5j[F`^_v#k-ݼLĆqK v䯿\l4Pz)8,[ |Yt#9.V Wq[&-hÒQܐRoc{%y0 ^mp P,6J}BoykK/ؙR!WYnȕcKo5 UKM&,p`U&`Ams+,ӄ@\!Ĺ*aVu̻'&857 cE2b zb&̀`U'ʺMG|-adP*&+Waڙ\xeX tJ]IWPվmĞ~[J,rk'W Vwf L=~Uܸ 6iJ+ p+}zX+\p5X͘+jr9X9pUM;p_ܫ\Ì8YYp5 yĵߘEr՟gyG \-FȈsֱ pǕW.RU (hAn\yZ/:ލrϗ+Cre SqUe9wS?lzwr%U嗫*Z?qPrtYW'M*rʽ*`խ;r㪛u9WzU+-W>6( \9\!}Wj+6ȳX 䝘ʚmHu<&r\UNv&k?mM>ᯯ]N0{*@T8b':hpWj;c 7rOHtJ>tJ Ѷvm֞-7՗oiWPCxk)Wz}]!^}lFXe0XOJ+MtT˜|pK E3MSʼQpIۂ[ahgx'\ٽeZ>:=WU.$aU W:=zsu}6my޿A3WNRO"#8fsB\BJ&3Ll]d(W7/CC"MoPBmRwNsC-r kǕY`1^ Ͻ!wlY+{hbK]VA~ӓKl_vWx` ȕ+,9''K\ֿ[L+ޕOkyU`LU7P܇rE $W,\b+"W,(((((((.ι)qcmyr ߶C0]R]$WCxh;x:ٽmyFXx ciUҵݛhuoɬk~|pln[^Q9VB/wo|Z Sz=\;=5L;)تq96Em\I/Y_ur+|}x|/Myr / {CsUX{ qe_ޠqO׽yWhj乺\ծWA &cVv7Pٛ)*\&J0\^b9s%0O>c׽,Wrioz>zE*WraHn;uSۭ _#q ծ]":EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQ^TgZ7=ߤբ&+\Q:Թ?^O/w8K󏗴M"IꜵI2vA}ljpEMsUqbi/oU>[rzsUD<S'{[%#eUkwo-AEa(ĿzQ#tQkYߕ/p!ՔkjE.88ߛsGj(QwRh.((((((((((((tU7endstream endobj 103 0 obj << /Filter /FlateDecode /Length 668 >> stream xڕTk0~_Gbaن1HulA^JV3lctrlt>,~"J*%"e23NLμB.޹̸ zqqu$4Wh|VrhD!Ҕ]jhaZQK#?y @e~ĉR,`[JDNvvm06ll5v7qhDG#ƍlgǹdެ_B]s!xb~kŅfnFB!zkGKf5JFdžC>{h)gcX&xDz7PkM~Fv IeuB,<=۩:/UӚvԺع ظjHMK(Y_ulz Jc @k [B;΄FwOx}QOmd2ùM\+7aEJKSgJprUFWSݼ!%b4oLKUZq gPUnscs*TgRa`X.YZ2~02Nr Nс4ܧ^>̒ez wendstream endobj 104 0 obj << /Filter /FlateDecode /Length 1009 >> stream xW]o6}ϯ\ Vn[T+H*dkY2t[esϹ>̻7?xVL+9TR2"6[]ydOz$IB %F6^ h(CODq/$dz:E-*v.0GψhNtt)bEB1т hz}_T;?Jyowgaجg )Sm> ^>|_eC۹ʦ8m)|!GWc_6ΆʓWE7$p~o'{uU0ȡMwȓ3!#w+{  TGzmлy,ߘ34q7}Pfzn,u1pi }IFF8`ɵ2iۇ*틺(cP9Xoը›QUP%Vf*ۥ8mO41'676h2khZۺ}GOf _ qbG32ye-T3S7m9;̺@H>yʒօbEѢhsο bANޫ>7n`ޛtlt s7U\Л9.\L,k~h%MNւP&`/EP.@@?Q\) (/B.$'p8s4lQ?ü]Z8.1"*m% ~+כ+ 8\ /t $Yg~h1gtﯕ>ϊo1 Fv_ЬO5k`x]Ҽw/A4}LmxLVD=tݧK'H;_HؼO>đu>CX%oG<&z鯂R$4B3©A=Pendstream endobj 105 0 obj << /BitsPerComponent 8 /ColorSpace [ /Indexed /DeviceRGB 37 506 0 R ] /Filter /FlateDecode /Height 600 /Subtype /Image /Type /XObject /Width 600 /Length 7190 >> stream x흋z8Ft+]{w[3l_qī(w׉ E` B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B$ŷjͥyIO븪<7zSu>4~\E꼩E3 i`&Ϡl(hWً*wk<㋯˪m|^GVq۶GijUMi]Vdؙ\|kJ2԰2.za}\^f/ [tW~+͛̓'ԍNHN{}WZ_^/6puu,O9oix ƪ%M S|z=W2W_•w W@{+"Fkvh(nX h IKL@$\uOb̾,nBQ`E4CKFĕˆ ֈ; F !O-*yt0d#sRKUǵѳjNN82ͫ <)uVaƆ ,eWq݇?X ;aW5Iջ:E,{\űd}C7@yk1ChvO=up㽰N;'s'GC4`f>]k7χ<-L%BkLTU'pQg+(RX *RKnTn*YlP g=Wd,;FsKaV6h+ckmIMS*4EVs>r*7"V\`>\S@W=5 p{dMdO<5p*ҘeI+dJp15\EUn9<^kz)\ΕM[=c٫cp=Wd.-jU^\⪓tUђg.|:liu:(}ruG{^`!*rmB6 5Vk \լksu]f|5Y\}\dUpX#dƜpXi-|3l/p=WAX-j6GW;a"Vcۖlqj`&dr0`r)->zaY!5>5H'kک\Y3Z_^Q/ j9j?8JpUUl\ea SU?WNZ4ch~\-t5UW!rmkZj\zɳ W JK.7FHʆEeA.V s5H׺n+\Y;Q=0XɄvVU\Y U>\W h*@-Wd+(\\Rm*ɯqP p *@лJj +`6+ 9  MP\vöcMd zAa>?\}ۧﶟWNNC!K ,C+oWpQ|bм-=GAI 0\d*ʝ+>;\eUq[p剫o.@nWZvov9Iʈg %Wp5:[,kA+ ubI0\9f]r\ՄZd^EgYe<0-Dj'=jz>c6R/X&V>4~ȊF95">_0on-u&$*!΃(hǿZ}xXW癰ZX:tr[ijpRjx quh+=Uâe-t Rȹj'92ـuǔ{g6'*2CIσoŃ̹:' Sar* %xB\&rujñ+#W0eT|,8WAAfxpPZre'WX} I9/n8N_^wUPK~Gz=0qu+SeL4XUf]\ԻU牖u!2ؕCT]Y \*Z>2 ]r]_c F5!=zp++>G;OD\Y5X)`%>3lPT]rE`ToC&X5sa<\wnVaeL>\sqI&C^X_[YDߞǩR|{y̨q? G%WWyyVo1rjNVM>n!)Y^6Cigbkh NU@U\|J+ސu+ڟgmB*[g~+]LX~+;,WpCOV/n5W`^\^eΕXPW*QXepH,\U*wD[dpWxpM+f\U"4Aȕh\eL&|f %Y8WHr%䔫k*WaLA+[u$a9W VfU&K!WIWMUUD (tWc+^]4Fd\ JZ]qaTO3W^J+WoiFWp5 e\-M'\ݢ{hpZZ;\ V{ pWpDj y WVrO}\Q{IOprʋϟ-MG'ϺÍO]~4xn ? ̄p5U2VWq8XcoſZ}xݿQ!̄U X+?˫pjXRo"UF2ՍUVc0^\ ^ฏ8}̌7Ͽ!\ WWogU'q~Ydyd.Kw⪴R?JE \-zn Ʀ=?BW}k#WZxN{vJ jgرR7K{O]S8+_K_o5•Ѧc68j:} Mr|V/,Q0iEjuk#\s 4Xr\qH+J _"F*Z41ғ{KZsՍZ{(պmp)dfs,k[6|W}?WFލd^*j;m7\:Bjk kX:WHڻ!ʧڽSkWT+\ v\ĕ\j00XՌ#3/W6 񆫰A\,_ ھm{aás+WN{ER;j, 6pcc+ӓ(ٖ+-p+WruQpZUIWB4<Ta//oBUvglp+Wvv*741+pW ;4We?ds3q%:WkdwruXqu`5X\us}=P,?\Yx8W V9j bln\'\ymt/W2pWfcaܹ4D\2n BWpeU U0\\͉ 4ܹynMb(#SOIe4`+3yA)ru|4s ŕ&+&LZ\)=\ ̄rX]ϓWal!p,;\d[>*JNRB˫9DWX)--p6:(XBT(oCliqumlR aqpxMM\•NYGn z{e}5-$ͨ J͉ᒁL)5 W`93 s՛'U9 P&W^4? h>\\\͇+++mD!B!B!B!ooҗIǦuO++m{Y/~?y;znwKt.|]ŭZu͸rV.}[t~X;|uC?^X.~XY}[li`<p=ZQUWU}O:$Xjt^~]Pe/YY}]laެhW_^WiCvt95 շ`ib2]\-sqm)X\2>ZY5^z{gce'Y&n2 [)UdHa}Tկ^}\?9օ窢fY:z[sUeT<S{W[~DqNa)B\^!4ǿzQwU7tcߪ>hCH Q0\US'~u*ȟ/=_M r|]Q͡!B!B!B!B!B!B(+dendstream endobj 106 0 obj << /Filter /FlateDecode /Length 814 >> stream xڥVKs0Wp+L7{褙i@L14ɿ$*ӎǖO$‡L4'~͈ZIq45&)g_ip;Ç9xč?-ggRL!5*#< V!QE򶨢XhIa 桩*Z~=iLsm%`3"/7%O;b}Cݵ ,,}Q UVp'wulO <7 ӳװ r"fdJۈn=Rat=h+uBpa! 8ZrS9nmGH*P ~tfaȏgw1t#,M_cYvO7]#31W3۱ Fy)"ϭ)3^":WꩉQ'6zb޵bNMSN,p1IkB9>V)>5ϲco 4mxlIAC )M1XlP?7v>rvµiv|@jצ~dE<{0N-2r=٢İdL $L6|ܳ%N~VNr˅$GejjΑ͕Va;/O&a1<:40HN1A}Ϥ7kqKyww"?CM~[u>XW|,Y s~>Uܕ ri%KxCnz|X=] ͇xSBU &'Ir~O9endstream endobj 107 0 obj << /BitsPerComponent 8 /ColorSpace [ /Indexed /DeviceRGB 41 507 0 R ] /Filter /FlateDecode /Height 600 /Subtype /Image /Type /XObject /Width 600 /Length 5179 >> stream x݉z66;cǵQ=U#%"'&FtB!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B<\yÁ+++\ WWWBf^ןi_-+\vWź5\•/E􂸊ׯu^WV py^7mp3تc WIVW•MIg;o# uuy;zf אY_*jtGPJj_['pcOwJWqH5iZni@)m\E!zd5M9$Ni*5`?Sڸb갋3ti;+j'TvJWQ>SڸTY!޶}gMqU@W9g\*WQQt9cH?U?F WUĦ*Sie*@ΞNh*vqsJ;,\2B?JbDBtJ;]E/`z"y|W)eJEp*͐6߶\WfJ\ }_XWVv|Q\K\ieJy̓o뛗*~?o*/ *$IoJs~'WJo/ԗCY4\R04tIJŕ*UT^Fˢ WJ*NJw:dJV\hKp%9ĕ]6 WM?`JqpUy V+E&2K.g> [M!UTX vIR37ÕUdXA|&݋ʗ_f?*䅇a(弧'~+KeTB{H#}L30wO݋ŭR2_w WXy.֯W)ea+(!QnBVQ\˺( jvs‫ Db3P֢ 컪݋M_RuQ '%핶G GΑ`qn#x\qDuh{k%ot+KWz] $}BJ ptJ4\YceÕ*kW҄+\i,7\ivW QpӮZrrJRtUÕ^WiYM q+\hv%]f52wpWZ]g5p+\ qԕ VK0kWTE+De+` W! W*]a5B"pٕ*YeeYuըO\*DA W*ĕ2VcJW3v%JW_9rF]c5gW QU W\id54q+\ ,\isNq<3vp@q+\J-a%+\ WVFJ1AE+\*P+Ֆ++\pTq+\J;;B\*D W!,\)r嚫+q+\Jpd%+X WV` Wp'W՟iݕJ3Xf\9\rep#ĕ!WWLqU+Kq+\WA 8SW W `+\YqE+\*[WX W!WtY2nu++\ʪ+"3`+\ WTθp+\Jpy]}e]׿q+?^7_U0+WMÅdg]Y^W]~T/hە1lz_Vi+2uՈn,\gfavscqWWMGmWe W]UV=z>7L4]ժ!_& W\-8|\f Ґad.srf6hR.\ڻWgfy{3RO&F9?O?g|,tz}6Ƣ+pieZ-l4c3y^Ե{hm2W{|SWs%'>oiӔ}vZW?ԿbQ aOkpc5ohp5>4q.twr|mjsU+vZ 9y8bm>vWŀW)zɮS3'Tj6]p;"Uj?M:Wjaa•tYގW& +u+lo-KcwCƕjsQ|7v7,W6gd\3pݕgJ+uxe`|&@UV >W\|&,{&&^YU4.?b1+2#W# l^U၄kT?'mX3|bUK}U?q E_+g՛nW#{a]<73,u5o5fJ%Bں:ڼ*\M9l;zj`"J-+#+WQɇmj W>,TզDV]m^To37 W^n^3Weja ټnJ.SKuWPp:p5P^*a ڬ*4׋cƕu[궭/JXl_lZ.u\ehQ}{<q%\Yng%l^K W[JNyW>tlS|}*q>WZ%V\XW WWfa7r7⊭Ŷ\3⊘+\q%Vp+# pq+\L+%WpuZ^WW]+Ӭ\wv WŸ\t W X+\%8\pup tW:WWYT2Xʤu\ʕ K2j\*rM+%UZÕz WJ\i_Z` WiG2Q:`p+W* W& \*a&%WFUANbX2tuR?/U,UNrJ\e` ThLbJKpCO"Wy.1$(Y%0pu/\\%* UI՘ՄCWcU5fՕU!bWp\9\Et ,*QѮ+`ĖRX aU)f󶅻q;@Ѯ2j:,qJIpYVT@V庚id5߽VvXoG=o-ӕVZ]k| ռ?ӾZu{Tcc(X/8Ƚ^_xW4u,Z]UMVˣ_/G| q]^ Ze5/ r1gUXZz&krV#i2 +ХZ>K; JXdU֪ WmGxչ"qۯjގ^b.?`!꓿e72YYruHfQZlh/LY.Yfue;=7w$W J6 G6%{7 Vljz˿;AXmkq:h9u~cV5UUslY5Opݮnhw~c'V]^prnc%&c78 Xr1bcت"1ι կHW~t?_1kBqtfgj=-*UXsEb\s?V q&,֥ERsm;H@USU_$Uz:\ѺtF `T5+Z!V X95+ZvT}xh͹xEdhEUGdEhhgݮh+.UϜ{JQ0RDv?nz#g%jPsETl4xQJTIxD]Uo"4ƥoɼ TK WE}{(Km WǃsHGWTpux[2UwWYsȦ@E|ǹzݞWWD_8\vW"B!B!B!B!B!B!BH?Nhendstream endobj 108 0 obj << /Filter /FlateDecode /Length 827 >> stream xڕQ8)x& uVjv1]wcr]*R{0 |S7IՖyeWVy]ROaITe076׮>Gl͞]oH+Qv񲅓6ɶO>3ӌ`i|L=YUl0m$meDނtV @x`x b_ Y=&w'5@#'kgM:;IߠѰW,_., w'9(Vaީ>dKcO>FQG_08^; ^xy//Dl/d?GFc7d42}%@1w7=Ȝ˦/F~$ AnW`~o /'KL;A'!) `{sw(}@9>_uljAzMQ VjUendstream endobj 109 0 obj << /BitsPerComponent 8 /ColorSpace [ /Indexed /DeviceRGB 63 508 0 R ] /Filter /FlateDecode /Height 600 /Subtype /Image /Type /XObject /Width 600 /Length 14553 >> stream x {qzG%YR6ld/{U&Q_UK w/ԟb%C{W>W/?U*yg&]>H*K{bz6 sun>b(Wrd4_~?~pyMZ{'g_E7<_/?M/7j3z?}3WRUVqڛ~3 'r./\a=Yf_|W g Ixoxq>4 udȸW:2oW\}? H\^ْ_xy/ ~a=eo{jTmzU(\ݦ.n> _TaGu{k2 [o7˾jUM{jusGZƕ{:O| 'Qq[zJW!W5hA.࿰񞞹[Z"[Rer:WVEW W|} W{zjZLSՃg2:n: W7 :WđZ^7zn63WWcs9o##*^W=Կ+beW*WEY=J_\y/lg:=\QU-#*㶮\->v//7~a=]surWU-#*㞵ů4q+?O5o`_/Ë|I^ʅt<$UL=!_`|\YD] vXKb,U)y#s- sUL~ūeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa))RXWˇuźb]XW+uźb]XW+uźb]XW+uźb]XW+uźb]XW+uźb]XW+uźb]XW+uźb]XW+uźb]XW+uźb]XW+u7U;W`zXFyA⎹cSRa &>6 W3Zjm6]Rn2|<\a\re=spU ];Gvn3eCpWeUyTܨyºv\HU%]qY>{t9~vޟV^;:hվTZ>.? #/W{y^u-WYTz_}z~5{jEJ(Ŝ2hJZx O`VkQ\cuQB7pc5"/:oG {jE ,JZ'f.j 0Wc(*"FfL^'jvθ՝,B\?by2q%-]/F˛[-e4ZX"}~*>)pY;?Wct1ަ?m $?,_g /u.ƪi/uuYr4uv{(+m3V3V$q W%ᗿ<=c1J|YTA7^aۧʝV1j:t&0W䭇qu5Wg^_Sq #u膳apQ\M?\헇\ʷԳ$< VGrt7q*W},u4GcUUD{J_իKYJ~/;OQhag³Uρ~r8-rb!.s-@E]:O3l+XՋ~ -Hn1 Y*CüqJWe ] #D%ξ1WRAܦAH~s%q]X({w\3,d\~X1ݵʙȎTZ3dj#SU!:\ƙHZur1\ !1Vvϰj+r h߇Oϰj^-{"| ol\zFР蚄w0B2Wsj+X( [L1WIE\ɠ̕N6}iչzg\5SNaMAVz۫Uф_4EF4rϬ&\ R(h9> (+4 }r55yG9W|;̓*&1X벍Z9}Ws We9qgLb|co$F Idhru6,|*A7W}T> p﷯S݈uꓵi'e8^Mr3Vͮq}\s"t yp߃θ0F] ѳ%^M{$Zed;{cv˰.'|{ݹ<>XUՎX"s8߀U5+ztσ&v]JYeV+w,gLW򤩡qӢo0=@5Ģ>*W2] J5X@?W WZV 01UbbHLŠk=W?}Iv՘EyX3V&}yX(\7w+1GE׉Yr ;ltc=hF=$ GK>[ NE%X ۫;yJIލǪ1]CGbdlAIm̲\p}'>1}s5z֎M%#q'#-bj+IMPVNJ1OH:Q[ӼkXc65WȕpE\Q\Up8#KnaiU\%YT&i!I0' -Dh^={\IG-VXCz/mGFssD\ͨK؎Ȥuqr>_ܛ//WdjW!DWR2n͕r\_+u{M v%2L3q5ڂ8/]+\+ЃY$9 ǯFM\.VvqoP f|IӍ ڂI+$tffP*~}Jo\8%9I ќR2*vJCe >WSB! W*fSܙ u9\y3vjcoZn)y:,a5n|^\Z8WM*R:SR2teM(*1>u'G{AV}zrEx#9(Al۸ZY-]u͕R6r\AaƆr 'W.5o5q}rD$ԭ syt͕ԅN7YSLz݋dJzWݴ kD^i@k\-? pL<"`#Wsit[[7/ԝA1 2q\*G>sE#BresPs|}`u@\) S~ <(2Żr+Uw~П8wi2zr7ͦpb^Sq_Mjq[@WMW~Jϕ  M5կqe$%-d >WIILݹĪR?HVФőHjo|AvjXR\z\]{xƕ7 '_r΂xkj Z%.Ҩ"]HOƕUDR|QaT51 U"(gH\-1+['q<2a#F隓bgAdhpULئA+RWa嘸 LJ+ZXTڡZN~Y j_ZFuUjlBJA\]fy̗JcB\ŦcwՠJvq,1AT-ed0#Cs%WF:< W"(s2F4O CŭCvըep<ÅȩpwzpҔCX B"_2r.WZZ-I`$ByPDm+9}$DbB\-,ED< w+!ԸH*g6r4gXX-OK9@\:jB mCݔN+J;/WcUuŕ+:e+_ЕM+3ހ̕+rZb-X+_Kv ^\ +J Fi:J=%3 CX;uNgJ4xl.]\շW%ᗿ<=j˪Y[KJ~URTRҲGz>=~D2h@ڏXjbNȕnW/嬴]p5W&1魅^C,+q$WgL+ojWS+WEGX5%_r\ ٫"j d2\@^%vIK3 a^] [ c=Njև1+ܸ"u%LAK׀U"I!B**,ܾ?0Sn/Qg6++$ʎ,{3Hv KRvL2LTIqWJyʨ׾cW!ҬyxvWZd`a'z}[3irM dY;r PyV"kO^T4+.&g 1d3Y apw.*d su#DaT5W[\ղW5{Z.I*S'Vϟk2?^ ^)~ Q&e?=gl zCڵzjhZUFsU-<]9֤ \9 eZ'TW8wSi4)w,1#i[ +h;I=rܣu8{DYnWq]xW/'lۑl%|Fa]į4[X%bqx~Lh2Xo.=gcT}qEW4҇WS͋ۻl_՗7qJF8W\iU.І[ ere\k똌JgPGs(kuj˨  Q\ |Pd2*F6\:W 9\ x'wRQi@_Xz$+r5f4}6eneYXNUeʸ#qh`ȕz{Ip[d jտ IvPrkI9D\Q\\9/:Z&BGr5'oW~(>RP<1ZLr,7ViG={?=R@`(UպjOX|tZDSy^^鑚\ 9rñq7Zy]M\Ij$ӕR Ϫb*s=ɬϕ0S+k"o \`vd0(];5 [E3<́6W[HV@:ίKS Ql?,W.n%?/xlXgWR붗`Y|4ȕſo7Ұ,N8a\]ens,M\YwY]ɭelɹq֧6Ru2|Z\-˗rqzS\ѽ`tv6܀bJ-4rqQ(CK.o7r%Hq=2ore 6zg{ɕW]u"lp2T+F¹q\ J\jZD<8tǰѻf>T% QUEE&ked%-\S ,mr%cU!H{K\U*^ )Pv62ŻI}L*hkb'|}bg, BZReFX3طsy2㢺C\/+ڵWSϤڊxxK}ۄ߿JJ W0ծF#9K]pVOy(W4f ջ\ynQP_x~DeJE5sl r%`Q:;7W"w|^]map%C-+- ˵}/=D<[̃OL c=G'@NyB|qmQ0HU11 q]K_#h!'=\M\]O~ƕc.TJsE`We#%vzݾЭ_k!LL5~~p5o"XJڇ;+5frD5]sVWK_`u$WjJ8TV PfW.كI{N \ +Wd{S3Wp9CR5er5I2 sEЯRAEBt\pKr5M< 2g(*5bbJpg' ^U{RN}ԇwT3XGj&@N6r5uG&hV>䦔\ČV\*\Ay( AJD-6Ej (RRzx\ >վ2\:W3Z }-#LXRIņCpx Mw`wtOԣ C5X6,W8u+-\)i67=h+Q*k tjckhG[vql`]'Ps`Ÿh>q s)/wW,ws)F>*j0˕ 7Q~`v>fﵟ|\)Q\ c),k7׉h%$&0jAI6DG"G*bV\;P<g,SFøB(زmkN,px %KS/4*\ѿyW;n~i鯃999WJ(:klķmZX&2@=en&'@1RZW䪤RWRFl-h,F5ΔeG\W8W4"ZBT*\\9dla"- Q3U:!WeFc:VWލ--n\O6W]sezH.!ڇLf2XΠm¹:pEE&θȄY7 :iՐr`1iUa΃/d0W/%Ktr2 UV3ͽgKJJ@-Q~vUWqW `?Wbd[S-΀jgaN~8Yɡ*W(U~FJE: u^ʕR4>Wz~{ok\majP5 Kq%Nr +L['ljg2η]c Wr[ڮZ0h"Ё;TΕ(U}H]mj]wMDB=bk Cg(섚YǙz13%*5[i;gs!΍ŵtܶc9P+Q+h! qp}m\ +fYE{5ƕU]{ENOWV[s'j%gH7WNpЈ["x'"k׾|!]eqņIgakUcvzv_rUn5/+5㣕!#q}\73B-9Wv$7D>p.]^\{VҬ }sp۵zɌ3a`0Tk>VP*eʩLW hv`䙫(D#\D8( oO`b WHJݼ)m,\5k\Rcreګ=̃q<ܴ1+9&}*XavY\~*:Xy mq% !ǎr+c J$sٵgzpw檱={e˻rmlyRD*WS4!;ڴj7h5~R-vK.+++sgY=c 'WͬۖUsdWȠ0inZarT{dHO(FB\<8DHRڒy0Չ28?h +xVہrn+Yo \脫ehY Z W-6W8^U'4WjJP ]pUa\Ugl\]Abl+`X<@s WUKy29I,V!+˕gdPָÕ}}|EsVUT;8V`q1+wyM2F[=+ bؐN!G}rNu8+WnMgWaƖSt`8I{y>uW<$oJpϟԸh\#%® ??yL6s!΂@:J5RP̡nBy˷hRHƦ4WzV@0"WOWI=m\ IJOT<h5˷`wx}wUS+R6Q1\]Nr0Wo6lyܝ+U W .lj˿жn*h@•PR.beA)BMǯl\:\z`sFS z!ϏVv]5}ۢ\Cz];!+ɕMqk؞⼛mhW2U+o\bWaiq\2hyMsɠvf:W 3`8(֞^ se6JFW0X_g:Wձ\%>ٿ"j\ W$۲U;Qz:UdȪlgK+[%Rt3ڌ_qR+K2+0WQ 2bӪA#UX]q~jd3-u9+KՋӹ*Ǖ6.'y•>W$ZUQ2p xηՐ't3Pʞ ٸo9~%,q[׌gH:U8zIr;H ۫(պ{|[EOϕ0S| r WqUhQ O/mUVŹ4&*_WhYs+q:o7j`W@SEb-s5d\أh9#Zw(eI/Ou, pWֳhD7r&ozLxͿ2*vvU_\W1rwK뛹2W 4?Ge pe+Wyș\%j)6W"^b2;8OwW/&C͕NU UAƕxㅫWuJAqBӠRfG-¬c͕\W+PWhNWob 3hZJ[mT$/Ɲ̕̕kbPV96ir%p4W j\mE}/5`A, NUf+&92az1Z+Z0+ q'q^ہg6}6"+.j Z*ui]in{Mk({CrdpUIZڤ^5}nIX1gGX1AVˌW(ѐPd F(ll'^.׷pFr{_kľ%rO/7M/w?ܸz,Cլ,ZN{}AsM_R,:bg~'faCr7[HB`Ia̷>=o}׫#}-?+9i͖o1M-SԮ3^'lxg;>Njg K0ŠuľϘ}Ket_CI}KwWxT,S?fW:x;#Wq˻3Pa7XZ&>U>sE'?=Uփ0)koȫ};ɷ݄SoG>LdZi۾\u_>b#z&Jzb)Kq7tjz`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaiB^5endstream endobj 110 0 obj << /Filter /FlateDecode /Length 948 >> stream xVMs6Wf5a|9ML۴-"!)B㨿  ]+tj.޾`}Zܼ"Q.V0RER2]|X&,e8gXMV($k^ďۮj2!q~wXޚnߖW1|q y8On֕<oZRV}2gy:efc:\SEߙ|,Mchf(6K>9#B9`W3''1v1@LÓ> stream xڽXKo6WVkqŇ$ {(=(tʒ@)M;CRe^">3| 6W0(Hl]PIEtQoef?%eL2 ƝvJ G,-MθmSR'i ѿK&#mgdSJSͣ Ewk^}mjڌNhԭjܦG8֥\Zp_šiSka KTܩэuvQWnnT?Uu;j3 pa0@-.֖8'veg HYGBj52该G8:Q%ɺZ4.j9,%v! O]U=-'6츎a =Q=o:e,- $,v qF2[5&2G? ?2ƊO'`'d΁kxWi Ry+ KѮJF{l 1` ;B4 ~mKSUܞLVb'!yaXُ[= m6f:>SqM9% \O?C< !&ڶL/6Wv4]]9/S֠ͧ*i"RObsbC"K%qĉ;E!.=ab]Qzx$cIj=``у"InS[W8Zi2pvOW,t<}JCnF1!%E j@SX1 <*Oͥ<xFD\.J$U5ZG"C;ZiC8 nMSM\|CLPv9[-,v#D <3p$豙?%/D֡믇] ꦹO'{k"#AnGvutٛمؗ^7!>YN򬨔A6xT &H?Ɖ|ccza?iN;A*/DiV6Ewwu? ]vɏiӣJa3t^)Y}ZƅȓL~DC.MH.g3ѵ~ `uH(\.^WyA8EnUAendstream endobj 112 0 obj << /BitsPerComponent 8 /ColorSpace [ /Indexed /DeviceRGB 89 509 0 R ] /Filter /FlateDecode /Height 600 /Subtype /Image /Type /XObject /Width 600 /Length 9713 >> stream x {u`v$zҴuwsq'M[Q_NjIq@rH~IfH]#uTծZVKT9 )8',pT8M[Xڹѹb:bG]VםX^h6jѥEZΕj9eiݠ4)Pfn$Ǖ"a]ڶP-K{w\ՌUk@K4WY*tI0\՜MI-*%+=lWpes*8| q UtJWa5)\n Gڑs Uʐhpkp*q,ҵ}b8 \U`lN}*TXfWpUZqʒ ;\ߕu!&;svJÊORV9Wq*gG*Tqe'aq5ݻR -1tM@WwgKYbڥ+M S3+jYI뽹ҰZB%ʲ,YUIp-5E4U•{5]U}KWҨ|wKY&:n =LVzVQųߜ|da!_ٸ"7V H`\5>(xA}#fewe+k8-_ekVsհ(u5յ1,k Y-a aYȢ!۩ʮ"'VKM`jŕϸ"Rʢpd,ebV0Θxukn\ĕfڅ}ZSX>[M=m̂+[V]`R VCred]oiYV?$~|*| W %ʂ3XšNa\-U%,McHW\JWTCN˲8[bWXM{s{@ÚNAY7p>TS%WKeV%Zj :\mӕEm\)Sr uUV]\Ma-s;Wrej~ɲOHv&aW*]qWkkADb+\Yqef,ڌ+V0+5r,|>)cUVK~ÛWkkvfaY˂b \ g_{OUn \fg+ uSN+Zr>ʂ2vh ,j5eXЂU,WʶP@W;`Ǖ>em̂bOYpŐpeeFp͕`tmEcHpyVQ]y,|qԧYpV+΁`96pVBPܣ뜲j㧂aekvӁ ypOUgWX9/9eeW+ Ї" *+c*ኣU5HF8'kYpŇWڔ5k n*IChHYY_8r^ߙ6*TFX6s*+KW[/ R5&X]үU(V ]1D]c^NNjzmp2,ضϰJj!e{t񲹲UUjWYֱ]a4,M<o } XJ\SƐԕ{hV}5(*,bP*_~o{XJ&.3Y0Jz{^dgeuMa3XםػwXV6{ũGh簟Z8r7bujvyC:`eteW|jv0w4Vl*Юr5+,3bu, ϰU'D^]1a6hfWVNSkweWX,19tSWX,]B\ccKWX9-D<\)=bemK6IA]qcUe?V9W Zb?Z-5+ڙ`Ɋr/!++wfI˪1qߞ{MҺbj뮦,dY7_hi l9OV֮ؕWpK.U=SVp5w~곏UWV{q5%b GJleė5,N5~'q4D'- ή3mU˚ Nr5J[*Xqåz|p[tupHr5;GrgtEa] oWX yŠݫ}J}U)J4ΒjEkXܤ fbu U$ڎWUZWEv^qzXMo \ bj$ 84Ufu#<-a7a V{_ KJHW$uʪ> K*"C:DDљ-R^?ۇ+џr[W6*:p)WcXCW#W v`V\؁+U+hv\|G )'+W[X4ZDRg[yӕ'vIHR2 |ڛ+nHUryRJL>jP;懴vz]%,XcOWT*UTc#UrfLpO=JND͕PYkĸ :%?1\+h[j)]oP pe^1 +V\uNV~XVK،c*:de]1M*fbL2qKW\ ug X,5iͤ+~:j?mVXk[;Pr嫕 a^XA\tU;J5+TL]Y|ؑeu8,rfh:+f]؀e{>h`QWĊU`W]U6W`Uו8߱v+!-ÕyVQ\]8RݕrqbeNWtY€|4圯Գ/Va]-.-•D`#m{:Y԰r4b"l` W#d Ttv)`9>]twOrwsh4WoϷ,gOX B_ˉU|eOӒ6]ފ3JW j)N]ewHZtp$]}N_Gsɴ6 ++4lʫ|R_I]Y8_$,U%Ç_}տ}tn X}ΛU WVWt۸˦liع*Y_6^ŠtucͿľhٯNXI`YI~حqE幠a5Vbòs*Yw?|OUWVqw8drth疮bjrC}Upnru\ZQ e5|QVUr'^hWe). +&,{Mo~L'V⸪)J<_%we"²<?hߚ1 8~W\եS]}dY9]eЎ) R <ҕ:&9U={K;{֮bswU!|j8kV$X^5|Jt5cU sB3%8m}3ػNXUr5W1`\]⋼jQUR}yss0U~$~\{(͉MC=*CǛ|u~I>&Ο/g_ &Np哰Új& hN<~{4E&W=F^ꟛKW1כ*+~\ưO9tZ?c<~je Wc/Qvh5` Õs k0쿺uS?V~ٜ+VgIwGUFXdlA + ,W-Y dp~UtXޮ6*,q2$j[|V X_kU*@ kW\HXְHb+n*T²Bjޕ`WV6乃j<ZX&u:?Vp2ajx+ΖՑ\y'UʫQ*qcWX.K>{Gr埰a~MJ)]qYy}: +ALYJ kJJ`mo\Eb{uժ *),gWVmGs.a9"w+ӕ \IWs2a9 !]Uْ+g N\*A²n Q r5`xZla}4u\X'X>v*@Kh<$]U X"nh\ܙ]HX˰Jy\]%g^J{]˘ ]YyxZxux&%X.0]6_IX ,F_@:]EL]Ňeq8Ҳb_I;x~W+#銓+/!a`Y"&JfT;W_P-v\NWw\EWrn{UzYW/ '*\KW fU-:;4ft~)p Kkf|.~{ i89#W1a\a:thpJb#]+VӭҚܒзOUKfT "i+c%cWq`qtwfUFR5|0S.]qU0`{WzXɊhޞU]ONE|ռO+as8/E;s^rۮvr4!&2]E9oϽO[wUbX)Uu&tKnɕN6 21ī>(x~}yUBXiU(5jk}dCH,ؕڼ ap_8}R^e>VqZz} i 1/:mȕ<]7W `NW\]=^*r%O ^~\huzKJ'8Ȳ-SJjE]ǕRU$(ϕʕ<üV8WR3}{߈D۟O.T +9h^hJ"w_K%?~W0(v22+1WoQ]=lsm&Y=UeSl+3owb{O 'Z8U$WuKwg*\O#W:Ȝs1K {5OX$r刬b3T})*MQɓ?/,kn̰_NWbkB_u2UTUɟ!L 銷7#][e_|N\Ok_g,WW``ӕܷЭJ6yB)5~[W`ɓ?uj_xQZ+G+ܕ]ބ|]կEO6u{WS jGw5Z,\i֕1af$-vڜDktv7|r`W6OoO5,,UlV]18?-4,6(FMWb֞rvFyHwjmڂʔ-<])GbWoa( _/Ta)NVp-RVJePFc%5ok80WC\X\{ FXmi򱂫onLaBVp-haѰaZ'\ C]:RpN'tPIaLWp-h`U*Xm0oA-n_BXYYUi,ܤFlf_(a.+D5[W)ڛN 끣TTb ׌u5WfV3WM&7̀B K e Y+U#K;jۛ$z.mm{J֭K ƎFl uNpJ^x ]$p:]ƎrXͨӜ{M WʔE{C7 ڇSyU4Tn:fwCvVptwUT ]D~aM>\7fo~̕>eOyC'u%333Hs+daC_| Yp+W97@p), X&VpV2]K&k aUo\yUg64޾) k-]˕2R ZhaY)@W;rRlMەqoznǶw,ɱv[9ʽUP@VUl]\U(Epq*Krl{UVE7=`IK =8~L_n&W;=V[D7peW Yq1}m:(:n? DK ˆ\9JJ8m%n{zWACWh95._zqY\ZsX/N Xٗ:^!ǹ v~B?=ɉ?Rjy歺jyhXҺn\vq{UzW]Z[X=6jZuxc%Տsܓڭts_u~"V{rŠUu+U([Ua eaI`ʼnM+foal˂IJO+f `dXU 8\6W>x|8uM\E5wWM\y:܋>*01q W*)EJAq_+SU up&Hؿ+y4gAl`^}3{Rc0օ$]nLb>؆ \! Wp<p>UpB ڗ|Ŧ_~oo++ۇ+++}++@ @ @ @ w)bnW\o7znv6.>x}64]\զw۷[mݬ鹽Yg~z5)(붗_zv~+חj^ևg߭zyw.j°nn{9'ҥ^eV/?r屭=mx.{ױuswRےnf,_kWAǦ@ 4=7tzXes-JV 7[|kAmw]%5Mk,׼lWB+]gbWŻ]=w{=7q'v>mvhիʹd~^#iCr1n߾랛=v"'UO,8o?۟_V Ƕq=[=7۟X{O[vx;gwu0=~+nA馻+jSwٿ_ϱr,0nGo_~͵\Hv^8{nB @ @ @ @ @ @ @ -O<~@ʙ W\.rs;qQ7}Qi3Yé~fn"B骞_iʍWWoKv%u4N4 н+l6?M`"Ԯ9YJ>ryaj83UH; cWkᑯjXE KwUfgFqu뿚R5qz~V8C "h4+\qv!@ @ @ @ @ @ 29endstream endobj 113 0 obj << /Filter /FlateDecode /Length 779 >> stream xڭVK0 W#Pʦjq?; J?y?ulk3Tjq@R R Ff\]7JURKDMk n./Mo vR8IYukS x)v1AW9[|ll%//ic Oi@cY~IIM Y ۃIťs`))N$_)胱08ᔺѰX{cpg> stream x 7ێ%ٛH;r&JlN;NHV7ɹV$H:Uugfno ƨ,O.Kn__-ݼ4ű>x0MRZ[Jr\(UVP^RT+JR+ʓY9F+JERQ+JRQ&lHb9$HQ.= 488j@)D(pFѺt(Sa_ +h{Vr`svWZ,ޓB"d!^b3\UBwtQܸ8RM1Λ.4h#0xL7Xcİ4h\ *>j \W푐:sG:evػ^o! =qODnMY! \MFYdo!3j7)x/QwZN!Gܘ"_ WXØ6h3OX0ĠXY Wƚh]3nkD4: GG"OI ,W8 W`Q;,? utׄm-|0E!Au{0B1$R7dF[۾pL]7rO3|'q3aXWYdɸrPS?⯖z*^#EnmA诊?Rqn{)Zs+!Yw9bWdjUgq?dXG8ud 5%e<+g*26j+{=؞GH2) '~lHVN4X]Q,$i<.a>(̔*> WLNb3C-1aYJܙ;Z!24X~#ᙘJ<ʐ(:9< [vQEJՕq s[qR%XWބ^G{1a_WNйyRQx[DvBehHDޣ y~Y]LAqțP@_ M -n \-$J`-$&"?w.Q/+ 3@hZ5 Vl6ؕ@q MĒȓrCq=n7F-o~0:y"p9=5PXHW4}B6+o~zsI]9Rbӷ'7=e0IO Y?$鎴zjpQ,6=3t&={;) ؞W-Vn7\?vO5}/WBVW))i0MxwOyʸ:^;E8U^i'D>G5=͒+&fhW4璵B N"S⮆,\YW5Kc!x99Vm }Nf`yz, 1 }`_)V-%OUh zd\ 7WXWN:`)‰cWޠlN)uebv6*ۘ 4$sYdoUT2Õv5^2k\q'\و?K:#낊2;ĕ8&X׌I!ȚkKT0?~\=.9mJ9*Ub{W/ODChh睶(5Aԁ{^ VMn4BVR>t(\鸺{&0^͙/t1֮F'`<%;LWHrVWg|U;r /ݩ8F4O/*2yKa<<߿Ws:hjJTJm d$~qE(u,WY:|a>V=NJ_Cxs~coD$F]ig@d< w5ux[Vµ37Уݖb i ? )o/8zAL'仁S NCeLgĜ\, {x*/B:}I.-hFDa.=2Nc: aj}Kݸ~D=r,DPYؼDxVU\n(O*ǹ:ȩVW$ҵ1+B6U.dME+ёx{qW{WC_WFU|HSa2 c,y$:9t tW髢PHoD3I`jcpn| RϕM@o\徕>\f| ~29v&\ MvG-|D"ψP0f2i'?Ϟq S6Ð"fM^oI{@ 6A[#XPz6iHN9I~|c9js~ϊ+*Po?jΞgЂ̅p':el|8ؼ8|"=M񧵚⏋1$NAD1Hsu0lD!rq2ߩ+|37@BFLwr-nb&=h_a22Or^rxFWyOUSHNf@YdA3({/ҭ\>ʚovZǐP&wJ0yߛYf0`#6 NQ-bm Uj{ qN: 50Q2L*ˮ5S0T۹YJ\^V\WxUyFff|=MH'-Pϗ-0̚Vcnm6SΰDT {ܫs-+-Ӻ<)ܢ&fb+5j*&L Z#Ū~sڸ[0!j5錠 g`ZVU:5Pqi' NDKX)W}!eK],UUQ6!۞4V*SM֞ 2 ISBKMK9rS C{?]S2ZDžwOd)ôwJPtW[0<*mpQG²vKTOxQ"p%%~k^UE %02*W\Ӄ qIC"NC _.fPpuv{#ƕyz>{5:us-ɞɺir f i`0H /;BdV\g4  !%"s dLWB TU5Y}W*_b Ď;aZ8ip*+N*3 W)h8 Wtͦqe 7<+/Ҹ{JFF5cW%W2N+;2L4]_J_+X WA;C-B!Lpg q @]nk TB˕ױϕX)}6+Y*, .I0Vr3Ez4xaU)s\; (T 0[ULѰ^PDՇןG jg#Z1O^Rə%, "lrK05o}Bˈۼkppfջ2mH> GIWU xwj?#y/ߎn18[ƷuuOwȐbJR櫯vݴ6q]ضD獲3C9=6nWv?rEr,wjwhez)k?k0QFxߣknVLID1p5ؕ\}+!yA\en#H>h˕d+qG$W<#]2(;\q+4?;įXÀFX{" p$st4bZlUU b?cmU~a(~v\5JUK ˎOO7su ha@+ --HM+{t$!Z` a?/d0ߊ$Bb!Ϯ1gTsĻ+Wa֝v0z4qώ+C1Q=.薭Rl(&nĔ,^d/QbU0WCfR3y gvFߊpq\5y3#IϨHj#rP%q P&t@kXnU:ދnl5ˉ;% QRn<&Kt v'Bʋ܇G hX&׈*ҁ`3x @+^86[mJU Ǔ=aFV W-z@VW!W{+@*+t)h<+Cj3"+߷1Q?X( Us D C+͕Us8ո}(W <\ {IPTDlxg=W75O&S?=QTCkp~ ` Fbtҹej 5\ybt&#Jd|0oqm ۑEbi`t_)l`ðw#I{w>$Sˎs3 2J^rU0ՍE|u4 K\A-^h9K̀*OY*jx8>]Yp,}eXeZz*a~Ђ+%\dzDj!+c D%pB\+qEa@m2\Yj\ʕ! WƩaTgWŽļr*V1Sb`zCU2w> 0D7"U0w]r\1 O+;63ʒ NB=Gmlƍ( 媭-%g&7mUlΞ.!~7n\1rwRTseXp%z)1O8X(l&E"y?,'{_N|x ’$ lT1Q%3qszZ|4}=0o5Ֆ+Z݋O*Ֆ ozɦz%YCr7# )KY/ɑϿYWLSdj4\\YbIIxu5u+k(%Pa2=r\Ŭ͓5S}/˕X7'@U|Z꥜~;~r9c%q= .{'Z\Y7&\1s*bD-2ts{>&ƪ1&B+ uh W9 k+]`d[_+Gsi⸲0"^+`}4V¥Cى}3Ŵ~vK 2; `^tb^,w"N-Wqn/9N/k*Zރϕoc\C_M r&\1kIR {ujW2 rnjZQp^@P%WIa:*T+$wtH[::*9 *7RQ~Q+ Dژ;RU:3n wn,8'wa\7"{`R!Cvb&J{JwȥJ­\f%>dn>ƛY\y=K5 ?Y5x\~=_,=VDZE< quĸzw>=Ɖ;z:~|~nwQ7`Nh#8 ktVڻb}js[]$WRXvOm /(x(ŕ:$OR3fF\=ya4 )9F|Lon~GOz:L/*~wQπL޿?nTEt4*FF%\}MμF>wLOkƘĂRsT!Ws%q$ ={Đclg>g"3rG6:PVq;ڻq̸dn/&Б+H+_O+L/Ýf)dkYvwkΔe *=L&eHDY市)jXmm6HfY/}_g׈4\C J>.ޣ͕KĉwE|L0tU yva>+1 jUe{qw W:6z~Hhև2nVkʘtβ*NJ|`ڏl:zBQqCXǾ WiWwU2\ Bh2f-`䀛D wk~: ;tȊpcBCG"c|Uϕ9_W Wq(rPy^Na!~iLkAa+ Xݞ@oYY?2,ѻv`dd!^tXﶅbg@\@؞xXEtUƄʹg(g;b9eJ[ᾝVMUc"%=]٬hU*7.&*AcGw] \8tm4=ryHM ,v:UX@&ؕG鯺+v@~l#;GLYbEt|wu\ 8=UCCNO²jZ=Jk.FFyLh;gd ̦>v;DF M$8/+$_VA8;ER[*4d=@T^+ ^5zD ^a͓Wp#̭OQ8urg2J/C_!)ߎvN(3TV8\x!lyX7q06BC"܀)xWg's5gUmjZ13}5*u@@2T* P o|N}Xx#Ps21*#?WXWE&UpoPu\q9\e<t  N=Ctlgm}!H-i Cy~fQ& ;~ _i"HO(zp8y|X WƩܙUvNϟ#f||+Oii,a+:pPCWv/ "̗7ͻ v!6 ]Bw/~+s;햓OD__@ % iYڥƤݝ-rIjor潬3iCIh7DBWe O}f'ۅ_ W%D[SUdb2+/~D~WwBr_ZEW+&FURck\"Wj0-uX.W=D/dͰV=dž ᪙>2gU_Tb^)WC7QÂ880WG6rd\jw!/Z34NvRbЋz9se|Ts͌Hha_\MV}Ey:-Z=! UTZiz׫up59+,  ;rO{p j CWj&1Z.k1'o &$9&3Օ%N|B3d*Ui++WPjV S&*)WUg慓tKj \u>ן{/=7ͻ9^9{?Wy:~Brz<.*Quqeݼodk4EzzT}iuvF\q=ێ=.*Os=M;?qM*&COe,gv. {]SVV%on[puiٽv7ߞVn»6_fxQIb-_-*ki(rU $+WUJe\Uc,\.)WNҊMm5iW<^S&D! 3h\xkX1WNl x{Llr&¹թtEF⺘K@71!wJ\q¾<(|ym:ؙ,j_F\I@kxBn$JCz)i\E)pNf6~r:kcwkjm\Q?]L2+Ŕ+WEFJ۽-x%}fu_Zi7vzPwܫ<'|/χr%x\t ,zeÐ .>(We2I;`uv[RCLbP[qc2+3. 츊N/+ s;΢@ %D^ WAɎBC)WH_E (O:{d)zJ>pco%Ƶێ(C\a6q3wWd+Q?%P:$/+Z{ gf%tVmy Ux{ *ghqgP 5ǹ+,/ַB^au\=Yel.r-PEm_8uy^Yeq,1Kx{ZU9;lڴ 4`KWk&VzT^2vXCͮq=0޺i2o`\ܽ. tCBs:2ΕYWMӗ,׽ϫCb-q^e;/d";.ڬ̫p'I^p퓨))r\lc_,;/coM7 fn^ZʕJ';!גA}3k\5I21W q| s%/媌+%I˕r\)Wʕr\)Wʕr\-T>dn>*WUS޼{Jj,׿nUru,n~Y͘U 䕫I [Jj>!]tP:mGͭr\akP+JER+JERQ+JRQT+JRYW*+ .%*JR+JP+JR+%CR+JRTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTf߻'D?msxP=IQu'{>7=?=+9G]~[)9u\~po2AGw4NLyRs{{ je'\՜W=czS^v..2n9qq򾗦vxx_xPV071w{]g(>ou\7ۑtu~Jb͉y/n|5w=w ǣqJk WAO\wu[EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEŕ~\rr&1r\Cg_\]cl/elREg-7{/ǃTTxt\.r:$Y?hL詢B:d3s _~?QEա /\ާ|**!6WJEEb_Vg_~WJJj>bŶ*Xru[+K_ǹؿzt}RTSjTʾFz*e7ƩIr"endstream endobj 115 0 obj << /Filter /FlateDecode /Length 928 >> stream xWKoFWDξ7r(\ r)K@I]Bm\6@ݙ8͋hena n(G/Ew;`U= q8!]^ \(,n/-a'u9WE!mrin/$XŔ?-E1`3b2Hݱ)z]dLی jU-c6;wXAPAxև{wGXZvq^ ;pb A%k%ށdV }9anSt u(ofxn΢].A=(qM,G84ݥ,6bkLwd{vUє=ѥJ.Rb)> {QmcDzvM6&ilu71 Kl9ZOqBkEUTm?K]=UB:R8(dBoxȹ E`ًr^X!BRb²:(CP/J:%ܔu{s!Ǝ @;D߷  B1 7̐D3iv1n0#\S);!1շs%E<,WK*V=1aRMᙊ41(̮QHj"xo?R`Qg4endstream endobj 116 0 obj << /BitsPerComponent 8 /ColorSpace [ /Indexed /DeviceRGB 62 511 0 R ] /Filter /FlateDecode /Height 600 /Subtype /Image /Type /XObject /Width 600 /Length 5054 >> stream x݋a PMfIHmp6ejI-9[~]fp%N,<*\O5ؤK:_7MpU)3aW S!feA篊Uu[Y/zo5T|gx_雨_ ħ+Տrmc W5zz=6Vs5e3m;X'16Hw7ZUQ2c}?7CWy 'ӆۺjڮ/*T-I^Ms#T-ULN5P-fj,imEƦ%*D&5+.U>~R!}دbT墙G_<3._`re\\T{UMf]jN6R:7Ҳ5bfmX'ڇ܊>Q^FHlqbˏ\-1`{2/\\u6N7Bgwqxc kVT_U??]PCq>-rO&T|boYϤܬ^oUUpI&SjN7|P?ӾWlijL̯Pt:I_C~^z`U^.\cY(_U5{}>:o]ϡ?Pv9e~8~}^η]]ZKY^. kݬhO6֝ۿ.lmy^ފIaP]z7g\+mqe7ۈȜ}*?yy]9t cni}7Un` Xʺ>qV_ߡ+yCy \E+wJ/~ppVW*N͸}8W{^70<^_|Lkj|޼hbN}Xy7yW7jq>+X:n/4K W]3ibăY?/*a%\JT*n*p9^de/g͉,!+ ع+FW\ve_Y˱wVބi7qzq6O뺑Z^y*8Wose}!>-bc~#>U*#_Y+VzU qUϮg۫oE+V*?~\pճr؞sU.^W`+\1p`zA\OVv%+\ W `+UHp+\PX V"*Y V}} `+\ V"􁸂H(} `+rFhppp+\ W]p2+\ W PTb\++\ WbW+Xኳ@\QUQmW W *\ WJEVBU0^\1ڤ*ZTC&"iW1U)*ou7\ޭ3=@qnp{A\;M|jP5a IU:>1ߛ0<4/*];n+9/ZʞT,tgF_VnWr+VUgł WnW<(h-\9+\1:oLO{,N+~iZWuQ\+|Wd. u몁+-g]+U8ł WJוy0gW򂵓+py=nrI\>ۨueႀ=we8~|%gֳοp+yb^>wQ*\>2a{W՗Vsw5}}s0k YZ(tyLO!OW0nەu \yo0,z?ޠOLUТr'Wz27,x@kc֘_'CT՛P꿂L.ʀWQM#W="qE+\! Wp+h Yp,\A WR+d ZUʲp5-\ Y Hp,\ YWBg Y#x\d Y!hp,\W4YBp,\! Wp,\ XB+\u/ WpE_+\ Wpa Xp2,\ W$XH(p,\P` X"pEjXUzpEO+ ,\ W$!M{ϊiU&WI\W)rjn\5{BQq\[^% ˍ+"M< mUAeuĂ4,毀++\ W qEBip,\PzB\`ኄ W p+ ,\ W$XH(p+\P` W"pEpa W"pEpa W"Uʰp+\\*eXp+\ WW++\ Wp++\ W҄+\ WpEp+\ X"p+\\ Wop+\\ Wp+\ WWU/h+\uL,\pZJS6j W} ~/ü^++2e즌peO3pUWW"""p!%'!`oBE\Q8\+EEB!B!B!BHɅwꝖVWSuWD~/^TYQq9J"bӽBz~) 7:er^ҕ"^3{_ʿeBk?zyp9-'Q5(țwQDqjQA:zqYj\*"k<Bwm/?c,g[HWD`M[jy ׮f7tkEwĕfWWr^P38q{TŚ#0qllo鮜L_v_D^rVjyD1Pݾq9k s U{> stream xmTo ~_G,qֵU[Җd:MMTqܦZeɜ8>(AÊ,PRLK#LEp?:w[+=aq8;C\N7$@Lh,WN] 2s0+sr^Oo ԰uy2BM0н9 ~f ~ѼYO/`.bh62zoaݨ.1M 6:s ]@u]BG?)jȘT`r+`)2[50Z5Ir6՘нj1&j l1;}71| kZa66ru4*@H [-ZcbK\ y,*>k,Rz.B>E ՌZ^m\37BqeBǖ2epMw"eyf!gz< ;UvvH,]BXҮlYE+p%z98C׳7<8{wt&|ݺ棢F o\J3ZtO\d}nbHeh0%+UP >ƶ(}4| 1s~r CU~0~mr`%_`c,yRy`j7ðMQjmM0r]N:8y[}#uN-B\ G>^N nJRendstream endobj 118 0 obj << /Filter /FlateDecode /Length 119 >> stream x313T0P02Q02W06U05RH1*24PA#STr.'~PKW4K)YKE!P EoB@ a'W $o&|endstream endobj 119 0 obj << /Filter /FlateDecode /Length 218 >> stream xeαJA b > ]vj<-,J--mo||ybCBdy-j /;~2xxD-+j.KtoOԬY:ni0s #VH|ěFo;s+lq΅Ƕd,6ɺY'=alp +%D7pendstream endobj 120 0 obj << /Filter /FlateDecode /Length 196 >> stream xm= @'X#MXXSZYZZ(m#Xo[fa5B&x#/~,+E³N|n-f-nKn!R7 !Hꇨ+U4jdcޑM-孍@l_ "j~' f&74.WHe4A o \s`endstream endobj 121 0 obj << /Filter /FlateDecode /Length 181 >> stream xuα 0+ zO`RL'V08iGE7}4бC1:n83d3dftJFq> stream xmαN02Xŏ{H.X*E"L0"5)oG1o`ŃsaA t7;/%KGvA)N v=4GOYScs W,6+"< .L)'rf;GpaF]1P.;a?2yWL ǹG9^jo.G82TJ="b> stream x}1 @49IH,-,J--mMoL2LvY~ Gc 0G8 q bɁD9쎐y Y|=,9 ܂IѱË_ꪽ^cf8y/>_[;bPsfm]vҨVi.oVڷ[eڏ2t6endstream endobj 124 0 obj << /Filter /FlateDecode /Length 156 >> stream x313T0P0bcKS#CB.cC I$r9yr+r{E=}JJS. @-\. =2>gg`zp=a&f?qA|.WO@.Jendstream endobj 125 0 obj << /Filter /FlateDecode /Length 205 >> stream xڍб0# $ hA%1!ALd08FWxX`|]ۑ5]2hH}sBK&rjиjO(6d9(\G.zQ(ښd0 Ԅ9F"Z ,EIIQx %U4d]ԆG mQMSe[p )yX$>A&<5NXendstream endobj 126 0 obj << /Filter /FlateDecode /Length 230 >> stream x}ͱJ19X&ywl 'pVbvb7[E(6W77V80/̤mfRɾ@f|mcqw<︼Բ\vgt|y,/䲖ꊻPLdK?t4g1:Vu&*ޠw#¦%{"oOp($BJ(D|p0hs^>۹3k¸ cԤRP5y>ZsYendstream endobj 127 0 obj << /Filter /FlateDecode /Length 154 >> stream xuɱ 1 ኃG0O`\op Njh(bl-?崚aUÓ+>$?*_5o3z  H1D>1Cf$t cUIa.<5Ga D"JLKL`` ?:Rendstream endobj 128 0 obj << /Filter /FlateDecode /Length 194 >> stream xu @`Ń0yVq :fNSuPY7|;4kuhgd4GO q^ͷ=@X f܂x>] C)C 6h[ }POmwj؊n֬GerۺInOs&y?ͅ_[*o&+jIhiKxendstream endobj 129 0 obj << /Filter /FlateDecode /Length 180 >> stream xm1 @ )xnBVJBBB"^do)BBbFST@F R/r@)Z?K6A}cE- ol}:X}"j&xovV$GC* ~fendstream endobj 130 0 obj << /Filter /FlateDecode /Length 198 >> stream xm1j@Ep!fsZ1d"W.B*'e h{A (&E a-]{^ҙ|Xr8}Rݒ;=K}A~qIג7j$2%32 ]hzdLs_Lä_Yt:wjh^H;FU.o%mZ-/LRzendstream endobj 131 0 obj << /Filter /FlateDecode /Length 230 >> stream xuνN0:D%{:&KmȀbj@y?BFi>@UJO򢸑Lȯ9Y^.wv™/}UI\ |~|]=%g\.7B>@T*ƒvPU> stream xuαJ@ )#d^@7!;N0Xr׺Qro`Y#\q|,Oۜ/Ҷ,7nV2oFOKds9F6۵l6PKF@f*;!ɅY$ rHT 'HqĘ8() p^we  * L1j ~-Sё1qx 0hD^)㫎 Zz endstream endobj 133 0 obj << /Filter /FlateDecode /Length 179 >> stream x}1 @]RVBVb(9BʈqvEy03L8I38Byrj5tكL@N0ހ)PR+IFdޒjIWZE,& *>`۰m$jKaj` Uendstream endobj 134 0 obj << /Filter /FlateDecode /Length 206 >> stream xU1j@Eq!fo Rd\ l`W)B$e\vG)U8Mb3KtkZ>iyW]VGmZ[wy|گѧZg7}'8l"M !#T ppP\`~ԅƲꌀEwKr40À0=O%AnRZAendstream endobj 135 0 obj << /Filter /FlateDecode /Length 176 >> stream xuϽ @ nY ֫ 7:9::(>#tPCÑKm8r#:&xAk%5ጙC%k,ƭvd9%hr%HDbfRA#JA;=LVi@ &!`nOYo .n Rendstream endobj 136 0 obj << /Filter /FlateDecode /Length 178 >> stream xm̱ 0H-}SV08ͣ7#tP> stream x==@!$x.d@ b&ZY+hq%g+̛@.Wy!5||4gN>0U(N$#;NQ=_;!EFg ꚮ~3 |4ؚ4#\Y]gr1WOL$ǭ#bVOendstream endobj 138 0 obj << /Filter /FlateDecode /Length 197 >> stream x5; ` %79m`A'qRGECGEzcokB>bw!ܗ&QvGlE/rPPMycEQѷ(5ҕ;i?͒5-7-ǫy! ^P+́<$r4+n "ID>8q?Uendstream endobj 139 0 obj << /Filter /FlateDecode /Length 216 >> stream xEαn@ PGNO_KH@b!`b@L#nvH0e`'wgFJ)S)gG, 톊!څTVK:V6t՜b%71w%;]ͮ:$δ & nKoW1]ЋputF@uFjM0>ɏ) N6#0˾ j5>[endstream endobj 140 0 obj << /Filter /FlateDecode /Length 224 >> stream xMα@ )iBy` A++Q);l3j:-(#IorNjNӜNP6hW%OR9Q[Qv$QKRvrM`> stream xm= 1F'Xxf׍ Vº[ZYZZ( vz4GL?13yL`(d8.,mv}zsQ]볝bʶxޱ-cIٖJ%YsU f7[q(hV젨[it'zS[ v.Q*FEQ"x ?>&Twseendstream endobj 142 0 obj << /Filter /FlateDecode /Length 203 >> stream x}Ͽ 0[дtj3:9::(> stream xuн0[xDD'㤎]GQxFB1K~\q4CCM1x "֡ΐJ[1𥎁ޮt=x= W3ƼVTQSc6CC55Q>Rp(s5Mے`_==?ͥGrJ"ZSZendstream endobj 144 0 obj << /Filter /FlateDecode /Length 137 >> stream x313T0P04S02W01V05RH1*22(Bs≮=\ %E\N \. ц \. QqC=C=2p\   \\\8endstream endobj 145 0 obj << /Filter /FlateDecode /Length 273 >> stream xuN0ty @!R)`b@L 5X dcģ҉&~uD9մWӤn |0rsK*kN%Ƭ9;fT`6kl:AP<ʋفa2~z`j0:hoTн Y,lR7"fSҮ_‹ᰮ@c91XtX u(cAr6y.!nCI@qqHf `W4x?lendstream endobj 146 0 obj << /Filter /FlateDecode /Length 199 >> stream xڥ=@PL ȟ b&ZY+hxJ d)-bߛy63f%gtx0e5$ jOaj:*yAUlQtєg&̛}Nr 5r^ a2ʮ`i`r_zH&=| z)3WwFHHendstream endobj 147 0 obj << /Filter /FlateDecode /Length 203 >> stream xu1@EPLL 1D+ c&jQ8%gdB-^6gߑ;dO\q~ƨ4 Py*^r; SrPEqbtLR~3&0 > stream xm˿JAOSLs/ <{ F,JSP /6G> 曙ҟV녞kYjUrgq+q)L}.n|w>?J3QV{XuG>vv}1=@nȘ^@2"u)'n6?"2ģrL~Qendstream endobj 149 0 obj << /Filter /FlateDecode /Length 151 >> stream x313T0P0W0S01U01QH1*26([%s<͹=\ %E\N \. ц \. | @ v:QAA=N ?@J@#`p`\z> stream x=1 @ER~- g`#8RK EJ4RZ(ޑ'̨i> stream x313T0P0"3#CCB.#)T&9ɓK?\ȒKCKW4K)YKE!P E >'W $endstream endobj 152 0 obj << /Filter /FlateDecode /Length 99 >> stream x313T0P04F )\\@$lIr p{IO_T.}g E!'E@!ncr eendstream endobj 153 0 obj << /Filter /FlateDecode /Length 179 >> stream x313T0P0Q5W0P0PH1*21 (Bds<L=\ %E\N \. ц \. @xD2?@,&=`C" ?ƏadjƎa݄lMI$b6LrzrrШAendstream endobj 154 0 obj << /Filter /FlateDecode /Length 221 >> stream xu1n@Џ(Vf\^PXJQ*;eDv mGt .4#Jنc^"U4aY:m_ȼqy1'ˎ2%'PU2| (2w(ڦE-zD6BF{DIڝ3?mgDj # Arf#rNN,t']c^al оWqi7endstream endobj 155 0 obj << /Filter /FlateDecode /Length 170 >> stream xe10 PW"y#' MKUJȀC X)GQz U 8eSI< e 15ߗ rKIr5JvDYPT)wK@1c5 0|2 GAw= /t:pZi|m˸иI Ptendstream endobj 156 0 obj << /Filter /FlateDecode /Length 229 >> stream xmбN@CA2 <əXg"WYBh<>%aKK6eg]B}}k{oxⷊ>.6-\WT<*#Syc]nyv@6CG'=D",2dfFz-mə1:;_w1|4t4hn7)xM> stream xUпJ@YR,LGȼnb.r6?` A+ RK E*-GHEq[E}\I)rVɢB+~ziRz>yzu^%k+snv#r69MD^HjO@IGJ3&`MS |08oF xo2("~B9~}B@BTB_Cmc1aH9ԝz xkendstream endobj 158 0 obj << /Filter /FlateDecode /Length 214 >> stream xe1j@[4'JT@!* q"JR n+s.*70‚,̃0ir$CdKyyωf^ˊ$9GlӃlKZhYqb~OC~OxCH7L-VhPjeL hA؀&jΨ\5әcts÷|*fendstream endobj 159 0 obj << /Filter /FlateDecode /Length 224 >> stream xuϱn02X%{D,Q*5C%N@ծu͏GCvaOoQϚGhI 5NXYQ39^pӢ>PB"m+}~|QovOdPoP2Gp=AΘ&n > stream xm1N@ D'JM_C~QH@Q%Z6T({-SD1Q Ѽcgqwm݉>4,mFG K=\ۣԻ3mm; d plFar&@GPي>pOc({zUAL/.ީ8|ksendstream endobj 161 0 obj << /Filter /FlateDecode /Length 202 >> stream x]; @GR2͚Dp A+ RK EBRZ㬺8N(->GCW;]@G5v*\ jwR]endstream endobj 162 0 obj << /Filter /FlateDecode /Length 251 >> stream xUN0/ɋ @Td H01NͣQ=X1bdoݿꯇNVknӟ/b+C~g7A~u}N7;yq'rTL6lq#T%TӤE jU$T;xؙVpya"Q1|r9@af6Mq@R{ ͊Ie,yZ,[Q?_Wuendstream endobj 163 0 obj << /Filter /FlateDecode /Length 241 >> stream xuϱN@K5 E+uM0bcl <Yumչ>*epUy> stream x313T0P04 f )\\@ IrW04 s{*r;8+r(D*ry(0|`??0 ? v'W a*endstream endobj 165 0 obj << /Filter /FlateDecode /Length 187 >> stream xU 0ES:ޢI N&O'8:knh@}7D%YgXnE68])$$ƒ~ܟv1ɂ1GG xos*!~Zo(k B" Pq>.۶{xcA+M;=endstream endobj 166 0 obj << /Filter /FlateDecode /Length 118 >> stream x313T0P0S04S01S06QH1*2 (Z@ds<-=\ %E\N \. ц \. c$! b\\\ϊ>endstream endobj 167 0 obj << /Filter /FlateDecode /Length 187 >> stream xU @ O Yxw8jotr'utPQ5I-$f2c-Z)+GZv*C@Hx=Π9sT/Ԩ"kF㇠ZFQ"7!\LŮ{kw; #e%(𮈻i^/aTtY!)y@,=l M>kendstream endobj 168 0 obj << /Filter /FlateDecode /Length 188 >> stream xU=@`6$p.?`# b&ZY+h+L9 Gذ nKfQ!!^CUdx[a> stream xmбn@ 1DG@ CT*CdPeJ;vhծGQxFkDd>;zWMrMMف5eJYƿ?mvϬ ΏToHN [`CZ,{ê3VZw LRD%ڻ{F:lZY> stream xڥ=N@Xi=B,  * D)S&\7GH6.DIi53oXk]꥞Z\ޤY\jw^%{"e;xIVV;RoN>`a}x3 HVmHb&oNhh:+Tp=q::Ϥ>F_/C21eya:#f`x!7<=cendstream endobj 171 0 obj << /Filter /FlateDecode /Length 208 >> stream xuн0k#xO `D`qRG(}FBЄĤ~pE.-K =zh.wStlytGN_NgL\kZZo-T c ښ[ۺ8Rf_yOwy_6|pdmA&:QV&ҘP$> stream xu @\z'H  ԩCtEh>уhkeͰ;Sr#&ttBpvd31[%OюWtOh9qh璳8"hre)Q5VzV \4 0i:ul3%Rk-Le00JKE|}xBendstream endobj 173 0 obj << /Filter /FlateDecode /Length 186 >> stream x}1@!$pBBEHaRK .G(.ZHI%ψ$ɧ)) EQgLs$"ܢvKs. yF R 0RG5X-؝X͠NPSϐnilbEO&4>=VgWX(9nn endstream endobj 174 0 obj << /Filter /FlateDecode /Length 232 >> stream x]=N04M8!UeHbD9%Gp²!4_fjOKO^swۆ^%k#n{27ocGf}w ?6\?Ѹa@=*ŀ2* : (}!WjtYW=-0|3?*| zclb`Q$9R 2S }Q:Hq/3@#7p@endstream endobj 175 0 obj << /Filter /FlateDecode /Length 193 >> stream xmA @'.4Z̠Yjei7( q 3o~f4\G3C|:x ҹ|pb"Q)PHK9OeJ5jPRn|-`Ys.9`6.?g[@K۴`Uf lvi)ʡJ渒/Vendstream endobj 176 0 obj << /Filter /FlateDecode /Length 156 >> stream x313T0P0b3SCCB.c I$r9yr+[p{E=}JJS|hCX.O0c? &p`Q"p@#`p`2QpOar IVRendstream endobj 177 0 obj << /Filter /FlateDecode /Length 163 >> stream x313T0P0bcSCCB.c HrW0r{*r;8+. ц \. 001 `LAȃ=`Aԃ:\?DԡQ?Q \\\[endstream endobj 178 0 obj << /Filter /FlateDecode /Length 242 >> stream xmбN0?`閼A' X*E"LSad`y^o+dc$sT@|89:]NT8V4)[bFw)/=e3ynr5z z^AH ^_kO mb2{ o)޼IPX5`j5҆uiSy 9i^Z&WW9+ow }:难{{endstream endobj 179 0 obj << /Filter /FlateDecode /Length 221 >> stream xmAJ@tx9B FSjtB\U.jir(sn }|2)$9?J\ze\)7oϔ-o/Yr>RbGx+$qP-T 8a Hڔ@\fgm{`%NGPik,F=pk0jluo-9m骢;[|endstream endobj 180 0 obj << /Filter /FlateDecode /Length 194 >> stream x}ν 0+['SV8sh}>B.E$$q4MS;Q)+!׾28^0+Q.zŚl s ,5yofJNѭ>THA-I?6*<+1vL{Ԣyˡjendstream endobj 181 0 obj << /Filter /FlateDecode /Length 244 >> stream xm1N048IUeHZ()XA 8WDAr)5cHœ5\+.U͵CT2,.[ҷ\/eL#93\SaXw>:@~^M:_6;~qLǠVrﻘJX&{ب#Izc&4~g'.zw'ʗ EJsY#袥}endstream endobj 182 0 obj << /Filter /FlateDecode /Length 245 >> stream xm1JPYR |s}!` A+ RK Eʗ^a2Œ񟉋6̼yT尒x"p,\@_فs/*g. )&LOPvY`n ,{OěMx[l)zi&$vX?zΏE7 }tendstream endobj 183 0 obj << /Filter /FlateDecode /Length 163 >> stream x313T0PaS 2TH1*21PA $ɥ`bU()*Mw pV]  b<]HG#13acFT0ca``?p`L> stream xm= @irYV ),J--mM8mR,dgbF)MidPaly&T'͞ Zh = vA͒#Kv07}> stream xU̱ @ B>y;mB`A'qRGE7ih}>BAyMI!xLH4PЗt0F#F 5Q$ rJ ELErILY [A37yxZJҖ^ yY\-n-!vjQ8)|%\0okendstream endobj 186 0 obj << /Filter /FlateDecode /Length 196 >> stream x}1 P _ YzbV8=Z#t3$BHGd67#fKcQ"&rRVP7IDc yܟ Cl#, pN3ExLuH %=bԏ=SZ`TI4JV^B ehFv}Zendstream endobj 187 0 obj << /Filter /FlateDecode /Length 167 >> stream x313T0P04S5W05P0PH1*26(Bs<=\ %E\N \. ц \. 30߀JNa!?#I0#;xI#> stream xu1A50]c&k%P)DRAhQA;C_ V:F:i]yYm)5КԸI T:"$a"X B$֞?!#rljtjCsehx. MO {}RmU@#C3zTendstream endobj 189 0 obj << /Filter /FlateDecode /Length 197 >> stream xU; @? ` A+ RK E[7GQr)h1/t)ZEyɗϴOC-*2gd6:%Smx],vKȬqzjHHHC,10\qEqRc,S4EB訵H<,l)o e@)]X!uE{/^qendstream endobj 190 0 obj << /Filter /FlateDecode /Length 212 >> stream xuϱJ@_RG> stream xڕ1 P q(dGx9OA ZN⤎m֣xҘ!$!'3N*Φ|INY>-KNɗ[~>^W݊SSNNT D'Ҡi!4y;쑷Gwp{cjCe s]ؗʞZ."US9©-KIendstream endobj 192 0 obj << /Filter /FlateDecode /Length 193 >> stream xڕα@ .<} L &`qRG;[pqᾤ 5)+H+9s<^&|XLפ*L,r0S⺡MNMC $z11wx!"><Zi&N?>cH RaH'c ˁ:ѴmO, YKendstream endobj 193 0 obj << /Filter /FlateDecode /Length 201 >> stream xmPE4K BBrmM>}}V́;ܹiԥS=T'u9&a+NFF⻥OK+ VZ[( f#2;܃J>PDCv@Z }•cC 7'* 4u.7mp b2rcZI_endstream endobj 194 0 obj << /Filter /FlateDecode /Length 154 >> stream x313T0P0asSCCB.c1s<=\ %E\N @BA,@Az H?*;&p4Aka[~ `1.WO@.^endstream endobj 195 0 obj << /Filter /FlateDecode /Length 253 >> stream x}J@#E`}!k.p` A+ RK E#U(y[,gǰzqꜟJz`;볟 Z.(wk~x|ws%{/xv4lnfxYDdItSn\#7@efd=`El6X4jB*`f}E_h0bj1SL̀,x>v*!*:MƢ:?-y%ۧF@-7>endstream endobj 196 0 obj << /Filter /FlateDecode /Length 161 >> stream x313T0P0bcSCCB.1s<L =\ %E\N @B4Pe,B @d ?  B~oAd $?HzI8'W zendstream endobj 197 0 obj << /Filter /FlateDecode /Length 132 >> stream x313T0P0bcKS#CB.cC I$r9yr+r{E=}JJS. @-\.  @x@@?C1;}pA|.WO@.O)endstream endobj 198 0 obj << /Filter /FlateDecode /Length 198 >> stream xڝ;@%$p.H)L0VjiVW(x[_~0E_cƃ=2b4gA ΄Sp)-8lsQyendstream endobj 199 0 obj << /Filter /FlateDecode /Length 115 >> stream x313T0P0b ebUel䃹 \.'O.pc.}(BIQi*Sm`Pz<7,{\Wendstream endobj 200 0 obj << /Filter /FlateDecode /Length 171 >> stream xڽ= @[&G\@7!Q1#X^,7[n8ȃW3r9Al&]'-\,cx܎` s0 n ==Cbq1 SeKvI'mr/)T8R`5zfendstream endobj 201 0 obj << /Filter /FlateDecode /Length 155 >> stream x313T0P0bcc3CB.1s<L =\ %E\N @QhX.O$$PD2`$ȃ@H&?:7 q.WO@.llendstream endobj 202 0 obj << /Filter /FlateDecode /Length 183 >> stream x}=@XLvNBLH0XF[٣Q8ab^2}KJ)*%Kw4 +@@)juE]VQzB[_P :9o.A@9(dq%7@'a/=ߵG.^Tyh p A!\\[>P:endstream endobj 203 0 obj << /Filter /FlateDecode /Length 200 >> stream xڥ= @g fI"SZYZZ(ښͣ[.(wS|7q4HRYs_8 LWCNv?$#(%p:lHj&5pGٌs V,S*7;(&A]t, -GT@8=F> $_ȥF<5ޯendstream endobj 204 0 obj << /Filter /FlateDecode /Length 158 >> stream xڭ1 @ПJuj!Fp A+ RKAEh9JAqc![̃I`4-ØԈmjw쎜{Vky\Y\/|9êe_Hx+5C8#$RC\B"xo<Iwendstream endobj 205 0 obj << /Filter /FlateDecode /Length 185 >> stream xM1 @4!s7q5@T0XErr,,2ԎgDM&rv=pr^ًYMyaoY!RrGB7 }KD#"eZSW!("PB Ca}96A=> stream x313T0P0bc 3CB.cS I$r9yr+r{E=}JJS ]  b<] @AH2`h AA~[@ Lx:Bendstream endobj 207 0 obj << /Filter /FlateDecode /Length 148 >> stream x313T0P0bcc3CB.1s<L =\ %E\N @QhX.O` $0()D? d=H2cģd>endstream endobj 208 0 obj << /Filter /FlateDecode /Length 186 >> stream x5= 0W:oN`B`A'qRGE7^̭ ء4ؔ? ,&Q@>0[}pb*Q)QzܟvI>>yG:J^]S |-,ZHZX:^<r[C准qzb&gaQ$Lendstream endobj 209 0 obj << /Filter /FlateDecode /Length 174 >> stream x313T0P0bcc3CB.1s<L =\ %E\N @QhX.O `?aC00~ @2?Dv`N2~+ߎ #ȏߏ`` ?G#g``?A6 H@RՓ+ ɝmendstream endobj 210 0 obj << /Filter /FlateDecode /Length 202 >> stream xE; PEoH!LUBBBN!۲t @!L@,a̻{ې lfOÄܒZrɌOp>ܘW!kJ/LnRQ;H(+p{h/ O.ok> 44W&F&R$}xY&endstream endobj 211 0 obj << /Filter /FlateDecode /Length 237 >> stream xEαj@ dz)CB=ҩCɔdnvj:t&=$%p!:d-"zX!ZnhyxDQd}LKႲ)ֳ[{vȭ+OPy5 @U-G[;z[*lB;v\ɼHer;SHR Z88 ~Ka{endstream endobj 212 0 obj << /Filter /FlateDecode /Length 117 >> stream x313T0PT02W06U05RH1*22 ()Lr.'~8PKLz*r;8+r(D*ry(01l;cNJ l r \+endstream endobj 213 0 obj << /Filter /FlateDecode /Length 116 >> stream x313T0P0V0S01T01QH1*26E-ɹ\N\ \@Q.}O_T.}gC.}hCX.O A-4v@ ù\=emHendstream endobj 214 0 obj << /Filter /FlateDecode /Length 136 >> stream x313T0P04U54R0 R M F0\.'O.pC.}BIQi*S!BA,???PP'W ,5endstream endobj 215 0 obj << /Filter /FlateDecode /Length 103 >> stream x313T0P0W04S06W02TH1*2 (B$s<,=L=}JJS ]  b<]0 szrr$~endstream endobj 216 0 obj << /Filter /FlateDecode /Length 99 >> stream x313T0P04F )\\@$lIr p{IO_T.}g E!'EA0XAՓ+ ;endstream endobj 217 0 obj << /Filter /FlateDecode /Length 157 >> stream x313T0P0U5W0T0PH1*26 (Bds<=\ %E\N \. ц \. @#HD؁:Q'@&> f0d82>3 df Dpzrr@:endstream endobj 218 0 obj << /Filter /FlateDecode /Length 203 >> stream xڝ= @_L#8MLRL!he!Vjih'({!q-6߲`}t!'<8 91 ũ piNfqJf)c2ot=̜w{@^m W÷x: dTLdO_'X`*w]!WҢqz9KU" }}dendstream endobj 219 0 obj << /Filter /FlateDecode /Length 141 >> stream x313T0Pac S#CB.# I$r9yr+Yp{E=}JJS ]  b<] X큸7001;j?0FJendstream endobj 220 0 obj << /Filter /FlateDecode /Length 222 >> stream xe1N1E*i| .-V Ab $(UAݣ(>B,?kWEwk.i;O%/$=iI^>$nF6x0ڄʬ ͎X⌾T~fGvlgOȠ<|HTGǂ+ˇD5WTL3*=2,<8hendstream endobj 221 0 obj << /Filter /FlateDecode /Length 226 >> stream xEнN0 J^ @ZHHCL @>ZlDZTe}9W|Qps}ů}PYkP|N#5[ Sj~??ScNzDDFM&4=:4WL hLVښQ5A1;,wKi sęǐ dw;-y"ͧ\ۼ>[z3Vc4endstream endobj 222 0 obj << /Filter /FlateDecode /Length 181 >> stream xڕ=@!$p. b&ZY+h pJLh$%^5Y (xTHN)74 U[QcL uMĄB9ƛG3a(if M( /#`cV2OZ˿Z;5tendstream endobj 223 0 obj << /Filter /FlateDecode /Length 207 >> stream xڥ= @4{t&)!BBB,xxqFE惝}ov)ZRGk;Sʱڬ)Nюe6aܠOi(Zb>$\Cǹ.5Tº)7 P \)'ߘ'-,e$9ґ i `AY ֚ G9-cendstream endobj 224 0 obj << /Filter /FlateDecode /Length 241 >> stream xm1N0E"4 @TE"Th+)S ͓=3uE5w|pWs/ 5gFGn{n5j+UknS=6@! `dHp糢0g0p \ύF<'"DMbLz[Zj6]*7DE??(jALP5ˠGԡ(OY*G@BR栛 5pIendstream endobj 225 0 obj << /Filter /FlateDecode /Length 183 >> stream xڕͽ 0+- h NB`A'qRGE(}zWEq _~3#)';#I~C"cQ8|Q iT5t] '`010%p1 iBt*Rt 2;nB)4_T+~Ѭ.:\Mendstream endobj 226 0 obj << /Filter /FlateDecode /Length 213 >> stream x}O @`qM>!zI 0XɧSW؈p w3s3Y:'sÄ1P{~s8Ӵ$4'tcot=w {* (D`D:y#jAԠBQSQ]9h@9׆mƠ3/"-PIoәn ժ?|R3{6nR}Znendstream endobj 227 0 obj << /Filter /FlateDecode /Length 245 >> stream xm1N@ Ema|HBbE"Tj`&GkH 4أnv+4rVISJ{!Orݢ~9^ꖋknR*.PI^((`)3Sژ1+-:%8p'?, \%ᔀ^ÊH"4)MP9%7Hi/! GdL!n&{| JMc_u|_!rendstream endobj 228 0 obj << /Filter /FlateDecode /Length 107 >> stream x313T0P04F f )\\@ IrW04 s{*r;8+E]zb<]:\={-=endstream endobj 229 0 obj << /Filter /FlateDecode /Length 184 >> stream xm=` .߁1D'㤎]ċ8p n #~$(}L> stream x}0K:#pO`i1NI4 Kd0FMj\ijx@½%\PPGL2P[2;|=7P~K<Ls 9y|9#l K#vӜ_[ZCN _CF,a8[NXTQendstream endobj 231 0 obj << /Filter /FlateDecode /Length 147 >> stream x313T0P0b#SCCB.c HrW0r{*r;8+. ц \.    `|$lthvb)،6 Q .WO@.̌rendstream endobj 232 0 obj << /Filter /FlateDecode /Length 145 >> stream x313T0P0bCSCCB.c I$r9yr+[p{E=}JJS|hCX.OH" $`@CLmQD !( ,xendstream endobj 233 0 obj << /Filter /FlateDecode /Length 108 >> stream x313T0P0bc SCCB.crAɹ\N\ \@Q.}O_T.}g E!P E >Փ+ HX~endstream endobj 234 0 obj << /Filter /FlateDecode /Length 123 >> stream x313T0P0bCSCCB.cs I$r9yr+s{E=}JJS|hCX.OLŘN|? ?*fendstream endobj 235 0 obj << /Filter /FlateDecode /Length 174 >> stream x313T0P0bSCCB.cs I$r9yr+s{E=}JJS|hCX.O0"370`H؃@`?#^^Q`Cƃ-Y  f $700 F"b\\\wNendstream endobj 236 0 obj << /Filter /FlateDecode /Length 197 >> stream xڕС0jrf{::"#a e0XvtmCOh)T^ aLiOvG ֤FscT,r0ʖSiNfEN`Y9Q3pqNN3O0n ZJ4&}5ty+A -ؼ+ԀW2>z endstream endobj 237 0 obj << /Filter /FlateDecode /Length 236 >> stream xu1N@ E"a|$H" * DH$*\!G2HQwmT 娔DJsՠg?x#Um<>r\Iq+wn˜24wC0MLNLtA 9a=tC68yF̛aO2/a<&E>oxvendstream endobj 238 0 obj << /Filter /FlateDecode /Length 124 >> stream x313T0P0b#SCCB.c HrW0r{*r;8+. ц \. @†H0 z(QՓ+ +Tendstream endobj 239 0 obj << /Filter /FlateDecode /Length 167 >> stream x1@G(LtYY +D ,ZZhq@IaGhf'_Ϭgɂ#}SqblF.b27+e=Z3bÏB&.ْ`9:Rs)U*H]J^w¤%HRQC/~*hGo8endstream endobj 240 0 obj << /Filter /FlateDecode /Length 114 >> stream x313T0P04W5W01T0PH1*22(Bs<=\ %E\N \. ц \. a`?r 5ezendstream endobj 241 0 obj << /Filter /FlateDecode /Length 116 >> stream x313T0P0V5W02W0PH1*22 (Bds<=\ %E\N \. ц \. c``pzrrlIendstream endobj 242 0 obj << /Filter /FlateDecode /Length 104 >> stream x313T0P0UеP0T5RH1*26 (A$s<≠=}JJS ]  b<]'W *endstream endobj 243 0 obj << /Filter /FlateDecode /Length 191 >> stream xm= @ x Ղ?` A+ RK E[)S,;h%Xfh< }:ex\T:8^pVQ>EmqF;)C}FE$ sXBט^Hȃ@?|bezYETZ_q-`R!a~K<.Kj/\endstream endobj 244 0 obj << /Filter /FlateDecode /Length 187 >> stream xڝ= @g"#Xraˀ!N;GYg!BR@[]/w%ܔ|q&?,Lƹ+x"ҡ@yRx -0遍~*?umֽr!0e] EӐ`%Ж*szendstream endobj 245 0 obj << /Filter /FlateDecode /Length 182 >> stream xڍ1 @EIk9 n!he!Vjihh%GL2Φօ}g?ofǜlS>'t#k5?;2{Zd܆L]rBC\"iJzD=[5/jLAOQ~ߏ@B_Zh4J5Ϋ^RMuZ9uEJendstream endobj 246 0 obj << /Filter /FlateDecode /Length 198 >> stream x3134V0P0V5T01Q0PH1*21PASKLr.'~PKW4K)YKE!P ETz !HԱ` |P=iu D)ph<krF=A?0`> stream x]1 @\B/ 8M(+Tr!bI q23;9nvdC)lGUgwIBf6$32d@fr@&m)2ϩ\^sϵ2HQRQO5QJrh MTrL@V@ endstream endobj 248 0 obj << /Filter /FlateDecode /Length 141 >> stream x3236W0P0bcSKCB.# I$r9yr+Yp{E=}JJS ]*c<]70| C`003a`\=&[endstream endobj 249 0 obj << /Filter /FlateDecode /Length 237 >> stream xڍJ1ƿ00 v^@9Å+T[}> stream x3134V0P0bS CB.C I$r9yr+r{E=}JJS. @-\. ?&iNa`D~700n?D䇁$7 \\\yendstream endobj 251 0 obj << /Filter /FlateDecode /Length 122 >> stream x3230W0P0aCS3CB.C I$r9yr+Zp{E=}JJS ]  b<]0@A@8~? q0\=(CE`endstream endobj 252 0 obj << /Filter /FlateDecode /Length 150 >> stream x3236W0P5Q54W0P05SH1*22 (s< =\ %E\N @QhX.O  P?`E6?gc?P~.WO@.Wendstream endobj 253 0 obj << /Filter /FlateDecode /Length 196 >> stream xڵ1 @Еir3'p.#BBRPQr0E:? d37u.{ʧHrCqJzƁGz$15x2`ts [R?L3؂rkm;x3HKv@%.oԐ nn**ɍ@ÔDrendstream endobj 254 0 obj << /Filter /FlateDecode /Length 108 >> stream x3230W0P0aCS CB.C I$r9yr+Zp{E=}JJS ]  b<]?0! ̃`qzrrƂQ.endstream endobj 255 0 obj << /Filter /FlateDecode /Length 177 >> stream x33R0Pa3scsCB.3 I$r9yr+p{E=}JJS ]  b<]?`@=:773n? Da`N``` O7Nszrr#߈endstream endobj 256 0 obj << /Filter /FlateDecode /Length 147 >> stream x3134V0P0bcsCB.C I$r9yr+r{E=}JJS. @-\. ?00`D~70n?D䇁$0I.WO@.e%endstream endobj 257 0 obj << /Filter /FlateDecode /Length 188 >> stream xڍ1@E #0e6 &naRK v9GTd)HN^f̦ǚ95(EqߜR{cRkI ? ldM*H&g8^WSQdHVR!J*- i~ nN/ookg$AH> wlzZIKendstream endobj 258 0 obj << /Filter /FlateDecode /Length 196 >> stream xڝα @ HByuj;:9::(>Zp"]qQ |CB?2ܓ1G!#I:Ramd$V$fO"tٓH$R^K6ʯ\UW0/%>T5*4hy~> stream x31ֳ0R0P0V54S01Q06WH1*21PAScTr.'~PKW4K)YKE!P E0a<|?`0?> stream x3635R0PacCcsCB.# I$r9yr+Yp{E=}JJS ]  b<]3P?n3 ~o0ah`?PszrrjFendstream endobj 261 0 obj << /Filter /FlateDecode /Length 195 >> stream x=αJ@Xf x{`TSwZ * W6`"8%Gf|q~K.4pR^j<> stream x363T0P0T5T0P05TH1*22 (Ads≮=\ %E\N \. ц \.   W  @ @,?(fQ 0pC sC3=;?f.WO@.uHendstream endobj 263 0 obj << /Filter /FlateDecode /Length 153 >> stream x3134V0P0R5T01Q06WH1*21 ([@ds<L =\ %E\N @QhX.O `J`pB`왏I@.WO@.1cendstream endobj 264 0 obj << /Filter /FlateDecode /Length 183 >> stream xU̱ P#k[WJ' rjj Ɔh>`Phj @ B\Q#HEldȗ$"Sg3:.{|LVkRj_ ..X ,g0i) <p&A=j|c(vk]b=(ԿOI |F?endstream endobj 265 0 obj << /Filter /FlateDecode /Length 233 >> stream xU=KPs Xxv(zb`A' Q|A7|~Lx`7UN?8g!Aj"z$r~nhdHڙdrO/$GcHN* WUP6Aߴ45q " bx%tq_cGŲh;L t5<fOk2|+ZlECd(IBY_endstream endobj 266 0 obj << /Filter /FlateDecode /Length 210 >> stream xMν @ )(> stream xUj@Yi nZ$sSEGQ|x I;=F(N8^D!qiIs ǔB3I-1QYAg//74gZv* 0ÿ+]SCE@QsϰF,IqSn/'gCb^mmjg`1'>ڟKendstream endobj 268 0 obj << /Filter /FlateDecode /Length 183 >> stream x%1 @@$|'0+AA),DQI:IUuO)Fh~!;:c̐ېዬQ֑)HpIH]RY#H[m(l2Oe-?uC endstream endobj 269 0 obj << /Filter /FlateDecode /Length 175 >> stream x331Q0P0bScSKCB.S1s<L =\ %E\N @QhX.O g``~?`g N}`o`F¢0?Q\\\ endstream endobj 270 0 obj << /Filter /FlateDecode /Length 172 >> stream x3134V0P0bSKCB.# I$r9yr+q{E=}JJS ]*c<]0A?  @CA2@5@D!dPICd \\\^endstream endobj 271 0 obj << /Filter /FlateDecode /Length 154 >> stream x3134V0P0bSKCB.# I$r9yr+q{E=}JJS ]*c<]0AI~ i"?P3@JR|Z0 @&\=) endstream endobj 272 0 obj << /Filter /FlateDecode /Length 109 >> stream x3230W0PaCs3CB.K 'r9yr+Xr{=}JJS ]  b<]d7zl+ -@>'W /endstream endobj 273 0 obj << /Filter /FlateDecode /Length 122 >> stream x3135R0PT0T06V0TH1*22 (Ces<=\ %E\N \. ц \. 5 5g" 1*Êl*,,0'W /67endstream endobj 274 0 obj << /Filter /FlateDecode /Length 130 >> stream x-ɱ 0 g 2'0-k3:9 TGAEfڢ|7lXU:x@='e; m;P=fpq}kw+*\ǣҟ;ZFy2ddL*R!sBY ,P#endstream endobj 275 0 obj << /Filter /FlateDecode /Length 189 >> stream xڝ1 @EL70s @BBZZ( 9Z#XZ:IVt« 3Or#xjBN%7nt8SjImYǤ+]'RzΚT;l@TJ @ hxjze/ ]a;AdD/ak+?iTRS" }G@endstream endobj 276 0 obj << /Filter /FlateDecode /Length 188 >> stream xڝ1 @EL/ :ͮA"EVbE$Nxg1q߄l">h.!Ǧ^OXRcR 7'e|ޏՌ5ٔs@ th~//iKxO`LГtIVx?>(=Cuڕ/@RriniMoEBsendstream endobj 277 0 obj << /Filter /FlateDecode /Length 105 >> stream x333P0P0U5S03P0PH1*25 M 2ɹ\N\@.}0PRTʥ`ȥm``C'W )endstream endobj 278 0 obj << /Filter /FlateDecode /Length 131 >> stream x-1 @E?^ xЙmV"RP:ٙ&Nwo\%红V\xA=y1:nwՇ Y/ t4M22DT&2+<*B#endstream endobj 279 0 obj << /Filter /FlateDecode /Length 94 >> stream xM=@PEx$^!R { T߱4J2:*54`ƴ"f@BJJ7"i endstream endobj 280 0 obj << /Filter /FlateDecode /Length 94 >> stream x3230W0PaCsKCB.K &r9yr+Xr{O_T.}gC.}hCX.Oz 0X [\wendstream endobj 281 0 obj << /Filter /FlateDecode /Length 153 >> stream xڅ̽A ɉ̗eSH" ͣxwN5gvZ88Kb񀷲>7TzOoײC _.)k̓<j*zP R.NO|[ƧmdSL6e\6NdV;x*endstream endobj 282 0 obj << /Filter /FlateDecode /Length 188 >> stream xڵ1 @EH!L#d.ͺB` A+ RK EBbGRRl6Pt+ǬƬ5$Ii;Xf$#aI,Dv$f,I(K~ |[jWopG!SE /zO6x+ӸY~uд`endstream endobj 283 0 obj << /Filter /FlateDecode /Length 121 >> stream x3135R0P0bc3SSCB.# I$r9yr+Yp{E=}JJS ]  b<]0001; aX*6T?0'W Nendstream endobj 284 0 obj << /Filter /FlateDecode /Length 228 >> stream xmαJ@o"0M^ป'pWSZY `eh>J+5E~;Yct_^iC-/+9u'Zst }{} ,, %s'l"aAZқMY'W Tc|endstream endobj 285 0 obj << /Filter /FlateDecode /Length 235 >> stream xu1N0ЉRX`3',ZiY$R AE GQr[0"OʌǓ/^ҟ+Vɾݭ%+yxb>F:iy-29Q EPE6fLV&b&e6fՎY (y/ifU _ cBԨM>y2_ |Ǜjhendstream endobj 286 0 obj << /Filter /FlateDecode /Length 188 >> stream xڕν @ + At-('𮶵kotrP?Q_ I+F!=ړ,o)$G$'KROt8oH&{$S^zVSBĢ iAf1h.p;`Z \2oߛy544`endstream endobj 287 0 obj << /Filter /FlateDecode /Length 226 >> stream xڕϿjAna s=b!j WJ!`R nGG8̜EH:_1;dySpnyΟ9)_6[d?9oR&[}";YL9#;e銊Һ„pQ*+j .+xs7xĕ\ }rR /:tKuNTc'ې'jiT2Dׂ+Xendstream endobj 288 0 obj << /Filter /FlateDecode /Length 243 >> stream xmJ@O"p}dXW0 j)h()SDm>{uuVZjG+9}Mjag"VNbkx|JV+-*@ Ps&[ D>#E@rI~2> stream xڕα @ HB}Ѽ]`A'u(GQ|TZ?$w#3ihdȎhC!s8cТZp*Yz?WS2f5wHPQY 4a:B@ 8 1n -SQR-8 d_Ѯ+J_> stream xMJ@Eo[8м$AB`B]W҅E ;#Ǜ*y{wquLZZj}%OR7KmN~&wlֺ₲<>H\i%Jo*-o])L O[ `;d1a3X`LpM6{{xSHp|tO01l6 i4,e3zwgRS@v伕+cendstream endobj 291 0 obj << /Filter /FlateDecode /Length 237 >> stream xu1N0бRD@\lBTE"T AKr!e3 gi_'aE5tB 2(_pӢ&1^_v7T]M=[b.'0S2*(ٌ`&p B!t 灼__Rc%ɞ 6{6C!Ic)A?XZ1IN+OVqY- m9endstream endobj 292 0 obj << /Filter /FlateDecode /Length 101 >> stream x3230W0PaCsc3CB.K 'r9yr+Xr{=}JJS ]  b<]d7`= 1S'W fp"endstream endobj 293 0 obj << /Filter /FlateDecode /Length 140 >> stream x3230W0P0W54S0P06SH1*24PAS#Tr.'~PKW4K)YKE!P EA 30` Px҂!Փ+ &,endstream endobj 294 0 obj << /Filter /FlateDecode /Length 107 >> stream x333P0P0U04T03P06TH1*25 (Aes<LM=\ %E\N \. ц \. Aj-\\\~,endstream endobj 295 0 obj << /Filter /FlateDecode /Length 185 >> stream xڍ1 @ LMBVbv9Z#L!W0as_DhO-%CX턏ӆt2r@:兜YMz&cPpte] 0.,$+IJ_Fn_o^:, v;rendstream endobj 296 0 obj << /Filter /FlateDecode /Length 235 >> stream xmj1 ^=;Od-$AhO=Xބͣ{N"Q6>fB&?N'izmf4Z||DJƠz.rM/T%V~rEP@X8 \IU{3bY1Ez$'i=Sː†LBp6Pu 8:R [49޲&&Z'XΝ_%mendstream endobj 297 0 obj << /Filter /FlateDecode /Length 209 >> stream xڕ00#pO`Amd3ALd08Fgh< @ڴ_e4f, kӄqH2@5(xEB3 i3 5C8ZA/:L^pXpkFbIF2qUNCE>_c+vdn&~VPendstream endobj 298 0 obj << /Filter /FlateDecode /Length 260 >> stream xڭѱJ@? LaZ 4ܪ[-'BBRP̛*y+uvg!B#n;MG4Zly\Ѣ瞚-Sӟ-5#%_v^QdRPDZTRR OԵ@*(AWE],RIR57P&?2oƐ(~#FLg5=dF#zvL;mf&,mXJ[a # }R:%e-vvS=U:霾esendstream endobj 299 0 obj << /Filter /FlateDecode /Length 194 >> stream x3331V0PaS SsCB.S I$r9yr+p{E=}JJS ]  b<]Bc``D@.0L1S?UB7@`JJ=SP (<9P@=mrC%hAC!@ y`> stream xuб 0  /0 D4?/iLsqINƪ&v)9 O44FQ5o3j ioKk2 DdFLƤ1(C8^QDɰ|p1۽."byҀ)gk׿R?U~endstream endobj 301 0 obj << /Filter /FlateDecode /Length 166 >> stream x353R0P0bSCSsCB.s I$r9yr+s{E=}JJS ]  b<]d `6`RAI68؀L2`%Hv0)"G'!P5Ⱥ AJ$ `G@%\=Mxendstream endobj 302 0 obj << /Filter /FlateDecode /Length 254 >> stream xڭѱJ@?l&yM"&`p` A+ :--7`kMg+ & XKf]{t\)pp{ =SuV=UvT]j__Z]>5(6S`-̗oնd IS03aLlB".!1Ox&pcJ&HۅrI)ܔ_,v0{ltT颧endstream endobj 303 0 obj << /Filter /FlateDecode /Length 125 >> stream x333P0P0bSKSsCB.SS I$r9yr+r{E=}JJS ]  b<]?T b78) s)hb y.WO@.!7endstream endobj 304 0 obj << /Filter /FlateDecode /Length 106 >> stream x3ԳT0P0aKSsCB.#3 I$r9yr+q{E=}JJS ]  b<]acW3v\endstream endobj 305 0 obj << /Filter /FlateDecode /Length 165 >> stream x3133W0P0V5R0T05WH1*26 (ZBds<M=\ %E\N \. ц \. ?@"000=o`#?0o  0X0`ao`27Áq \\\`endstream endobj 306 0 obj << /Filter /FlateDecode /Length 243 >> stream x]J@Yr̡@&A[sjsɃxj= Qj(y=HДeDz~,//Ue7~_G8"Ǎ;ΟGΗoKWn6^D8I F"!:+2oa[87`d`+hLMfp&byiguf0~5jRryd* Sk_ N9Lxods-5Pendstream endobj 307 0 obj << /Filter /FlateDecode /Length 140 >> stream x35ԳT0P0bKSsCB.S I$r9yr+r{E=}JJS ]  b<]d3 eR/i& 0 d`L?`@!\=Aflendstream endobj 308 0 obj << /Filter /FlateDecode /Length 244 >> stream xu?kP{<0p '% ur(vtـ]G|X#y=8. [~< 8:İ˵W|Ք.1wQ@jH>yo瘣1 ý 8hFx]*18yTB,a PM 2< fep\$I5+zG4VY5D NZ@fW'coQ!endstream endobj 309 0 obj << /Filter /FlateDecode /Length 243 >> stream xUпJ@/.0fMN?Sge!VjihkR\AKT֩$EuwM1f``w%=.>jRWRkRnKO/VSYZR7T@fm큼0 {düۘ=4]L3Ȧa@bli@T|`MLjb4L1dtFW$G *.|ؙtI6Dcendstream endobj 310 0 obj << /Filter /FlateDecode /Length 239 >> stream xڭ08#^@D'D::htGxWm~_LyxJsNgo(I5M7?/&~I#K CԼ*x1F%)dB 񑊅A8EjGU(Nk4, ~j}> stream x3535T0P0bS#SsCB.K I$r9yr+Xr{E=}JJS ]ry( , LS? 0adT Y;PCuP7 .ĵ'W Kendstream endobj 312 0 obj << /Filter /FlateDecode /Length 221 >> stream xڕѽ 0𖂁#x/i*U ~I(}JK "&HrtF*8 q0Y Ȁf4  ״ 2o@.08BDu uf,HW lf(ze~ަ_Q@6+L6elZv,XKP~EԺe֩N=v> stream xUϱN0 )K~h{=B @!Z̏F%Psw|J8êt0r^jE>U KWk=?ܻbuyJz_uEk?ƌ!fl#>3Z;@'7x &&ȖNm9R0!G/aEFD+E$ьMX^>a-M=:upǴ-i}GA^{sywָ+=#endstream endobj 314 0 obj << /Filter /FlateDecode /Length 150 >> stream x3Գ4W0P0bSsJ1*2" Fr.'~1PKW4K)YKE!P E?<@0g`A bP>T*L`)`J+F Hʃr Wrendstream endobj 315 0 obj << /Filter /FlateDecode /Length 240 >> stream xm1j0g1> stream xu1K0W v8b vtr@?')ΝCMHH^K^Y/PX.8\> stream xαJAYL"y.p1bLBASP=p2E8n@,ofgɌKWR+s8 5srzJ 5W7Y ~k%vTZ^{cٳUoC0˖*STB`ζ&%EQ0b43e}"_馡}lendstream endobj 318 0 obj << /Filter /FlateDecode /Length 104 >> stream x3230W0P0W52T02R03RH1*24(XCs< M=\ %E\N \. ц \. a0C \= hendstream endobj 319 0 obj << /Filter /FlateDecode /Length 102 >> stream x͎;@PggwAxJ!* %>Et300 UjrR豆iqA 5Tv̐ɩ p:_thq_hendstream endobj 320 0 obj << /Filter /FlateDecode /Length 204 >> stream xm; @ . Vf.1L!he!Vji(X({8Qښ}i<"Ńf{Qj{T3Qes:.{TŘ4 5E&6%/_x/PAP02g0yp&dBw:+0}ATyM6Ӣ5l.5iK|Tendstream endobj 321 0 obj << /Filter /FlateDecode /Length 198 >> stream x3134V0P0R5T01V0PH1*21PASKLr.'~PKW4K)YKE!P ETD0S$00|`A; 00* ?8Q"I&PMb`߁q ̍:]'W ckAendstream endobj 322 0 obj << /Filter /FlateDecode /Length 182 >> stream xڍA `'?(   AZDjX.̣y҅Tcu 7f: 5P L % MBb%_/#jƒ&Ύ҄Z{Ue5TƩ-ՇW6j@-OӉ;*`{^[bTd7 wSZ=endstream endobj 323 0 obj << /Filter /FlateDecode /Length 253 >> stream xҽN0T"GȽu~n! & 7+Q!ʟĄd嗋l4\jU<sMo4HQ {N^Kls/dKɮꑚgʱw_ s=$p8E . (sׅ42*ȱ| ]6&ܴLpڋ_IHGN!X>] 7#f".F?^Q 3ҙ b=endstream endobj 324 0 obj << /Filter /FlateDecode /Length 244 >> stream xڅJ1g"0M!`Dy[ZYZZ(ںy}<•aǙP1|?IO :1H=>cTPc;Ocw!^_[^ʙ;V8?dmgPj\Rq :dĄ* |Vbn;gE d1o( ؁ahDBc!D[o1En %in6N:\Z` æ]H_I<?y뭜endstream endobj 325 0 obj << /Filter /FlateDecode /Length 175 >> stream xн 0>B L*)j3:9vtPtnG#8f:M|~3z> stream xڥ?J@'X&G\@HBL!he!RK E֛L2ɮ9o[,Ƴw565>UU7v1.tqoYKtq ˣ|QђCDF"RcB|&;J e%wpU3B?O|G(^'f ]THد|X9/O8E.> stream x373P0P0bsC cCB.33 I$r9yr+q{E=}JJS ]  b<]0$0a aÐef0x:`P?H e00?C(v q'W l2 endstream endobj 328 0 obj << /Filter /FlateDecode /Length 138 >> stream x3635Q0Pacc CB.# I$r9yr+Yp{E=}JJS ]  b<]``0f+ɃԂ 0a@\\\٥;endstream endobj 329 0 obj << /Filter /FlateDecode /Length 243 >> stream xѱJ@)nMD BzQ|-#w_Z˷euG|]KkhFrw[r??ܓ[]rKn7-74B,? X -,fXNpMV%\{`r_ |7fZlP \X~r['-pG NZpZY̊4_HWn$endstream endobj 330 0 obj << /Filter /FlateDecode /Length 107 >> stream x3635Q0Pac cCB.#K I$r9yr+Yr{E=}JJS ]  b<]0a\=endstream endobj 331 0 obj << /Filter /FlateDecode /Length 232 >> stream xҽjA W#>WZL+vrp!ET+ -vXqt;';됱j-->xsiNY-gOّy+#CYEI O$Rx%4DJʤn ׮UH@Y$߸Np⧤D@(Ax^ 9Eۄip xviCendstream endobj 332 0 obj << /Filter /FlateDecode /Length 184 >> stream xѱ@ & &]xHLtr0NUy{ጃ zw6d4JBGqlfiG{1+P)QEz@-ibc|!Pi ౮!`{.TV6ߡA_y48+po endstream endobj 333 0 obj << /Filter /FlateDecode /Length 231 >> stream xڵ0kHnЂ0 &2`A3<#02^KL%!_s{I!.qa@CT9 +@P% 7 v+@x0> stream x͒N@ ]uG_.!MBH 02<Gx۹F:.˓"J:lN錞c|,5<WO(m(KѭEGWbtK=b$(#!@5@oJ 4{aŌfJ`o}4.lO%wm_mte4](z`_TU`endstream endobj 335 0 obj << /Filter /FlateDecode /Length 169 >> stream x;0 t#' VbTD$02`nQzT dj20XY陞c+4xRps?aq@iA W<ix=   E^6ɱC:_:Wѫ}O_ /h m Ij^endstream endobj 336 0 obj << /Filter /FlateDecode /Length 259 >> stream x]1N@4;ۊB$\ Q%ڬ\vY)yTk.拊57 UIJ/Kn6O\k*ybx[~|nXp8HDF#々~7'QȔ^;LKZ+45qj@.dtv!"ieh֔j]dV絳Su ?hgcfKxhGZendstream endobj 337 0 obj << /Filter /FlateDecode /Length 186 >> stream x3534S0P0R5T01Q07SH1*21 (Cds<L =\ %E\N @QhX.OON2bH$;&=A$3?8HAN7PJ`$H `( E` qzrr:pendstream endobj 338 0 obj << /Filter /FlateDecode /Length 187 >> stream x1 @   fl1[ZYZZ(Zkyt {O!(VhpZ0(j. 匴F91J3FNPf4W.dI K#ZX+ސ8 w6 .n N<sUv848nendstream endobj 339 0 obj << /Filter /FlateDecode /Length 270 >> stream xڅN@EPL'~ >X<&ZY+h+| K$\gfX){ʪߗu%B-k_Weʡ/ϯ7/nyS壼'7e"0қ0Dr92DI-٨l+s@!٘b4Hfoq!C?I?b`6|tC t} lLD2r1uIU'TuIk*T%5P%5!.>Z/1endstream endobj 340 0 obj << /Filter /FlateDecode /Length 310 >> stream xڅ1N@б\XG\8M,  * D "To+l"0DQXO]yx:NbYٔOG8'M~ea חG/pl%ގqtg%Qm3 "Vϊ<X1f3j ԄMVl!ey o+ =̃Zy[coFG\{SZƛЦQ?䍉`߈=m;4M?l½};YTjĭjө IPZlklku釾2#}UJ.҆Rymaɽendstream endobj 341 0 obj << /Filter /FlateDecode /Length 232 >> stream xm1j@*x-"cUZp@R)b.X:#T!vRYH ~Y7zVƷY v_ԿQ[ݓ;N{{W߹ʭ޵۹[J0)\$x " LY$> LQ~ 3 afˈLXF,@' .L h22#戜#䑁rm\-jhpendstream endobj 342 0 obj << /Filter /FlateDecode /Length 223 >> stream xӱn0`#HrOP' [%R3TuZsx&yT Xjw><?LF3k>m&Zb&RJ'/Ut1L|L) uUp)v -?@׌8;n=pOkq11Ecf՘1>KZ*t}w{7:y+}k(R Qtnendstream endobj 343 0 obj << /Filter /FlateDecode /Length 95 >> stream x31ֳ0U0P0T02T06W06RH1*2  !2ɹ\N\ Ʀ\@a.}O_T.}g E!P E?< r WGzendstream endobj 344 0 obj << /Filter /FlateDecode /Length 229 >> stream x͒1 @EG,is#Uew4c!r9_lD,lD[ΦB$:[RI9z% 7t | t}GI%EP_+M_*|u69X~ohFWjҚnD!> stream x3337W0P04  )\\&f  ,ɥ`bƥU()*Mw pV0wQ6T0tQ```c;0D0I~0Y"I ?&D(I"\=VIendstream endobj 346 0 obj << /Filter /FlateDecode /Length 301 >> stream x}MJ0)YؖG_]x>.]W҅h=Je? گiftߟ ChÞ6 s/\knCs%ux^ߟ\s>k o@B,D'DdZ"-,-B/63"x甙k p7q|$pF暿 dL@AvZHFӬYM5k|,ZdIeb4j`Mg!@Tt`[Bͻ.A8Ew̕bԊW'bt7}tendstream endobj 347 0 obj << /Filter /FlateDecode /Length 305 >> stream xڍN@LJlA gEr&ZY+h=> @IA烋 |gf.K xQz!eY^#[E{_o8_c#>UX>)EৣNGG#"qhfH8fEAEI=-Β%$#쵂H\Wfä hgcgݺi8iZG`s+,25\i`2[[E3)D/bZ1.8G IUuuR:X&oݴ]֯"Mߴoendstream endobj 348 0 obj << /Filter /FlateDecode /Length 225 >> stream xڽнj0 ['Pt!tP2;4qh~?G$C@Bw&,+]po1}R28^~в$IF~{͒/wu|'ܯ8&旘knLM@;&ED-tw>5 pU/jh:؊,PW+D5^ԝhma#:YVp=Dӊb~9ag/uwiS]]qendstream endobj 349 0 obj << /Filter /FlateDecode /Length 285 >> stream xڭѽJ@Y lGȼ&H +PN-`bu>r"X?L6']x\c[awO}͚L> stream xڍ=N0'’!sHRd E"T ()@ Qa-G#LyxcOx~ar Լ=>٦fqR57-ϱm__l<ږ[Od%2 9SQvTy2S T 2NXFvY _C!"%R/Q("!V$M x#$0"W ΈPr($7y?"^\%Id^EARiP7@t4F}ҷ CGɞ~\endstream endobj 351 0 obj << /Filter /FlateDecode /Length 239 >> stream xڭұj0`[heTA@=)Cd̐nQ58@mpCo'J,3~T>LVс%cMq<'$%$w>H?^Y\GGT %1s <(Gϋ(nhɝ> stream xU1N0E'JM`_)ҲH@Q- HaycARI?t5Uoqg|rzUA5TsϪnjwWU> stream xڍJ@E_H10y?(uSZY,Vjih|J>!easN2s߽Y'M+u)?Vֵ+nót㺶ȶɖ l]ū{m`Oè@A"dekv"DL8O92!~l@Nc@z.1aiŒBڠv?Qt>pC 4s9H]>0B/@ IL}~-&\^+vqpڃ :TN&Xa*E3q}Nd!ѫId/;{k?nfendstream endobj 354 0 obj << /Filter /FlateDecode /Length 267 >> stream xڵ=n@Ǣ@f9Al%"C$SX+V*;eDIpJ zְ̊շy^O=JftॽEzKIzWQ+DXQ:]L@GjQPizV8Jy<_oSrJ^CoCK(vRਾB,|.WKuɡ`DuO6KN6_i JGT+ɭ KPJ~ s uyendstream endobj 355 0 obj << /Filter /FlateDecode /Length 338 >> stream x͓?N@gC6QڸHaRK vF8%^0 Z-;;3|qvrXЧhsJL6~Em*iS^o*\R[}OT@WdR;Ȉ,QG9Ci 7rXK0A@$s;:>GOÔ11PVGG { r(ܑ  J}1*7S($;SheIL>oC^fi0ӤIΧ C4qHGnJ谬cC +{7Z۶> ࿢*E!en/endstream endobj 356 0 obj << /Filter /FlateDecode /Length 258 >> stream x1n0` x'b R"5SS۱Cd(9BFcWGRZ}l_Y1S#=e}EeEzYNzm6|<>I/O^捪ko?n>CK(I֪ov^سs`'rVr\w I˼ދ/np=g?;ؗ= 13rً E7Z1ӌk kmgj.=WMsendstream endobj 357 0 obj << /Filter /FlateDecode /Length 349 >> stream xՓN0 ]uPU"D$02`nyMNIܻEJ8v?ϊ xc\=83,OݣZ*ƲR9UZ_Jt79f^! 5Dň6X;ЖuH@cN.|͎r.m@γۯF|=Mb ִ`]Üb{)$U2ئ' ÄcW|rƬ,e9sOx^cfu=z.{6S1;Ae&oVgۛ`_#7ğ)NG YmvM٭f !&\oVW ?!endstream endobj 358 0 obj << /Filter /FlateDecode /Length 105 >> stream x331Q0P0bS #CB.C I$r9yr+r{E=}JJS. @-\. A(9TH:հendstream endobj 359 0 obj << /Filter /FlateDecode /Length 311 >> stream xڍԱN0o#O \<'H3D'㤎H GBI%)+,`z aJOJ}o 9ƙ={MyqB<>@<1f#q8&t3x=%T]_'V1 S>8|bGx ~ه_(Jf2Lc# ן8~w[stJptU,r,]#c},=3ֳTc)frLiGvKA;+DE 1]*YB8k ~oLendstream endobj 360 0 obj << /Filter /FlateDecode /Length 209 >> stream xڳԳ0U0P0b c #CB.s I$r9yr+[p{E=}JJS ]  b<]8J,fn0ªc5CX@Y bGb}e1ce H,ln~ #BBP`pb~Y 0SFY䱠I'W T4#endstream endobj 361 0 obj << /Filter /FlateDecode /Length 290 >> stream xڵӱN `H&GJkNM3NIM{4"Rȍ%) ~ٜoK<+>Lcuz^aہxĦqkAtwb{%>X> stream x}ѱJ@?lv_@p] !p` A+ RK E;!hM7HqfwO`vv23)Vf0WI%X8=Uk3UqaUASSbmn*Sުvm| 82"7@б, }8$tHIR2>JJ =MT;4[6R׳ā~D}~k.:6ʃHϐDJwk81ۇ=Isz6WBJI7l:ahJ7Cަ85,φkVq< /XYd|vRJJ}Iendstream endobj 363 0 obj << /Filter /FlateDecode /Length 176 >> stream xڳ431W0P0b 3 CCB. rAɹ\N\ \@Q.}O_T.}g E!P E?!u?3bSWbWbWa1gXu0V6V eG,eƒ'c1%r C> stream xڕJ@'LsL 'BB> stream xݑ=N@FJisX[N"GTPR; 9BJGZ0; Jifw<~EqUQAg9T )fT3j4wTN\IM}MoOhf7s,hSv`ځ_ hv= {H 񞡱B [r%kT3. 0=;  ڿv>;bC _\Af #c,'4/+;hq1h?7p%endstream endobj 366 0 obj << /Filter /FlateDecode /Length 243 >> stream xڵN0/`?BdS` Heꀘh XI-#d`stgۿ~Iy)x 5_XQ&oG\7vWEF<z{O5 Tb!ȣO!2J`@;PP<;Gg3E9c̈*l09t / inm';)),bߘ^Jq݂zlgFendstream endobj 367 0 obj << /Filter /FlateDecode /Length 210 >> stream xu1j0g<7 41'z(S$ MHXGQ|JW\(T 7uN3uki1}.Gq%Cf&u#U])Yϧz\R׹fi WOp_PI! I@*#f%#~,K{ǏT#,ΰq`(nYsLޖF^V2endstream endobj 368 0 obj << /Filter /FlateDecode /Length 125 >> stream x323P0P0b#S3sCB.#C I$r9yr+r{E=}JJS. @-\. ? :  .WO@.P endstream endobj 369 0 obj << /Filter /FlateDecode /Length 161 >> stream x33T0P5U52P02T03WH1*22 (Xs<L=\ %E\N \. ц \. 6 ! Ր#0$z $!03`a |\=[3endstream endobj 370 0 obj << /Filter /FlateDecode /Length 203 >> stream x=@H\@ȜM B0X({+ba8垫|>2Pԏ~?Ѥ$|@jRRod5Ԍ;*gX@l$u8lSyEȞn!X#xiTCƩFHjODO'0vBJ#n $"&ݏendstream endobj 371 0 obj << /Filter /FlateDecode /Length 159 >> stream x3534W0P0bSCCB. HrW01r{*r;8+r(D*ry(0a@R` `$@z ɀ a/ m?C&\=?qjSendstream endobj 372 0 obj << /Filter /FlateDecode /Length 209 >> stream xڝ= @GR2MtbSZYZZ(ډr2EH|((v̛ݝGa_endstream endobj 373 0 obj << /Filter /FlateDecode /Length 144 >> stream x36׳4R0P0a3CB.c HrW06r{*r;8+r(D*ry(0`?l(g?6g u@lC{ pPendstream endobj 374 0 obj << /Filter /FlateDecode /Length 213 >> stream xMͱN@б\DTd""R.HE) h!kfg:[\ꗺXS)Ks"Z;׌oY2=7Ro0ͬ&a8YZi4 %:1X[z83L̺E[y!8}?+O2dWtm8 \\ղuYendstream endobj 375 0 obj << /Filter /FlateDecode /Length 160 >> stream x36׳4R0P0R5T06V03TH1*26PA3#Lr.'~PKW4K)YKE!P Ea9$luPفX$N#Ccagc{  00?r Jmendstream endobj 376 0 obj << /Filter /FlateDecode /Length 202 >> stream x]= @Y6sݬ+0Z *ZGQr!n5|ś7ȈBR[^0$)?G19]/bLւ :c:k{-Ŭ`m88u t&p2 lB̘Ϙ> stream x323P0PP5T02P04PH1*24(YBs< =\ %E\N @QhX.O9   fv6> $'W  'endstream endobj 378 0 obj << /Filter /FlateDecode /Length 95 >> stream x323P0PaCKCCB. \.'O.p KLz*r;8+r(D*ry(177? 'W endstream endobj 379 0 obj << /Filter /FlateDecode /Length 207 >> stream xڽ P FҡмVn?`A'qRGE7f}>BŚނ*3$|9VuQۀ}+5͞1%kTڤ|18Ux*%V738 \A&rOP deyܿ>X ?c\%#'q(IfNĴ)endstream endobj 380 0 obj << /Filter /FlateDecode /Length 131 >> stream x337U0PbC33CB.c# I$r9yr+q{E=}JJS ]  b<] >00013 A9 CaՓ+ t^@endstream endobj 381 0 obj << /Filter /FlateDecode /Length 259 >> stream x]J@Of!"." E0pA.Z v |˝gH0??pNNmnҮwYUϹ勧7wk"nssa q[{_AꭅBaD4%;>#p{%*édlW]HO˷df 3ÂױtK҇FoMfl=o,"E"pLΉ~WhFF*4& !3DWZnvjendstream endobj 382 0 obj << /Filter /FlateDecode /Length 257 >> stream xmJ0'y h[ 'i((ysƙ$;dfjj5u=5mMrPٿf~jg6wW`G*`Z@y`5@N08F  xP f͡HmVJ[\8 )qYTN KJ8L3#ęgDUk-2gB8&%1Dw>vqendstream endobj 383 0 obj << /Filter /FlateDecode /Length 130 >> stream x373T0P0b3K3 CB.31s<L=\ %E\N \. ц \. ? Ph707000c~4ȫ_4,q.WO@.endstream endobj 384 0 obj << /Filter /FlateDecode /Length 171 >> stream x1 @ [~/1FJL!he!Vjuh%GL7pWjRVsȣ BRJœϲ?SVp\ؚdq$fyQ3ƴ_@ x6QjykaD D~:Vht%7Tmendstream endobj 385 0 obj << /Filter /FlateDecode /Length 259 >> stream x]ѱJ@ Lᾁ'p<8O0)V"*+ϑ:Ygw{tx-(9bA1=3?k*hmuAoh]MN-V+rn`f \uǦxY> `=jx烷li'^ b8vUx谈endstream endobj 386 0 obj << /Filter /FlateDecode /Length 252 >> stream xڥҽj0p [hd`e3$)C 2@!!G3U?& w0 ,N=j7>FTҿUx4F=E_%\ᵀ=/ɸhendstream endobj 387 0 obj << /Filter /FlateDecode /Length 229 >> stream xuϱJAba yh+RPK E;1 tƽpS|?;?xžjs3TC=-r+SrgkkrKyrM͒a{ծlB-`a:`u)xuwGW2&e˯ɦnh huaǨk} [ bԪob"EzONoɌlaendstream endobj 388 0 obj << /Filter /FlateDecode /Length 213 >> stream xѱ 0; 4X-P vtr'uTt7)7&/“ h4"rMӘzdendstream endobj 389 0 obj << /Filter /FlateDecode /Length 290 >> stream xѽJ@YRyM̝p` A+ P,& Aȸϐ%GǔRFtRN2ڹ{{\$\1/)n4 ܵ0C v-0ypiVp-PL"(JvWU+ov-cDgU7({_`7'4 lÅmsH/@םb'۸^UbUVlA1J1vހg9^[9^endstream endobj 390 0 obj << /Filter /FlateDecode /Length 267 >> stream xڝJ1'lq0޼fpVb]hy}-86L /;q5%QwFO-kHfr;r +ZoyaC 2i寙5z>%k<&r,`vd+q3ߒ1^+ \oxE<@G*q/|Aoٸ=,8U(`ش fA-pڟڤPj"{mI倷YRendstream endobj 391 0 obj << /Filter /FlateDecode /Length 351 >> stream xڭJ0ǧȥº=z =umr!4LRuDg^W4;(M}h-ԣKCQ\jժԥ*NѮ̼<ޫbu~lX)U6_GzahB t ]2G6Da)hrcfEA1-?pλճ I}҈6ĥPgOn ܘ'+tc036u! 蒡AM"9%} |H=X9ZHv]ϽmE=LQVgq)ϜRT7D]n cƒ|M'b<%NZu>vendstream endobj 392 0 obj << /Filter /FlateDecode /Length 219 >> stream x37ѳT0P0bsCCCB.33JrW03 s{*r;8+r(D*ry(00`P"0C=~d3@@C P?P 8xq83qe0w`0H+p32> f qՓ+ Pendstream endobj 393 0 obj << /Filter /FlateDecode /Length 142 >> stream x3631R0P0bcCKSCB.#1s<L=\ %E\N \. ц \.  30oAr 5 T @;af f!`` ȘՓ+ > stream x=J@ )2'p2Dl +BB\K E;qy^a2E33EdȼҥOumYꭥA +]Ȝc2͹~z|#8іF_[]PI%ae,*=c<<6F< ӉY+ _ ^Lubފq,?vMectJAqO8:G}- ȘKH~cD='0t[g7׏iCendstream endobj 395 0 obj << /Filter /FlateDecode /Length 207 >> stream xѡ0[*#pO@@ %0&H@! $h%#L"uDKzz٢"\1CtAݓSi֫u{СuB U|0ۀؖB%/Q@Px_Qv؁ʲ#rO ^7\gpx'A~^ɼP/nC|Uendstream endobj 396 0 obj << /Filter /FlateDecode /Length 249 >> stream xڭN@ }K!~5*1#ܣQ3T9l Iɾ5TUEš^+:pP3/F *-=UT>cKxii$@v#W@!'=r48 E\)GC B1:6b:wZK??"Xi=1wfbpY4?]e[t~x#endstream endobj 397 0 obj << /Filter /FlateDecode /Length 288 >> stream xѱN0Ы2DHmNJȀS22`%4*1Cg[!uBbbt:Ftr6IF9s|bli%cLl^_0\tSv PiYY0٣-$Fi nQC$lrڢWF$\Ea}!~"bǠ?qQu{3}>t^ uCaΟ jeG)AmJIeŐ[W.翢j؄7,?neendstream endobj 398 0 obj << /Filter /FlateDecode /Length 185 >> stream x? P ,dМVt* ίGQzN:xȗ@ iDrj* CDJbCbqNjILjn߮#r)o̙-S/XSeFԕ+^+k۪d%A3vX}X~ö"7iӊ^Ds.endstream endobj 399 0 obj << /Filter /FlateDecode /Length 281 >> stream xu1N0G\o$"-D $(PR[mr⛐#Lvq v '33n"O'5sj<=x/5j֝){S^˵)x|1jSn衦t8z[d yDbDΰt=ZbM΢yqPje^5X*>YY:#BIj!MlG-ƨH]$?r>Pc6A٠~I"vfD7(0l@/]3wׄendstream endobj 400 0 obj << /Filter /FlateDecode /Length 191 >> stream x3531T0P0R5T01UPH1*21 (XXBds<L=\ %E\N \. @b<] @>dF"ّH~$RLڃz0D2I@D1aL``n@'03H~`c1(l@A(8\=~@endstream endobj 401 0 obj << /Filter /FlateDecode /Length 203 >> stream xҿAr $7/eQII\!R Q,'s0eQ"ܟ3?(%V U Вn(6Y4n+|א<>ȭh\ E&tj8endstream endobj 402 0 obj << /Filter /FlateDecode /Length 152 >> stream x333Q0P04U05P05R040RH1*26 Crɹ\N\ f\@q.}O_T.}gC.}hCX.Oy 0?lB Vh Vl> stream xڽn@ 2D@ހp\hT$R3 bF"1Ti-rUO9$fo=> stream xڽ=j@W0LsDZT)+' R(:J&xݑ:y;v&DZgЦ3p)ڱ ,rHYH|I'$%nlkcLCsb@D$*cz$Xp3C0_^")@lR{Ö;"r{H=ϩt.:/d[%K*e?#W~'7 endstream endobj 405 0 obj << /Filter /FlateDecode /Length 97 >> stream x31ѳ4R0P0T02W0P06QH1*26 (C$s<͸=̹=}JJS ]  b<]'W 44endstream endobj 406 0 obj << /Filter /FlateDecode /Length 96 >> stream x3631R0P0F :Ő  Yɹ\N\@U()*Mw pV0wQ6T0tQg?P`Փ+ "gendstream endobj 407 0 obj << /Filter /FlateDecode /Length 147 >> stream x333Q0P04 & )\\&  IrW01 s{*r;8+r(D*ry(000`f0&=A$?"C $D(9$?X&ie\endstream endobj 408 0 obj << /Filter /FlateDecode /Length 312 >> stream xһJ@&o\"uSne!Vj)(X9yo)SgΉ|%s~LMjf;7Ejv"7zS> 9ҋJ''f:N&Ҝf&=Ҩ#&P5AOtA`mU~ԳjʖJ.u˗o5Jj Z'@Z}A|*OMH I+kO%3?q2'X74B\G=CN{5""՜Rpf鷔'zJV_~=@}MTz?endstream endobj 409 0 obj << /Filter /FlateDecode /Length 380 >> stream xڍN0`K!~HڠNJȀbFM-Gw.*$D駞ϾᄏxqG'zjlW.ܺ'OvƭభKhՙmu[nt"䁔"!5Q&|dю9?51p'Yfr0#0@JS'K (b΀L ɤ 5;LڣY>6M"v(N}N~U UT[TfSUĕAT H#dQ){6R2"@X:!rTA\S^Ej,p dtS'BZI,=Yendstream endobj 410 0 obj << /Filter /FlateDecode /Length 118 >> stream x333T0P0b#K CB.c I$r9yr+p{E=}JJS ]ry(hC FC ybՓ+ endstream endobj 411 0 obj << /Filter /FlateDecode /Length 374 >> stream xڍ1K@ 7_CIP AQs#~lI !ܻ{w5 Ǐ?.qEs84i"bS5D[O|p#9/՜ٕx}y{\<\XDw<[ v1c(ٲA2-#kgSr̪CwYX@7skϻ.Ёy=De=AW=/2Nе Pǯ{Ro0R J7=7рKgW/1>11x;M4$.ds.(M.[Amdc|b];A7Y@|[33O/n<.;=oZ)endstream endobj 412 0 obj << /Filter /FlateDecode /Length 287 >> stream xڕѽN0> stream xڵJ@%4y˼nn p` A+ J--PB\_SE;%_tB=ܵlkouLn}{ ?T\n0`Bh§"( v3,rV (R0(Z1̾?^3A RW^SML j3)0}1F3f liX6e*yX i}lM󣫖 S-zYendstream endobj 414 0 obj << /Type /ObjStm /Length 1404 /Filter /FlateDecode /N 84 /First 734 >> stream xXn6+x^"9!@Ѣiдׅu}P%&5F=$˦3dڈF6!紵ƅOڲak;1!ш6 ȃWE<ޚ0;N_Xk1ͅ{Mid@%!Xt36222l+A;;$$d  BDQ 0t XՊjW0q^en5bAGh:P\^T[S P@02GYc:]XAhv߉FVƅϳ4!wAoy[x^dV*$L b1 2sD$"sQD AfQ`EF9F9uA9%"H QjN#NR#^O#Zx@yZRPeO>`{֜h<.7w{3g?ޛaj~^%wO|,~Dpp;fב^ׇ.N}Ă! Ǐm { Z"><vPqnJG q(|O|o(#]KqC/Lo)&%PqFGaBavʙ>P[f{S~:W/SϔJz{c3L?H# /H6Hm%JjIhq}5嫁I,˸֩-e3F,Set`tL=޷DQey¬U. YfCd/ ]Ҫ].ijLE@T .PYCZC퐦vH_i+^vS;Ӣ̅EÌ:hKFYKb]ª]B߫K9؅o1PYZL-F^l9,lqxf׷AVWOMCF~r>ts]:7s6e2 ބ9m\^L[oA[t-:׮a -:e]w|t;<rs||ma'ˡ'+p.g-E[d=t)"qO_Hc|^Fl2 7X)إDХ8x7jtEReI)όtaGC}U =J>tK8/oZѣ:J$S cM2jB_̻jc?WA F?Hg&tfhL' `0]endstream endobj 499 0 obj << /Filter /FlateDecode /Length 76 >> stream xQQAHiaƏ `" ACs~F$ZSԄ {+!fg^tn>O> endstream endobj 500 0 obj << /Filter /FlateDecode /Length 73 >> stream x 0 Ѕ 39YXhvG$D>}MJ0iʂMU#I/]ڹţ>endstream endobj 501 0 obj << /Filter /FlateDecode /Length 121 >> stream xMQA"Ckckp~mMsà ) q6CZp2A-F+iӝd> stream xAA ¢ AY pG%,[Y&O#"d;f:nmq}C*9endstream endobj 503 0 obj << /Filter /FlateDecode /Length 71 >> stream xAA Ѕjj1, @C`(|]{a#ϝ8*Hob>I]Qʂ 5endstream endobj 504 0 obj << /Filter /FlateDecode /Length 66 >> stream xQ PPG[Fc;6B@@AC qqgj36f-M4m8x3endstream endobj 505 0 obj << /Filter /FlateDecode /Length 113 >> stream xQ ACQAM0 ^)M$j/ ;^`rްv򈧨R.k:՝nהor\q> stream xA A хK3X4M(ܻ"4pEnFLtfh:9Jendstream endobj 507 0 obj << /Filter /FlateDecode /Length 74 >> stream x A GЃY1\{ ,9>IZlyVi'+:j+N/z> stream x- E1Be 27=az& h(|zݓެ}ķD9&LZhs1Nn4=?>u#>$d[endstream endobj 509 0 obj << /Filter /FlateDecode /Length 182 >> stream xO 0 ?@7 `CW@p 9@ U-APHPhmNA90 Cng{wiZHIvȮxYfѝ;ǫ~hN;εDMtQ7];R:*-"Cꈌ]73> stream x-N @>34ZvOG>uz?zK60 ,i{k7Q!OPGD-tdXR"Oc|kfUa]Z{x_83%LRNKLP{WS/Exendstream endobj 511 0 obj << /Filter /FlateDecode /Length 98 >> stream x- QBE 29O" `A չ຦Tzto-GeM`Ѧ3x7BĸV24d'cNm5ܸHbendstream endobj 512 0 obj << /Type /XRef /Length 778 /Filter /FlateDecode /DecodeParms << /Columns 5 /Predictor 12 >> /W [ 1 3 1 ] /Info 85 0 R /Root 84 0 R /Size 513 /ID [<3052374b08872bef8372434a1d5b663e>] >> stream xoAgR4BZ*485B7XDHzIbkjm{uQ!UK*j<Ә_A'of?wf~ƤO&NOu33sgmyԍ*hQH7$4k s

f+@i߸hPɣ 0A&dPit>|p6 VfzѺL吗C|kJÉXl@-ؚII)P#U X]|Pv:{*.--̌2l2i.rhv+/F ۣS1zWɆfKv xi  n cpy)~TavAڄ+$-mW7)+ĵH k<;g2 )];H>x1c}T-L*`YA6~$ WiUZx!H^+mp $71+_sBnLT4~ ]S4$͛v٥1}^$NZȂ*b0}\n-i}<pKD̔Mʆ\}(A>=/fE%jFDW᠝MvD:cr0m-ƜX皾79'rbѶ>^-3R8SG_+y**ʼn.jN+*~!'>y2.P$N;{2\ip<)ta:/Le Vu:~w""1`PK%%λ/@KxidБ0'抰"qkt̙HV~?SL"0d to7!Hb}%.Q~0ڹ3%G_ ht%*kgɽ7oJ~6r(F4cB?4˴ߠLE*9ZEӡ:'-ǧkN@QYUG L3COicQ+ rjXt@BɇW:C:Zj75tGT5Rd*\?kppY zV 9ԮpyH8 y ^[L~#Kc+SY1NԙknXZO&C;_XCUN f͏:;^% 9qFh7uqȐڱ#ƅGe7h >Zd^CRm$0%pN+Zw6([C^Nݰk!?Q%S }mH7xfגzT7cX>I .1I;IHwf!;1O t'G'jB,r Q`w{>;_hbmkbழx9jd5|kB9N5C4siRUu*K{;|FUDO&N& غޒ>;0RD.Xo$wݞ^.u`el;k0-gfA ،01| 4;"2>ߍ3=㶲ځ.&d]i\Js5\Q[Rȱڟ[sgr:2Wd']a9J}6 @ˣ0mƊIrHzܤh@{9Sz> T%?@Ӕ3& +a !kx1= /N%(]ۻWib'oW ~Kתdž3vcU& (E|$R`M([r&G* Hػl 7CHBbעY Z-v2QvwrQALKSݯ+ہuW' (CRAOw.纈 ;.q4+F^ Z԰3]Q+$e܀"fpbhV]VNr<Ii, bH?KyPp7+}.R@ȥpгXH'G RY8?c=!ӄ}v`a3AR1Z, 7<mqD84.$߼95sHKFIh1ŸoaN"*Ǻg#EjG bL,, j:NEv )Ȳ|i+O25oM"N:ԓ@xjD;Iߛ[C+`||1J9)|0]j1`T0b":gLym+.h-la(^䷬;}џvpvi#~bZ`2 4PLIVXߖ}{V?.zDB^3 om= ↯P ^m]Lkb"7$=P<;GT(ԼM ӅQR18^#w1|U!Qݴ0'br+͔rLtИҽ:c/OflD Ah7S°fd@t Uj *IPO꬝I{cSoB P)!`il|݄ڀ﷬nB;`teY,-Gz~Л҅E4I`_b3zW%7"Uj{-E[vhSDd̵]yK%I/6z3DۿC%`y6zX[{<(f\jPUO "Ӡf{g8vː#n8A:9Xݚ.M___a $rɞ}" q[mVT ost2=<U@:nB\#¢]c ckV.B4F&CЇ∉!x𸠐H1<Ƨ70_.XEpztX~)kgYg4עӝ'gH @6jȭ28<ݨ *DǗt ]\6\fc0?pB!"Lx? o@SRB/:JDk.f}o?zkϞ(d)sKEs/GJ}+}nkp U>.-rԠ\2s}dc Jy"l̚^#X$GƑwrz~Z<)^j.!nT&G~r_s֔нzyA< |@=u]<p=';yz3 O*Hk+cN;VEdN )@؛on }i.˝W Sl Tva,O[2pR%9?e) }SR,QM԰׮>4d]:33y ^&WqS;!"C`"y=xqXI{5$n+;) yx7Ժ3l)r Qbuᄙ2dkn DM_>k8ۢWjffsPb BLm|<0"Ý 4uWˑ0de9*wciUX< io_PʸG2fl}AEk*؄]zA}"?]r~ ^`s=D'p}r,-yir:uj؞/x e _9^:S ~Zќ"TS$g͆3[KDg~j79tLWJ+]W>4.ws{DMM$mȜC(NcrxHWش5YҘAyFk]O#J`\5F]G4{:Uu| \-zNV{ό~ h'lGp(7GOcg1k)B"I{(wi>%||=H=kXObltRgLpxH,36U#H5ɥ6=ƅϱU9]0֫,XfP,4&NdMX', C25u0ئ.=BïOpSG0ŻQ TϹ C8oqQ b_ cwЇ lrE\aC^vK>S(3R;W_;N:eH4gpf܈_d.u@nY%l6 `#dv\>UpvZ^aj$͐MӓmGeG̿652j'F_#0M 7dj 9Gl8kG;+[~ otޤ¬x%2x;r1F@Su6P&_rZ_|c+wI r5 'xqwƧYũg$CA(7 lq!專Lj~7.Q#uWYȩzJ5ZO;Sl8]hGV'B9DYZo2Y~q9j=\ǰ3,VP,ᤚj~:d)3kG_UfjۗYQ',]^&}bs.WѬ01w|SD *EO@jn?p*/u[t rmEtHaDz5/myċ33卆xE3ZΠɨn6˛Cjv}(}".-0N Fb@A~"d"Թ饋Y2٪Ε99߇fZϐ9{i A8ˬ#b ,W  cu*ceBBP17KjY5BDƈ Bcfƃ5e4C#[iEts[PkgEB&&ihj2:E#0VCA|/l.3NPlFlEoR(UyϵA^7b\cؙ-Wlq=k0gAab>e6k^(:{PADg'w90B$H%$3>WXΪTp1.;fC| ^T X]Ͷm+;iEnKDbC`rA: {lh(̚nAH%=^-_ A2o}";0 ۺ)a^ٲ,%]YK,;r 4\}99z<=yTˆ[XD=%Jtzy)D F'?$Q 4޷~^v#c+y>/UQS\ ,zzn 8bc!&@jRKr' XCR͍,hsijuO<7[Bîm"*4\TXVHK4?oknx!8KSm(+ 2ņ1➽<G hܴNk{IQAx-uҽIVFh{!UJvKj|# lWk_d,Yف] Q-!@>efos@HWL϶r3ՈwUD3)܂w˞HC;H-/?{Ļ /IH.p!^[vzKT^FI}WoڮQOjc\Mm{Ҁ&0#iɴ؜ÈaݤgtA{tCqQۡ"/{3̯IjiJ= W \q%  9lZUkHͰK,35>r,̈́3nGբkڒl\MB csC!Y$y TܛQN$\EpE]`9?83QCASzf<7z)8KHX hqjedr=L.7{t3~:zZmU֒-ӯm{}kxw>TIxHhΤvqSjt9Kp{N.+\5~l#6vH}\@OI*":N~I/])漋9?BEE}86~q;>b;qtZ]EeOkGY<3j7m4\'1Բ3?0a!#F&1yu\Tg#iB cy@ SI0ah[RxόAr#d:oϤdy jIozO'qk-PfCI@Ҫ)VnAzyP6f|ԴwS,W59O'L76W 0B#$?B&gL՛@LR5[u;} d(yy~tV|vtڦ|C]!RO: }j$/-;eJIP<ӞyD-'x>{6KmAV. =iOoIa uQg^AiݍF`ToQ_z)PXP6MCMVu?pKޅ[xF.Q!ͦB@›3z1Y!>Rl-_[b݊OkCh!SI}ldƛ-.!Db`x}E?05Ia uń}q泱%WeWX]@ xşz?ҌOjlIZ̹̔i1Ȃy~W+`. eXqa,wVB{*l VFZE]-xχ{қe4 < ĊVc#!;~h\14H*- 'ZZ9L0X#02;Q'daYp5SKdFZ,=w?@sA!ށZӅY!@ '^I@b;kZlUK|ٚ'4Ҩ](SŌ"㡟ܨ E!YB|j)jl}+zj?#x;Nw>BmVшYmo|T^!rM^4>s&g >2Y %icΔ:~$\DHHXXޢO[ t^B*"+pRJh,Y Nޟ\qJmhJP6Ff218G˜JC&=ؿ-S~bŵB򗓈+UC8$]/QHý yIeDvK*یb,GM^RN+㾲($rG '1=BL1M'Y< mIgѩ\ba ϰJ;Mb>fPٗ S $dRKJ>-Vv; =L3;ۖ @r_=GCj]|n?cAҁ_RP= /.˵^Usں;b<v:Yox:}R 2u:IApav@ϋbGYt`kSvd54?q}  V>QkU,6^($M䭪-U>ݴB d3=VlV& hA0BfW;\Jvqo(= ,Nv-6ʥNi/5?UE#:!ww\7SvhXf,7zLTaʕX蔮+OJeEUzq$zX\p$}n;ԖÖ S~c/x9SsOP8Ѹ)kD%\CNneKl4OL8ʗ*Uq*Ql^5 ?"3+?ƿ8&YV[1R^b  V{DenӠ6HcfJ- `wd-,!85 n@/upU ɫgعI͂.6F?rF1p)O@B +~¼EXc3,T6t 99mV[;ɀ)*M5|ˀףۘ!<%k%lKGjU1X2)Ym^DJ{}*@Ӻ>Y*)_& 1nGBJ:O{0cS VQ|'3~)<5lcA+ʐ#GR?7Wb &:]McbNqR5r:vVrL`I~Ԋ>K\Qvt]Bz-Ͽ>VQ7P6$QlR{q9A4l}@C w|f͒(9BXװ|U &XsB2S= '-ܺ\))p31$ldyx,*4cBk /-3zeflk,]}+LxaA7A!\taS"n\kņ I6)!霘=ih=Se KӴ|yP!N^|OSeVlL 4mÑK2Xv!:ρ' 'N\d9rq0]IO0nx)ӯ_8I13kZ _@Ұ!~Ĝ_,[mήoceO_gP]-=7puH~UE{4'o-cRZzC| ֊m*QimY0!ᬄ;'_Ce%C҂̌gR%ZL=C Y \r6XxsRv|:N 9MBLvns3Jy?IH)PGȫfTJ<뇿h1ԹET‰ݛ'^]׆hU]Z7PާxT| c!MDǾ?1nVA/e%(j9;rOI#F+_.I0.TȏPA+gӧX#*n: YO[qtpr&}C-=DBt z\덟& H7I?[lN}HvPiWzҨt*1?Ɛ8Qt$/`7'I_ J@k¨ = 6h%֤a °Ganx^>4݁˻aIn_hR%|FL̒Y煣xXULdoA^@˙ a"nJN/띊.9u^lrlu}Qhc_zNdV -eQt~^őuΩA^qZGOD{qj:MqS5m|QPP0cGĤ(-2mr1aY4ņ K :t$fEҾA1<+2/җ " 8*M 8&,bRj*"C5q:, ף~q#%W$dI$kQPnC)$lXNd]T{#qE`E3[}-C#{/mA5FY$ =wZ :V+W)FoCwHC+~2CZ~P]XtYF5NjA:Syܕ3!5a@_^56 Q{^)kRw@n{PBÚ<+؝ylL31=1K!exvueG报s|u\bvXܟa߂ m~}@:Tbv1V U{O/֪.Cz;k,v&K|J1yY}~eIoc  _6s]-pX,D^In7PZm٨UcB}w*s'YTej ɲF$NTra\HlxK74 Oalm0346dGV .Ot퍨 K{^=!_o%vVnT"7A]? *L?bf:Io'h , ]<2*]<9߹0^eFb\a&{wEǷwFd&| S >SU {Lj % F4JtT:J}{*/D?Ï+TAyetcX!C. [|un7 ҟfc n;-Ɉ)HqgolJvQuS㘩 R?4{oK!XѬn~MxCi:(»ARok%/xeҍC1HKȸ|.*JlFt˿_}m7ƴpձum]y"-b4Kz,EevexN i9vںB!/ qxȥʞtWےf )>,w%z6Ukka(Je$N}`D+#g}84y#㲘oP.rУ9ƸX#C.yL6jؖ}8gmZXY^t/,Gl)5C% =r'܉hƜ R98Ϟln,Ye::h•I()3J=IxR޹IYy%Xkc]#Wۄ(N%}+{pɨ`R*_s]΃FW0hnJ`Dž :w> ǷL{V+B!L1GY|@ lf;1p"TA1ޝ;g{HuȪ+:fTR2Yk貐vkxjM*qVo8uW6\b=KߣA>3"@ӿYCnq{ٷ+-i,{Uk -I("h62ft9[\gt=[b!ź˫|L ~^vN5ꝏHfkxvMV#̒>!NAPjHW693ҐkAJ8RV5j7Syu+ۜ!6%FkStx'?B/dWkr}[C_˂?@ ;tWd<נuJ %\/_Ɗ@Cc(/]@Z1dgÒ^`K'H;5>aЮ{nT7l-v9!okte޵?% A;Bk'94WUɚ7Ѕ ީTꕳ=PnHڬb>*b: w2(  &o<;1vzƫ tҩ7O}v4h9DaJoal'fŲW<%Vrgm|nxbu5\I*OT)0Wj"P$`*T3 s=?-ޱ/w^.Dp%BN;90J~mW.T#䎅;3\t54;E{: \eˋq)V -d h'zlOd%c.q@MQCO و.u mji=P7b0DQA%/@5òOffbz/E|Y`O}cg\n뉟d͔^8PA'9>C .IXDȝ#s@F'f%ݬǮb#y,rJlR-<Ƨ7 qw1$ ]cwȟ&jB7s=3VK|iuq}{M/XZLBwqpy9 KBt_KSǼu`8)wZY`jN}\{gNL_\t\+8Ri7愗i<JK}2iTLMܡJ OYƎ!N1BidP;/}[sCB&6RT$^N`㴖Go%ю#Ekm0ZW A&3OL"!娃:#1Jf/k{*}]X$\|H_Pg3BR ܍n!B$+Odž,չL*?*l|6B@ݏI%HnIC4E^IO&rM3s%΀lM{Bnz}Ar7EelQ&X7A hiMݞs3*۩X5o 0IE p| 98o02EΠmDKpE;()2bEZW0*#%R9ϡ*H0s)ʕ BRD_4K" 2izҎ뛪\F&/ʯL4u%K$Վp&n8`\xA^c#V#c/w3L^&Ab ##cYTћh6AC~`|70_bT$á\#KxٛDqBIzK{87PZEs؀Zp͛MAž˾뉇Wh#LIk9Φ@ 5N=ilVr(i *`PRyraGؿ  l]Jov {6*QuVXR6X8 Ͽ#[83p^ѱi_h.}]^E|2fH2!O̮fWhΟu@m%z mj"(T' 7MTCGɰ>&tMK *Fkz|ZEb>Ar*٢ EWkaCnXl\`$)/98-~G3&%TpWAhF,CWBd8R(#h{"J7w0 rHA!JZDkW%B w>#Y !- /$"r?EXZ*\d_En$Dj*,rcS최g> a _4<bq!kȝ<.0_ vzg\83q<26 &[rWO?;YAAt"_sZB , Œl7qUx?e+{L+X etqؕSL+ 1ۢ hڋ., ,%s:Lwڎ 4q7o݅s8Sg~N 1NYP[ >zJ%v6%ֳ0dY?Q {/)M"s#qx,CFGW>i*seBz =e2bB90/Mr]\mRR]/0K8H{eG:i@Fc0Ζn U&/הy "ȔLjh8KJý.8='ddd@`sI/wdmE%XN x%xRDeo.M wqb.^gm+0VT.J I=LP(EQ'~8Z0QքV:\u/8@`6"1GF3Aձs'$@2. hru"̃܎an*}|T |"e3R,gA%0x`C:lʏ~h)(TUF#6Ұi ,0 Eo=([oru$Z7蒝](ʛϾeJu.Rװչ.,aғɖ&JT _=C^0t@댵"(7/iLz~c%JtL6M\Gmj / RdG{ІL(egl"BK$v7;^ZCd%vյ3LaGH`gf Fnu3locϵuR*g^n:|A%g9YZʒgxe*aȨno}Y9Lʠ n\R%d>_d: "< 6gg1L)<׳WGK9H8+ʼ0KVbŸ넂-*A)p" CpjHԴ̇Y8T)}J95Ҧ-WXn'^ruU${{/} 8/p)9dįOOIʽVVڡ9k\]ƒ,=px 4ʟ}lvW l\odUeri ,(#" 0 zѝo𘔴{SAx6C&W*`+WӿL\,1VV7)V~X[ײ}k9!N#bZl[ck ƾc÷z,H3R(&@GR=Gt %A#+’&; NP'Wyz-%0_[Gf3aw77 V4; $]J/-[gzO?iam%:ns_i|;?k0)Z8nW>‡sFl/]юY]C`y}sVSA{ZydI UUdY|GMFj -/Df~Ħ(VFYS~Z˜uް'`.ݟcC*|ָHMb]""@qKi E?j{g%< ` ڛ;LR.^,P>k=Ī^ )lx(5&ṁZbmq| GP oX\H gKs&k ^<]lHjLrs^ ۹4e~?e5D]CFu\/W ??9bL@cO5Ĭs<.@ZqPc֚ߧ=oڬJybDM+7K5V1' ,E-*{$JG V(X̹hLK"m~cz,*bOv,m l[g\fBѱ լ. 9b?w2n+M ED y-d Տmؤj^o#3y 1QZr/;Yޜ3DZIbPtŪIƟdPL *c6Ftx>ggYn. L.S^eOw?š!5y)7B gU]R5?&/߁9,ɔ `6jlA)Sʀz#gwtŹYazQ[ae;Q)psNFxWއweF0< ԰aYrMSӱw zX0qx8Uͅ4a8\:@鋌GWLYf`J- ƫz/;ǻzϫ3'\ Op +,ZcW:wV'ME2֎}fŀ9UfY霉,. )P) R@{d}" ㏷ #hE9_+PV`4eF+pԸ0~=my̛W$0hˑ%w?;/.NS/0\q|DC`TP h[u=b`54x_Ȫe\գרOk~IJD͹F}(v_EF㪝X _S5p.rAnRĥ@~wgL6@e.t3Opb$Q,,KjW)eIC|my;#!' fjp*c,R Y3"K^{پҐ`x1ߍL z^GY XbZZATl7 nVR' uwnB@O*772¯>5,F: 5dI09'L,-E-q al!bۓuA|cF}"=B!g>oh\m {ְ+oOƬe|, ;쒀YFm;7U%t>3rOQfqvUwD?⼞įĭ y0Azbxս詥aPe /lBbNqﱧg>r>+}ǒ7 \BGnkU¿eס[`}hsQ67 #9V`X{A$*{ęf<@T }ڃ1!$߃(O],h. ?$/`@qqD;}k/9WH#ٱ^Oޕ>*7<ME]ҳҮ #Ր?g 0kPf:4t^>ұʣkJ`Ko[&LVwm ,)Bz//p\3ze6zleScc:>x#X2 Ch)2MHVKNEp!lH";e; Yӈ"N8ï1=עU߸egƅа,M5$vGw&XpfۏǴO `a,{o`[5J%˓j⌜VZk#d<&#4:Ew` =A7DͮLNM.`V{55K/ʦJw Ήtfk,R;!ӽ1WzZᢅfH1u(X/Vp}#s} r&G$`ZZz3!(dh9|4fp{ݚ x%A`Ydgbce@޻_ol߼*EF7GPK JP~0&=S y F~}yVGF~_%u*,zAE ׭%_UkF$eE7a~'qҲL:\,~_*sH_Jtuc?1@G.Bz(YEc=6p]p oΔS yBלt*Bv)GlkWF"]G'=BHk%>6frxh_mLr<<!s<\4-- TH8 B;*&i1My@ZZ=ײY{2 >N\̚>̹B8#X c>FrOǸ-3ʉ ̧a,J zz 羬.NxfOzxIžzTzemhA"W26.@KvD[U"h,ʎ{ְj͢^MaY43sX`.86-ٞA*F"ųvq3Fɂvaəݍz^ iDVfZBJrJ[/4cXtxxW@V>LH |u$:t$YMu9^ڻ]D ´a}]TG*o!cD4G:fA7,B.. T|srBa?{iX*3Jjn"&,^#b5*%;j$9>:ᑲj7!JDXT|0zxN!șPZnIAfj̃딷YvFep2 h[Ϸ 4Z@vڇ?$4b}93'i+ oWHߑAԈc7'ч?ST5CO')!ޣ9by᫦tM ͪD!\@uKt;h1{E 3Bμ8nn*>+%;dQ^B!V6BS  ˄P`K=ή c!B:Y> ` >bi\"I3!:1Wai T*0u^bQA E gkñ{ 4Kz** K|k`et @9< `, F8ګ_ЏC#j&p6Brki [fi;+է%&؁m<=q;+] :ig0кNCzXL#5GјG/a7kceQQM6$qi-,7?ڰWBAUq?u.aCgVZ?*`{JTҿ8r;2Dd8x8#%>U5?ӔTr+f?~jgT6ʒڀgA.9vcJiP'rM,Zב +k 9#YAUi_BE,g{ޱ+B>^إQrZj?>ޒr_Akօ: # \6QoCL oP4&IةRU40=GִQa- \.]uIvm>IlvAx,\oߣgW.0R*{Xdq% 0Ar[սMZO/~g&((4ԋYS@A:kBO{\hT18:˷1{!_@& p 7i x`;q=I0,m2B+wIm H3QfKP *z"{'^ R$3mk}bsN64{w2&ܙ8ڑJп 0Ak MwԦk^ z7D6*]hԍq i˞8~bלswKkDCUJ/&|sD?*qH HXpB9FΦ3__P^(p< Uvza:xY0.4v!:/bakHMƜt]kW9\(?' 7Ms\TMJ;XT> a>}G.:Iȿ5;SS5:W'LgWyE.%_΃Z*̂7S1[x4{EbFjW{aIȯ]r BE>y5mՉ$%Xw,cEb>ē!B/lYw;n& = pll02ֱMDc0REK@J1 Z<2T.):i*;kHG l!WBC΁kҍ(Pȸ@`mwZ1jΣ-?޺ wJs H; _5*aKpm'骺wnw JRE)ZZ+3iCڝW`!j1XݍStuh7[,c 2ecgH485&x_Лu>KN|wɡNCPQl@Go6 qtJ_83J3G}|\ u2E0"X`夕^z'Z#kEf+%d&Lj1(Еņn`. ^SYȬMf X?ʋE(3^U P,sQC661ʹgY78l}ŖƷcV)C}𰓘n╀u_kd;kSsw"Sn'@Ҕ0ƞ~0g {[7H2O5%&*"t[EIba \o UՖLK9`V*QϐEr@3>Cчjz!SP]S3u{v?uee@ hĽi),=+yl6TPx=*Q!@)e3vD(tAxɟNƲQ,4>mlk\:H> h-H:0˝D[4~DOJ2ox*F$"YGAb[ZJy.qUBO?Üb SB㴣iG:SSME$a)b?N;JK#]ՇS'CbJZ[9BI$Ƣ, ? `/Rsl`8ɩ'Ӳպa+(UuT7xa)byYz 0IQE&/އC~l+vd䃵L-HxN͵V W\mCO 8}XIbd_rBhƢCS+1mTNztB&489ΰv >Xv"$ c$AJLQF}ܧ5Hⵇ~ Q i#_砉^QW).OG.n5- @V|JqrL!&Kxkg~ )xA*Z)^MkwWi2%eݳ~qWK4[wC⊮O1b cuBJo{,%c+|<(}@UY(j9}-`{@R8+C$ y Oi"Qa fdܨ@kF M/_5+hrdA0X*Z織M3O̝/~o4Y/{P))<2fBO]}̑X/AǏtٛkBh x0fR'Eʤ{fVТ__Y_PlveyQڻ=Rd_iSD. Ā_ګ>W4 S%  ͌Lӕ]d^(RO1Zt{ @ yX,؊sP%dMsz-!(*%5O3}'*߈+ )VBO{*V; ùk0/ zZ{T<}TSOŰ3|Vi.j/SzWlLB[F~$U ?f\r/J5墶̤2m% v.5#;[U&v1~$RZ)x>Va:_5ӡngpә#Tu @ jkHWh:_C* TnJX+B<;2S}f; #6MVKe*{'y{+Į0Qrߏy zmz:\mﷳ"7D=AuXˆLGKKy?Cl߄YO%ɘOS&w&<EJ)"biD NOSv`q}3 ?ըsO>/NI萎T4:>iØk40:\YMȁզAі!:^gc8& VMK{ *jQq~-k.tP9ϤImjA#7ߌ|n\z! 9c<KOΜg]G0?vCk Cظ2nмhW\kەW>Gxs0kW+n춏~|H Nxw#U)XL?s 2h70͗&)f:M)eLK꿠Xcݒȯ$m"ii1.҃gha9i&/Aϩoq8as8oE P_%닸dqM,M(1$ Bgn62U֧QYį!x_j˨I-(ħ%lU9ndLqAteZexթB< 'OL~lOW?P lT٣#}6@ S8D@(Jpu*3ģK9`38+rt+D{"[m}Bf9E>[bS/r6bSF]By)iq'E61(zt1FJ6^3RŜctN]׆}o{}^4PVh MZ^zy6 $,O;d#^|~9`T"duo<G8yuS{;zVN_xCf+ ]_X?{rE̍ZkcOudP_ l,gxul/|%n& AQE0{8pXhL/BfoTe+rz$DPY*)E״lHPGcq6%ŃzV;<6ۚpFÑb(q3a·~ [-Bz%7R:{/S$ u#OIL`Ҝ {ʷ(Ud.8H$TH(:t?afۤ3;bQcF/2 lFP)Ͻ>G&hw[_IcSj#"GX߱6.&XD>a(/+~}ET,CFy9g zhF'd +љO8x59˒WőC6{ )Zo{")v۶YD4C?L4"Uu}yy . ,r^çcW?Wl=u~'?Z"<|tlw?@oB4Jz%Lgz^n I s760? Z F,-/멉!k 3ڑY6IV@OɆq ~Щ73 EHMd1zzBXĀՓ3 =6u)|ͻBA낌Ө-$zkIBV$T++2o.s\~Cpe fKrLF.UptA#xt1"ɺ1cU윽PS^8~AFeަ f ==0IKzy]ӎ2A>Rd"faG=緋A .yMVtqd>˻S<iYna SӁn 1ysBdcd)Ilf1ϥd8eHu)[Z=C?/ZGl໐ :CQ4)bFm+Mdb7P6vYekRr`.\$Ehflu(u3;5q8L+YZbk?k3@ʂ1 h**VSb>vwZ_vwC(ܡ;Q-GxyNdvvܢyuY礤=M39}iP.#Hz&+I 0" <(Kr,CNľvT+Os*\& aڗ>xZd;dmنXrAkʱzޏ+ZdH{,r!2ka8'm~ofEg[or{dg-zE љȕYX l*7£6.di4:=(neÌ'R(I%2ڄCؔ秸jUI>UxeI<[O7I {y+.Vn}.Zo`#5Q"*-?;N&GJado?u)烾.g}-Yl)ǝ#CHݬ {iuD86Y2P63_;Au hnϩ1Jn/mB_5x]`omV6 2'x0 km 8^oxCQ _S QMAjd?1MYkD(H;PSm6QhҸ"u:0}&3I/*Kze*&?S8Iz%`&\~++L&cU7 `Y^]+hJ2Gy9?[!h˨C?*;!,HO|zD2 \WOAI v N ˫D!3AR6'/ $eGY8k3ņD\'\W"&ӣf6j Hk #b:QDnGNlڴW`gҠ5S[ (4uc(lBɱAb:RmMd %l2.+;}27,Hӥ۷6sq!ˈWH{>褧<-w$&q'~t(D%&pu׭T^*07'RKMX<Ţ3,cD"[gT&2;ש@hhN5.W{2gbK3 ^]ZiP1y.FS_ȱ溠I edi&Z;Heka"Q_g lcBc1nơ9FJv8A&kX$ cPABJT"OUs/PG]OT*EN!:Tw N OAnvwmm#4L\8 xawPQhZSotj"ՏOS d3XD=FZ Z9m93P@tV4s$hi􊻡"2P]~͕\﫜oX4iOx卲 ZmvYW'6N=>􏏇ST7_"CM8Vi5oln:IWx+#*`E;ÜrH p]X>;ly'fk<ͤ9nvk!\,j_-Hkc~5J5g >sm r$5SMbT9gfAn ^~Xxsy ?yٗ$Ϭ<98 u}m(T ɌJݴQW4V*n|;= x%5 tg*sC^ \(ҙ܅p. u_LY_}Mq# ˉ]/?UiPA1m$֐=s 4y[W>W?_7sM慮bY^r'^9NQ4,H(Q_4轱 b(WRZ:iM RToʁG O}HZG,[D{ [Td KPF Fo21z'1-uœeB1nPiRG#~yᏍ7;tv$'B#TD&[K^d4S<4Y^г2WO/4<-H>][^Fc1StC>jy喋یp4qMx$M6J}RK~ kRltM𔏐1Hڝp̶\}5gotjT )>z9.˦;~@ob@ںN26D"|8<^ ~@Mn-р\SN|4ݠ)H6T? ;$_ թ4yA&+^DBa}8|B.RBA.v -&>fw@w 1%XU U^6yY=&1:Р%de\ 8f19ad ϣYןOMѪº.Q5a'&$ռ`}3GR#{y9UR~o0lKm{Ƨ /&$T%?ϫHhzKBIX;R(H!s7 , t|:p۵j6/x#|f8Ӣ/<v7c! RPMy[4JcX ѓUR9'+S_ '|pVs6bXtĂl8̂6Aa5A7V3Ua~iy'<"ȡ;qXo ѻJ<YA j,b`Ce|,I`~mɁ="Ua͘-MƗKf5e98pU rd8pdmQ.> n 3Co9~@DʸQ52ܟ()kX,[ۚPBM qiMhJ5ni7$1T 0\'L1t+nE'M X 2{B-5sBFހo3}tئסH$ehuo'j̡O&Apn6׈](z{?#Q$(r^C+7pĎF;~Nwdb\\}p-BiaMQ};BYus_k %UbE˱S5b/*MS+%y0sl RQ(.hTZq? ]ơ捲}_;ݳRf$/]hTo\ڈg?dA4u &-ݕ>WQ:8(Qoca2O0DکAV}/ӖpzqVL]d*]=Bx-I/*z%;ƍS D22GB.ޛPΏbC$PwјW(*'y v[h OvGF8j5g7-g^+-&8;m9Qr_+xXG{i9~Q&hN6".D:e15>1ky?l쿼^"џ=ca3)eo絇ϯ6!95mOs/=S&a(/>Yp5pHiF$Xtdމ\GۉFtvvM5U@t)] ܄qQH LbH$qDNt> Ta6h̆Ku>9Sy"{ <[T|fЪ/=6 Mܙ~З Ѥ0T!d^ n1G3hAPڗ~D5Ys_xy#| f&cvKFX]zNcGdH70h0=RvKu[=5:2޵+ôPNb9LfbC[Όvg!B,25wR9 I mU&u9ac-m^߇u:f?l%l=?[S/P~IcD1!_J:7Yēmմ^?D4ZW+Iq6D$gMDvŷ=[QfC4nڮ\М. c4Yzid15ӱ= 6r+ᑞaR ?nҳ]V'ŐSDc=]hAɯXw Jm5]lZ7D)?8t$N?]9mbq2զq2J*`ƳDx Sv("|yVEUm%?COU'QU%ZD U\ö>\w׋Hb?>A]e^4~,1;ni>)% I/P4эg뮃W]`T")(._>%-E,Ytwؓ=J 3hK0k;ݬ ֶ!l3=|*O|c{(yșWe@EiXY njqs{q{WW1]c.DJ ]U+vXVp@ ;#j?c&n_. @4 s E7_4>BLaOrFSoB|1Edrf-઎BɚCI -&jiI%9DV7~<;n:{iCi>ԡ \Ƿ:H.}$SBy8iiH|x  |/\}r{H۵c[=Bn)吕lx>* #V}ifgڐ{=_&[)x Enf6b&/ga)g+/7V=;!Et ц53ŏ߶-C P#RB֏w!Hz.pwj2j\׾^QQn&3"F tLՇ @}"s+F,qTQW gʠَZ֒\e7tGu OAdc,}Ԃ[{<5*Ȭ,xdJZ?N_kn|gg" qibkA멝(qF~ѫíd۬6qKln"˨fv,ՙOki3ܩ#&GeOpy'v0xKқNj*85M۫Px`f5WhFC[.[W7Hϓo;(]u4ĥ Cn@B%+t3H lK ߵY&B {Ƒ뙥c} ]e?rTФd|~bw 8J{e>xEP-f!k+Y냑؀)*?/YUJ HHA`?  =?J`2ܨpUKH)R1g G qt-K-ߦGe%иFvڰĿ?#ƤEu) r)9;-H=Nl`{HIF$&T)˯Tl-2y;R53ecNRe^SR)2: &gWIfdga '@M:L>q7Ê}{E1k&~97Fp;&G O@G( . *@l 1PV25+ bf@#V9TM9uf.H CEVmM  ܀J ̱wP7lmGw]BlLS) ݯ^9hD}}HFK؇&,0c{OiUԑ*3~7 Aw>F^Wr ZS)rћv)Tco'ƺc[W =IPդ*47sYI?{]6V&nnxp&x.Tܙ2~u|C0X] m‹3{DZ١.YqZڻ|[pz{,`7H]H<[NY z$LW,}W+{rhѱXxQ]re)F'߀y /vl⸷\ACB^1g0zT'iNxM]%qb`%p= FA.p"VI%Jk@KNM=n{{ &.7^%X*Tk|%v , PCm-Ct*R twki@=*aD7`bYUb3VfﻣF.fLI{e7S@&nW@YݳF0m9/|H %z(w&q)8(`ۊ\C>NTf3h}%/}:I^by@{ }>܇ ?聿.?7,y&TQLH=ꍩC3(qV¹ zF /FɈ``(xC9';t9K) _} : ;bK3~$s=P6'RАKDMQ2ٔ@a s[!Qvk:_TmRM=sYT) 6 9ؔ#s`b@S,tDkW9UKw1rH5OǡKYwᆓ<诌n0L?ݲՏrp@ZڇQf%/걅*'\]kvmmmϖr[w&;]sfX:]lWE~n4ԱyzIʔ|Q۷ߦ=4P::x ϐ8sBL,a`=D v\!-h4{|m9[EVyAoX -=Q|m^%m{#"j_%bv0p2LhQwTlbpM=iસՊ|Hq;X`V8@%X e𗙾^TB] s*="gy«׷ºsԢcT͓rÖ,M#Y-uscˆ *)# . (a}VM_ǭq''Zwu7_lOٚ\%?~)P{a`F'BT%:-"UD*'NAF-\9R/[Q=6.f]&jUOź^`M` ^qfڎ`*kn?9SP #R 7 u GCje07Aȵ0^EWϫO_FmdtO)L.WO|/_,Nۄn4w==ek~a=֊E `,ױɧ@dl6IpѱHaA]U.w.p$=۰&OTrMMБ'ԁ~6/#qA9:mQGqFRz Y_'͛^b ?3"RR|GFՠGhTiW;[Rg`s֠Z r z :_.olK)s-T ;/92栛tl˖';fQZN)GU cQF,z]P?(%'zVZf1*8H~;{ՂX_c$lYݖkrQYè Y5S,>]oq-{XNPxʅ 2vSzLi8*J/=4On>sUsP խX%)d@Ci!yUIa+kƈKqÉ "WD)')#s = E1jnz¬@\LAa#y0~7^xH)m0!} "Jf~ʡ|Jw"s"U3J /eUt+%m;~BFWE%ʾV|2!4l:%R~Y-gWE~M4M?HeKo7aY)&Pc\EىYcy J??2PajьosA،/ ~&3ehd!ٸ:g񯻾KWOXi1+*)ɡ]2B I/nE9hUہ΀8]381J5)!S0 yFOXv]94# ?laGzQ$mPP;V+P y"n[tMMjq3ܤۤM :#~JXiLc7.:K %s0ݪ쒎ue$C<ҷ}|&TP-loy7,p,0JTXÓr-_C&U 7)oEB=Z } fU;)5!8c!р:e ΀M(#EX]= >k_ #il2yL!Sa9@>zʄC2-#:@ƉyX e(m9&罹1({ꩰo>M6,rYBg.IL?`g4D껩 rHy|MZȈ[TjPSVV姄Im};R*ʮkn:-7nّ{Nk1VT2$3v n[2PU*9r25RNi]6RakP f.PqQbuqM]ԳGXowR݄9'5K8UP'|5!wPpqPuXal_(Qb$CI6i,$,ps5RQVb&I yF dxBdѦ"+ Ci`^ 0sk*[@Kjx5s\Ջ1Ǡޓc*$yD G+4ru+/3;FR2mCkRC֕/0>89fZΓv78TWqΣ_+§OOrXkͺy+c@hTе^@HgDg{K'Dt?QyS:v`R8O턧lY6GD&bK^ÚTܫ}e"HO4jqI<].!!Au-٫/T10C,> Ol4 ɭp0? f%DiSm/"0H~ „Wep&~n˭.{@:5aWM,}8gϦElJvg q5^]cTso5(p? ezl1 |̌LW Q>q!GP 9KLx>P tGV'g} _rF#s|"Z-3)Est{{nFUP9gXj+ (ސUg rQöfΞ{jr|3`e;yʺhiA "Z mcǗgC`Rax5ik9_j231E2d*p\y۾!!iN+"ըI A>׏]טr;l p"Džݔphbz֣GYJ[bCGTg1i Y<<a>Zc/~g]Q@F2Ji sQbQb86*(ػo".ˏа\ݼ(QB- (Ay1}32+ ՓVkvdѓ >BCh(3@gЄ;ͅ_|x zykYЎMAT(޾NdR~wb&7PVԘ.AIQzvu]DBpz(3&fKc-N unS{+yUH4jj,*?pS Bt[,bkT!7fJS9=h5nsn$۴ kK_+UVVvAPZb+ty{Ny Գh}oycb")cbG=lYh({|Fۼs+ydimRrκ2D4GV"sF)d6[K+iߗO&oEV-DLvl naCBY~;, `M3#W-6hɮTvU#W22FLC>2s%BAZ?<uxm}΅5_g. 5Җț#$ 9΋@ a][*a L}ǜmz3āc&lcbMG-OK%II.L)E|^vIA5:\>Lvm$y9il j(L3UeRj)dqZ7mӆXmUML0 NYO+_qd`Qo&͉`"°Yd%`,jd5Y꧘Ωغ7,~r9K KÕ`b$&pkڕ 3uFѫl23vUtp4`@6d\&봊=Q.W Zc[= > ЉYKMO%@a\qԁROQ7ŝ#(8R[p\&o 9\l xHBW\# NpN(.7>#egE/_u]ЛnR}K8iF!hNI54^A,_oo!8f{ąvebnZY] bωs>q~&h{Y &oÁ{ ~[J믵M$F(x:-$F3juܡN,͠0!͓~1n=B%MDG^lwdgspel벴شXE]iEJ e ~S«`s0!2:i\ %Zce\K0Q˘Nש5osh@Z?F9 ƭe:JB1t@+YܭOE+ cєR; n[ )GY7\?l{lы?<@ P,vp`#e2jJyH28C;Jd7碑LXl9ljuGRS)ގh5&#L{m;dWL=[aB@t!<9D(=eʟ'+8E5nm%L^`̿ԂRzj|7$"* @ҥt ĝn+5,^st@ϭ9~f*Y<5bxB !RoZPI2A5َ! ODϵ/:eT!"0wGO{LTayJȄ=WR>/Ǽ#q28ZR7e.e+cް"o^5 NTK0񜄿 k}FTdtH]^Z^S}-"E^$g{z;h#7%sҺjY>ywQ>ykni-PTY \#%*Vb!O ^词0>g cJ&5څ7ȉ@";܆CVvFjŧ QYUf>Jղ}&Yn"`#Snd0:`oH2}i"m;2iFOT}$/;!G U  ,]B2bW#߆yNb21 ?`:rK& 듏VØv S3b5" D|O:5X>ae8 ۑZ=G3=av2q`J[|攃^pe}E-Z@)yqnhޱF":JLV?#Cq 緔" XAaDںG>0 YZgeosphere/man/0000755000176200001440000000000014334225312013005 5ustar liggesusersgeosphere/man/area.Rd0000644000176200001440000000405214131145600014201 0ustar liggesusers\name{areaPolygon} \Rdversion{1.1} \alias{areaPolygon} \alias{areaPolygon,matrix-method} \alias{areaPolygon,data.frame-method} \alias{areaPolygon,SpatialPolygons-method} \title{ Area of a longitude/latitude polygon } \description{ Compute the area of a polygon in angular coordinates (longitude/latitude) on an ellipsoid. } \usage{ \S4method{areaPolygon}{matrix}(x, a=6378137, f=1/298.257223563, ...) \S4method{areaPolygon}{SpatialPolygons}(x, a=6378137, f=1/298.257223563, ...) } \arguments{ \item{x}{longitude/latitude of the points forming a polygon; Must be a matrix or data.frame of 2 columns (first one is longitude, second is latitude) or a SpatialPolygons* object} \item{a}{major (equatorial) radius of the ellipsoid} \item{f}{ellipsoid flattening. The default value is for WGS84 } \item{...}{Additional arguments. None implemented} } \value{ area in square meters } \note{ Use raster::area for polygons that have a planar (projected) coordinate reference system. } \author{ This function calls GeographicLib code by C.F.F. Karney } \references{ C.F.F. Karney, 2013. Algorithms for geodesics, J. Geodesy 87: 43-55. \doi{10.1007/s00190-012-0578-z}. Addenda: \url{https://geographiclib.sourceforge.io/geod-addenda.html}. Also see \url{https://geographiclib.sourceforge.io/} } \seealso{ \code{ \link[geosphere]{centroid}, \link[geosphere]{perimeter} } } \examples{ p <- rbind(c(-180,-20), c(-140,55), c(10, 0), c(-140,-60), c(-180,-20)) areaPolygon(p) # Be careful with very large polygons, as they may not be what they seem! # For example, if you wanted a polygon to compute the area equal to about 1/4 of the ellipsoid # this won't work: b <- matrix(c(-180, 0, 90, 90, 0, 0, -180, 0), ncol=2, byrow=TRUE) areaPolygon(b) # Becausee the shortest path between (-180,0) and (0,0) is # over one of the poles, not along the equator! # Inserting a point along the equator fixes that b <- matrix(c(-180, 0, 0, 0, -90,0, -180, 0), ncol=2, byrow=TRUE) areaPolygon(b) } \keyword{ spatial } geosphere/man/bearingRhumb.Rd0000644000176200001440000000217014131210620015670 0ustar liggesusers\name{bearingRhumb} \Rdversion{1.1} \alias{bearingRhumb} \title{ Rhumbline direction } \description{ Bearing (direction of travel; true course) along a rhumb line (loxodrome) between two points. } \usage{ bearingRhumb(p1, p2) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as above} } \value{ A direction (bearing) in degrees } \references{ \url{https://www.edwilliams.org/avform147.htm#Rhumb} \url{https://en.wikipedia.org/wiki/Rhumb_line} } \author{ Chris Veness and Robert Hijmans, based on formulae by Ed Williams } \note{ Unlike most great circles, a rhumb line is a line of constant bearing (direction), i.e. tracks of constant true course. The meridians and the equator are both rhumb lines and great circles. Rhumb lines approaching a pole become a tightly wound spiral. } \seealso{ \code{ \link[geosphere]{bearing}, \link[geosphere]{distRhumb} } } \examples{ bearingRhumb(c(10,10),c(20,20)) } \keyword{ spatial } geosphere/man/finalDirection.Rd0000644000176200001440000000261714131145601016231 0ustar liggesusers\name{finalBearing} \Rdversion{1.1} \alias{finalBearing} \title{ Final direction } \description{ Get the final direction (bearing) when arriving at \code{p2} after starting from \code{p1} and following the shortest path on an ellipsoid (following a geodetic) or on a sphere (following a great circle). } \usage{ finalBearing(p1, p2, a=6378137, f=1/298.257223563, sphere=FALSE) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first column is longitude, second column is latitude) or a SpatialPoints* object} \item{p2}{as above} \item{a}{major (equatorial) radius of the ellipsoid. The default value is for WGS84 } \item{f}{ellipsoid flattening. The default value is for WGS84 } \item{sphere}{logical. If \code{TRUE}, the bearing is computed for a sphere, instead of for an ellipsoid} } \value{ A vector of directions (bearings) in degrees } \examples{ bearing(c(10,10),c(20,20)) finalBearing(c(10,10),c(20,20)) } \author{ This function calls GeographicLib code by C.F.F. Karney } \references{ C.F.F. Karney, 2013. Algorithms for geodesics, J. Geodesy 87: 43-55. \doi{10.1007/s00190-012-0578-z}. Addenda: \url{https://geographiclib.sourceforge.io/geod-addenda.html}. Also see \url{https://geographiclib.sourceforge.io/} } \seealso{ \code{ \link[geosphere]{bearing} } } \keyword{ spatial } geosphere/man/distVincentySphere.Rd0000644000176200001440000000241514131143521017124 0ustar liggesusers\name{distVincentySphere} \Rdversion{1.1} \alias{distVincentySphere} \title{ 'Vincenty' (sphere) great circle distance } \description{ The shortest distance between two points (i.e., the 'great-circle-distance' or 'as the crow flies'), according to the 'Vincenty (sphere)' method. This method assumes a spherical earth, ignoring ellipsoidal effects and it is less accurate then the \code{distVicentyEllipsoid} method. } \usage{ distVincentySphere(p1, p2, r=6378137) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as above; or missing, in which case the sequential distance between the points in p1 is computed} \item{r}{radius of the earth; default = 6378137 m} } \value{ Distance value in the same unit as \code{r} (default is meters) } \references{ \url{https://en.wikipedia.org/wiki/Great_circle_distance} } \author{ Robert Hijmans } \seealso{ \code{\link[geosphere]{distGeo}, \link[geosphere]{distVincentyEllipsoid}, \link[geosphere]{distHaversine}, \link[geosphere]{distCosine}, \link{distMeeus}} } \examples{ distVincentySphere(c(0,0),c(90,90)) } \keyword{ spatial } geosphere/man/greatCircleBearing.Rd0000644000176200001440000000152114131210620016776 0ustar liggesusers\name{greatCircleBearing} \Rdversion{1.1} \alias{greatCircleBearing} \title{ Great circle } \description{ Get points on a great circle as defined by a point and an initial bearing } \usage{ greatCircleBearing(p, brng, n=360) } \arguments{ \item{p}{longitude/latitude of a single point. Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{brng}{bearing} \item{n}{The requested number of points on the great circle} } \value{ A matrix of points, or a list of matrices (e.g., if multiple bearings are supplied) } \references{ \url{https://www.edwilliams.org/avform147.htm#Int} } \author{ Robert Hijmans based on formulae by Ed Williams } \examples{ greatCircleBearing(c(5,52), 45, n=12) } \keyword{ spatial } geosphere/man/perimeter.Rd0000644000176200001440000000321114131145601015262 0ustar liggesusers\name{perimeter} \Rdversion{1.1} \alias{perimeter} \alias{perimeter,matrix-method} \alias{perimeter,data.frame-method} \alias{perimeter,SpatialPolygons-method} \alias{perimeter,SpatialLines-method} \title{ Compute the perimeter of a longitude/latitude polygon } \description{ Compute the perimeter of a polygon (or the length of a line) with longitude/latitude coordinates, on an ellipsoid (WGS84 by default) } \usage{ \S4method{perimeter}{matrix}(x, a=6378137, f=1/298.257223563, ...) \S4method{perimeter}{SpatialPolygons}(x, a=6378137, f=1/298.257223563, ...) \S4method{perimeter}{SpatialLines}(x, a=6378137, f=1/298.257223563, ...) } \arguments{ \item{x}{Longitude/latitude of the points forming a polygon or line; Must be a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPolygons* or SpatialLines* object} \item{a}{major (equatorial) radius of the ellipsoid. The default value is for WGS84 } \item{f}{ellipsoid flattening. The default value is for WGS84 } \item{...}{Additional arguments. None implemented} } \value{ Numeric. The perimeter or length in m. } \seealso{ \code{ \link{areaPolygon}, \link[geosphere]{centroid} } } \author{ This function calls GeographicLib code by C.F.F. Karney } \references{ C.F.F. Karney, 2013. Algorithms for geodesics, J. Geodesy 87: 43-55. \doi{10.1007/s00190-012-0578-z}. Addenda: \url{https://geographiclib.sourceforge.io/geod-addenda.html}. Also see \url{https://geographiclib.sourceforge.io/} } \examples{ xy <- rbind(c(-180,-20), c(-140,55), c(10, 0), c(-140,-60), c(-180,-20)) perimeter(xy) } \keyword{ spatial } geosphere/man/distm.Rd0000644000176200001440000000200014131143521014400 0ustar liggesusers\name{distm} \Rdversion{1.1} \alias{distm} \title{ Distance matrix } \description{ Distance matrix of a set of points, or between two sets of points } \usage{ distm(x, y, fun=distGeo) } \arguments{ \item{x}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{y}{Same as \code{x}. If missing, y is the same as x} \item{fun}{A function to compute distances (e.g., distCosine or distGeo)} } \value{ Matrix of distances } \references{ \url{https://en.wikipedia.org/wiki/Great_circle_distance} } \author{ Robert Hijmans } \seealso{ \code{\link[geosphere]{distGeo}, \link[geosphere]{distCosine}, \link[geosphere]{distHaversine}, \link[geosphere]{distVincentySphere}, \link[geosphere]{distVincentyEllipsoid}} } \examples{ xy <- rbind(c(0,0),c(90,90),c(10,10),c(-120,-45)) distm(xy) xy2 <- rbind(c(0,0),c(10,-10)) distm(xy, xy2) } \keyword{ spatial } geosphere/man/horizon.Rd0000644000176200001440000000137514131210620014761 0ustar liggesusers\name{horizon} \alias{horizon} \title{Distance to the horizon} \description{ Empirical function to compute the distance to the horizon from a given altitude. The earth is assumed to be smooth, i.e. mountains and other obstacles are ignored. } \usage{ horizon(h, r=6378137) } \arguments{ \item{h}{altitude, numeric >= 0. Should have the same unit as r} \item{r}{radius of the earth; default value is 6378137 m} } \value{ Distance in units of \code{h} (default is meters) } \references{ \url{https://www.edwilliams.org/avform147.htm#Horizon} Bowditch, 1995. American Practical Navigator. Table 12. } \author{ Robert J. Hijmans } \examples{ horizon(1.80) # me horizon(324) # Eiffel tower } \keyword{ spatial } geosphere/man/makepoly.Rd0000644000176200001440000000221713472155746015136 0ustar liggesusers\name{makePoly} \alias{makePoly} \alias{makeLine} \title{Add vertices to a polygon or line} \description{ Make a polygon or line by adding intermedate points (vertices) on the great circles inbetween the points supplied. This can be relevant when vertices are relatively far apart. It can make the shape of the object to be accurate, when plotted on a plane. \code{makePoly} will also close the polygon if needed. } \usage{ makePoly(p, interval=10000, sp=FALSE, ...) makeLine(p, interval=10000, sp=FALSE, ...) } \arguments{ \item{p}{a 2-column matrix (longitude/latitude) or a SpatialPolygons or SpatialLines object} \item{interval}{maximum interval of points, in units of r} \item{sp}{Logical. If \code{TRUE}, a SpatialPolygons object is retunred (depends on the 'sp' package)} \item{...}{additional arguments passed to distGeo} } \value{ A matrix } \author{Robert J. Hijmans } \examples{ pol <- rbind(c(-180,-20), c(-160,5), c(-60, 0), c(-160,-60), c(-180,-20)) plot(pol) lines(pol, col='red', lwd=3) pol2 = makePoly(pol, interval=100000) lines(pol2, col='blue', lwd=2) } \keyword{methods} \keyword{spatial} geosphere/man/gcIntersectBearing.Rd0000644000176200001440000000231414131210620017025 0ustar liggesusers\name{gcIntersectBearing} \Rdversion{1.1} \alias{gcIntersectBearing} \title{ Intersections of two great circles } \description{ Get the two points where two great cricles cross each other. In this function, great circles are defined by a points and an initial bearing. In function \code{ \link[geosphere]{gcIntersect}} they are defined by two sets of points. } \usage{ gcIntersectBearing(p1, brng1, p2, brng2) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{brng1}{Bearing from p1} \item{p2}{As above. Should have same length as p1, or a single point (or vice versa when p1 is a single point} \item{brng2}{Bearing from p2} } \value{ a matrix with four columns (two points) } \seealso{ \code{ \link[geosphere]{gcIntersect} } } \references{ \url{https://www.edwilliams.org/avform147.htm#Intersection} \url{https://www.movable-type.co.uk/scripts/latlong.html} } \author{ Chris Veness and Robert Hijmans based on code by Ed Williams } \examples{ gcIntersectBearing(c(10,0), 10, c(-10,0), 10) } \keyword{ spatial } geosphere/man/distCosine.Rd0000644000176200001440000000211514131143521015373 0ustar liggesusers\name{distCosine} \Rdversion{1.1} \alias{distCosine} \title{ 'Law of cosines' great circle distance } \description{ The shortest distance between two points (i.e., the 'great-circle-distance' or 'as the crow flies'), according to the 'law of the cosines'. This method assumes a spherical earth, ignoring ellipsoidal effects. } \usage{ distCosine(p1, p2, r=6378137) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as above} \item{r}{radius of the earth; default = 6378137 m} } \value{ Vector of distances in the same unit as \code{r} (default is meters) } \references{ \url{https://en.wikipedia.org/wiki/Great_circle_distance} } \author{ Robert Hijmans } \seealso{ \code{\link[geosphere]{distGeo}, \link[geosphere]{distHaversine}, \link[geosphere]{distVincentySphere}, \link[geosphere]{distVincentyEllipsoid}, \link{distMeeus}} } \examples{ distCosine(c(0,0),c(90,90)) } \keyword{ spatial } geosphere/man/plotArrows.Rd0000644000176200001440000000211513472155746015466 0ustar liggesusers\name{plotArrows} \alias{plotArrows} \title{Plot} \description{ Plot polygons with arrow heads on each line segment, pointing towards the next vertex. This shows the direction of each line segment. } \usage{ plotArrows(p, fraction=0.9, length=0.15, first='', add=FALSE, ...) } \arguments{ \item{p}{Polygons (either a 2 column matrix or data.frame; or a SpatialPolygons* object} \item{fraction}{numeric between 0 and 1. When smaller then 1, interrupted lines are drawn} \item{length}{length of the edges of the arrow head (in inches)} \item{first}{Character to plot on first (and last) vertex } \item{add}{Logical. If \code{TRUE}, the plot is added to an existing plot} \item{...}{Additional arguments, see Details} } \author{Robert J. Hijmans} \note{ Based on an example in Software for Data Analysis by John Chambers (pp 250-251) but adjusted such that the line segments follow great circles between vertices. } \examples{ pol <- rbind(c(-180,-20), c(-160,5), c(-60, 0), c(-160,-60), c(-180,-20)) plotArrows(pol) } \keyword{methods} \keyword{spatial} geosphere/man/distRhumb.Rd0000644000176200001440000000272114131143521015233 0ustar liggesusers\name{distRhumb} \Rdversion{1.1} \alias{distRhumb} \title{ Distance along a rhumb line } \description{ A rhumb line (loxodrome) is a path of constant bearing (direction), which crosses all meridians at the same angle. } \usage{ distRhumb(p1, p2, r=6378137) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as above; or missing, in which case the sequential distance between the points in p1 is computed} \item{r}{radius of the earth; default = 6378137 m} } \details{ Rhumb (from the Spanish word for course, 'rumbo') lines are straight lines on a Mercator projection map. They were used in navigation because it is easier to follow a constant compass bearing than to continually adjust the bearing as is needed to follow a great circle, even though rhumb lines are normally longer than great-circle (orthodrome) routes. Most rhumb lines will gradually spiral towards one of the poles. } \value{ distance in units of r (default=meters) } \references{ \url{https://www.movable-type.co.uk/scripts/latlong.html} } \author{ Robert Hijmans and Chris Veness } \seealso{ \code{\link[geosphere]{distCosine}, \link[geosphere]{distHaversine}, \link[geosphere]{distVincentySphere}, \link[geosphere]{distVincentyEllipsoid}} } \examples{ distRhumb(c(10,10),c(20,20)) } \keyword{ spatial } geosphere/man/dist2line.Rd0000644000176200001440000000340614131141731015171 0ustar liggesusers\name{dist2Line} \Rdversion{1.1} \alias{dist2Line} \title{ Distance between points and lines or the border of polygons. } \description{ The shortest distance between points and polylines or polygons. } \usage{dist2Line(p, line, distfun=distGeo) } \arguments{ \item{p}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{line}{longitude/latitude of line as a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialLines* or SpatialPolygons* object} \item{distfun}{A distance function, such as \link[geosphere]{distGeo}} } \value{ matrix with distance and lon/lat of the nearest point on the line. Distance is in the same unit as \code{r} in the \code{distfun}(default is meters). If \code{line} is a \code{Spatial*} object, the ID (index) of (one of) the nearest objects is also returned. Thus if the objects are polygons and the point is inside a polygon the function may return the ID of a neighboring polygon that shares the nearest border. You can use the \code{intersect} function in packages \code{terra}. } \author{ George Wang and Robert Hijmans } \seealso{ \code{\link{dist2gc}, \link{alongTrackDistance} } } \examples{ line <- rbind(c(-180,-20), c(-150,-10), c(-140,55), c(10, 0), c(-140,-60)) pnts <- rbind(c(-170,0), c(-75,0), c(-70,-10), c(-80,20), c(-100,-50), c(-100,-60), c(-100,-40), c(-100,-20), c(-100,-10), c(-100,0)) d = dist2Line(pnts, line) plot( makeLine(line), type='l') points(line) points(pnts, col='blue', pch=20) points(d[,2], d[,3], col='red', pch='x') for (i in 1:nrow(d)) lines(gcIntermediate(pnts[i,], d[i,2:3], 10), lwd=2) } \keyword{ spatial } geosphere/man/lengthLine.Rd0000644000176200001440000000112414131141671015363 0ustar liggesusers\name{lengthLine} \alias{lengthLine} \title{ Length of lines } \description{ Compute the length of lines } \usage{ lengthLine(line) } \arguments{ \item{line}{longitude/latitude of line as a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialLines* or SpatialPolygons* object} } \value{ length (in meters) for each line } \seealso{ For planar coordinates, see the terra or sf packages } \examples{ line <- rbind(c(-180,-20), c(-150,-10), c(-140,55), c(10, 0), c(-140,-60)) d <- lengthLine(line) } \keyword{ spatial } geosphere/man/geosphere-package.Rd0000644000176200001440000000443014131210620016636 0ustar liggesusers\name{geosphere-package} \alias{geosphere-package} \alias{geosphere} \docType{package} \title{Geosphere} \description{ This package implements functions that compute various aspects of distance, direction, area, etc. for geographic (geodetic) coordinates. Some of the functions are based on an ellipsoid (spheroid) model of the world, other functions use a (simpler, but less accuarate) spherical model. Functions using an ellipsoid can be recognized by having arguments to specify the ellipsoid's radius and flattening (\code{a} and \code{f}). By setting the value for \code{f} to zero, the ellipsoid becomes a sphere. There are also functions to compute intersections of of rhumb lines. There are also functions to compute the distance between points and polylines, and to characterize spherical polygons; for random sampling on a sphere, and to compute daylength. See the vignette \code{vignette('geosphere')} for examples. Geographic locations must be specified in latitude and longitude in degrees (NOT radians). Degrees are (obviously) in decimal notation. Thus 12 degrees, 30 minutes, 10 seconds = 12 + 30/60 + 10/3600 = 12.50278 degrees. The Southern and Western hemispheres have a negative sign. The default unit of distance is meter; but this can be adjusted by supplying a different radius \code{r} to functions. Directions are expressed in degrees (North = 0 and 360, East = 90, Sout = 180, and West = 270 degrees). } \author{ Robert Hijmans, using code by C.F.F. Karney and Chris Veness; formulas by Ed Williams; and with contributions from George Wang, Elias Pipping and others. Maintainer: Robert J. Hijmans } \references{ C.F.F. Karney, 2013. Algorithms for geodesics, J. Geodesy 87: 43-55. \doi{10.1007/s00190-012-0578-z}. Addenda: \url{https://geographiclib.sourceforge.io/geod-addenda.html}. Also see \url{https://geographiclib.sourceforge.io/} \url{https://www.edwilliams.org/avform147.htm} \url{https://www.movable-type.co.uk/scripts/latlong.html} \url{https://en.wikipedia.org/wiki/Great_circle_distance} \url{https://mathworld.wolfram.com/SphericalTrigonometry.html} } \section{Acknowledgements}{ David Purdy, Bill Monahan and others for suggestions to improve the package. } \keyword{ package } \keyword{ spatial } geosphere/man/gcMaxLat.Rd0000644000176200001440000000231714131143521014773 0ustar liggesusers\name{gcMaxLat} \Rdversion{1.1} \alias{gcMaxLat} \title{ Highest latitude on a great circle } \description{ What is northern most point that will be reached when following a great circle? Computed with Clairaut's formula. The southern most point is the \code{\link[geosphere]{antipode}} of the northern-most point. This does not seem to be very precise; and you could use optimization instead to find this point (see examples) } \usage{ gcMaxLat(p1, p2) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as above} } \value{ A matrix with coordinates (longitude/latitude) } \references{ \url{https://www.edwilliams.org/ftp/avsig/avform.txt} \url{https://www.movable-type.co.uk/scripts/latlong.html} } \author{ Ed Williams, Chris Veness, Robert Hijmans } \seealso{ \code{\link[geosphere]{gcLat}, \link[geosphere]{gcLon}} } \examples{ gcMaxLat(c(5,52), c(-120,37)) # Another way to get there: f <- function(lon){gcLat(c(5,52), c(-120,37), lon)} optimize(f, interval=c(-180, 180), maximum=TRUE) } \keyword{ spatial } geosphere/man/gcIntersect.Rd0000644000176200001440000000171014131143521015541 0ustar liggesusers\name{gcIntersect} \Rdversion{1.1} \alias{gcIntersect} \title{ Intersections of two great circles } \description{ Get the two points where two great cricles cross each other. Great circles are defined by two points on it. } \usage{ gcIntersect(p1, p2, p3, p4) } \arguments{ \item{p1}{Longitude/latitude of a single point, in degrees; can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{As above} \item{p3}{As above} \item{p4}{As above} } \value{ two points for each pair of great circles } \seealso{ \code{ \link[geosphere]{gcIntersectBearing} } } \references{ \url{https://www.edwilliams.org/intersect.htm} } \author{ Robert Hijmans, based on equations by Ed Williams (see reference) } \examples{ p1 <- c(5,52); p2 <- c(-120,37); p3 <- c(-60,0); p4 <- c(0,70) gcIntersect(p1,p2,p3,p4) } \keyword{ spatial } geosphere/man/bearing.Rd0000644000176200001440000000300614131145600014676 0ustar liggesusers\name{bearing} \Rdversion{1.1} \alias{bearing} \title{ Direction of travel } \description{ Get the initial bearing (direction; azimuth) to go from point \code{p1} to point \code{p2} (in longitude/latitude) following the shortest path on an ellipsoid (geodetic). Note that the bearing of travel changes continuously while going along the path. A route with constant bearing is a rhumb line (see \code{\link[geosphere]{bearingRhumb}}). } \usage{ bearing(p1, p2, a=6378137, f=1/298.257223563) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as above. Can also be missing, in which case the bearing is computed going from the first point to the next and continuing along the following points} \item{a}{major (equatorial) radius of the ellipsoid. The default value is for WGS84 } \item{f}{ellipsoid flattening. The default value is for WGS84 } } \note{use \code{f=0} to get a bearing on a sphere (great circle)} \value{ Bearing in degrees } \author{ Robert Hijmans } \references{ C.F.F. Karney, 2013. Algorithms for geodesics, J. Geodesy 87: 43-55. \doi{10.1007/s00190-012-0578-z}. Addenda: \url{https://geographiclib.sourceforge.io/geod-addenda.html}. Also see \url{https://geographiclib.sourceforge.io/} } \seealso{ \code{ \link[geosphere]{bearingRhumb} } } \examples{ bearing(c(10,10),c(20,20)) } \keyword{ spatial } geosphere/man/distGeo.Rd0000644000176200001440000000551614131145601014676 0ustar liggesusers\name{distGeo} \Rdversion{1.1} \alias{distGeo} \title{ Distance on an ellipsoid (the geodesic) } \description{ Highly accurate estimate of the shortest distance between two points on an ellipsoid (default is WGS84 ellipsoid). The shortest path between two points on an ellipsoid is called the geodesic. } \usage{ distGeo(p1, p2, a=6378137, f=1/298.257223563) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first column is longitude, second column is latitude) or a SpatialPoints* object} \item{p2}{as above; or missing, in which case the sequential distance between the points in p1 is computed} \item{a}{numeric. Major (equatorial) radius of the ellipsoid. The default value is for WGS84 } \item{f}{numeric. Ellipsoid flattening. The default value is for WGS84 } } \value{ Vector of distances in meters } \details{ Parameters from the WGS84 ellipsoid are used by default. It is the best available global ellipsoid, but for some areas other ellipsoids could be preferable, or even necessary if you work with a printed map that refers to that ellipsoid. Here are parameters for some commonly used ellipsoids. Also see the \code{\link{refEllipsoids}} function. \tabular{rlll}{ \tab \code{ ellipsoid } \tab \code{ a } \tab \code{ f } \cr \tab \code{ WGS84 } \tab \code{ 6378137 } \tab \code{ 1/298.257223563 } \cr \tab \code{ GRS80 } \tab \code{ 6378137 } \tab \code{ 1/298.257222101 } \cr \tab \code{ GRS67 } \tab \code{ 6378160 } \tab \code{ 1/298.25 } \cr \tab \code{ Airy 1830 } \tab \code{ 6377563.396 } \tab \code{ 1/299.3249646 } \cr \tab \code{ Bessel 1841 } \tab \code{ 6377397.155 } \tab \code{ 1/299.1528434 } \cr \tab \code{ Clarke 1880 } \tab \code{ 6378249.145 } \tab \code{ 1/293.465 } \cr \tab \code{ Clarke 1866 } \tab \code{ 6378206.4 } \tab \code{ 1/294.9786982 } \cr \tab \code{ International 1924 } \tab \code{ 6378388 } \tab \code{ 1/297 } \cr \tab \code{ Krasovsky 1940 } \tab \code{ 6378245 } \tab \code{ 1/298.2997381 } \cr } more info: \url{https://en.wikipedia.org/wiki/Reference_ellipsoid} } \author{ This function calls GeographicLib code by C.F.F. Karney } \references{ C.F.F. Karney, 2013. Algorithms for geodesics, J. Geodesy 87: 43-55. \doi{10.1007/s00190-012-0578-z}. Addenda: \url{https://geographiclib.sourceforge.io/geod-addenda.html}. Also see \url{https://geographiclib.sourceforge.io/} } \seealso{ \code{\link[geosphere]{distCosine}, \link[geosphere]{distHaversine}, \link[geosphere]{distVincentySphere}, \link[geosphere]{distVincentyEllipsoid}, \link{distMeeus}} } \examples{ distGeo(c(0,0),c(90,90)) } \keyword{ spatial } geosphere/man/gcLon.Rd0000644000176200001440000000143414131210620014327 0ustar liggesusers\name{gcLon} \Rdversion{1.1} \alias{gcLon} \title{ Longitude on a Great Circle } \description{ Longitudes at which a great circle crosses a latitude (parallel) } \usage{ gcLon(p1, p2, lat) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as above} \item{lat}{a latitude} } \value{ vector of two numbers (longitudes) } \references{ \url{https://www.edwilliams.org/avform147.htm#Intersection} } \author{ Robert Hijmans based on code by Ed Williams } \seealso{ \code{\link[geosphere]{gcLat}, \link[geosphere]{gcMaxLat}} } \examples{ gcLon(c(5,52), c(-120,37), 40) } \keyword{ spatial } geosphere/man/onGreatCircle.Rd0000644000176200001440000000160613472155746016037 0ustar liggesusers\name{onGreatCircle} \Rdversion{1.1} \alias{onGreatCircle} \title{ Is a point on a given great circle? } \description{ Test if a point is on a great circle defined by two other points. } \usage{ onGreatCircle(p1, p2, p3, tol=0.0001) } \arguments{ \item{p1}{Longitude/latitude of the first point defining a great circle, in degrees; can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as above for the second point} \item{p3}{the point(s) to be tested if they are on the great circle or not} \item{tol}{numeric. maximum distance from the great circle (in degrees) that is tolerated to be considered on the circle} } \value{ logical } \author{ Robert Hijmans } \examples{ onGreatCircle(c(0,0), c(30,30), rbind(c(-10 -11.33812), c(10,20))) } \keyword{ spatial } geosphere/man/gcLat.Rd0000644000176200001440000000142114131210620014313 0ustar liggesusers\name{gcLat} \Rdversion{1.1} \alias{gcLat} \title{ Latitude on a Great Circle } \description{ Latitude at which a great circle crosses a longitude } \usage{ gcLat(p1, p2, lon) } \arguments{ \item{p1}{Longitude/latitude of a single point, in degrees; can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{As above} \item{lon}{Longitude} } \value{ A numeric (latitude) } \references{ \url{https://www.edwilliams.org/avform147.htm#Int} } \author{ Robert Hijmans based on a formula by Ed Williams } \seealso{ \code{\link[geosphere]{gcLon}, \link[geosphere]{gcMaxLat}} } \examples{ gcLat(c(5,52), c(-120,37), lon=-120) } \keyword{ spatial } geosphere/man/destPointRhumb.Rd0000644000176200001440000000214614131210620016235 0ustar liggesusers\name{destPointRhumb} \Rdversion{1.1} \alias{destPointRhumb} \title{ Destination along a rhumb line } \description{ Calculate the destination point when travelling along a 'rhumb line' (loxodrome), given a start point, direction, and distance. } \usage{ destPointRhumb(p, b, d, r = 6378137) } \arguments{ \item{p}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{b}{bearing (direction) in degrees} \item{d}{distance; in the same unit as \code{r} (default is meters)} \item{r}{radius of the earth; default = 6378137 m} } \value{ Coordinates (longitude/latitude) of a point } \references{ \url{https://www.edwilliams.org/avform147.htm#Rhumb} \url{https://www.movable-type.co.uk/scripts/latlong.html} \url{https://en.wikipedia.org/wiki/Rhumb_line} } \author{ Chris Veness; ported to R by Robert Hijmans } \seealso{ \code{ \link[geosphere]{destPoint} } } \examples{ destPointRhumb(c(0,0), 30, 100000, r = 6378137) } \keyword{ spatial } geosphere/man/dist2gc.Rd0000644000176200001440000000267014131143521014634 0ustar liggesusers\name{dist2gc} \Rdversion{1.1} \alias{dist2gc} \title{ Cross Track Distance } \description{ Compute the distance of a point to a great-circle path (also referred to as the cross track distance or cross track error). The great circle is defined by \code{p1} and \code{p2}, while \code{p3} is the point away from the path. } \usage{ dist2gc(p1, p2, p3, r=6378137, sign=FALSE) } \arguments{ \item{p1}{Start of great circle path. longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{End of great circle path. As above} \item{p3}{Point away from the great cricle path. As for p2} \item{r}{radius of the earth; default = 6378137} \item{sign}{logical. If \code{TRUE}, a negative sign is used to indicated that the points are to the left of the great circle} } \value{ A distance in units of \code{r} (default is meters) If \code{sign=TRUE}, the sign indicates which side of the path p3 is on. Positive means right of the course from p1 to p2, negative means left. } \author{ Ed Williams and Robert Hijmans } \seealso{ \code{\link{dist2Line}, \link{alongTrackDistance} } } \references{ \url{https://www.movable-type.co.uk/scripts/latlong.html} \url{https://www.edwilliams.org/ftp/avsig/avform.txt} } \examples{ dist2gc(c(0,0),c(90,90),c(80,80)) } \keyword{ spatial } geosphere/man/distHaversine.Rd0000644000176200001440000000342114131143521016100 0ustar liggesusers\name{distHaversine} \Rdversion{1.1} \alias{distHaversine} \title{ 'Haversine' great circle distance } \description{ The shortest distance between two points (i.e., the 'great-circle-distance' or 'as the crow flies'), according to the 'haversine method'. This method assumes a spherical earth, ignoring ellipsoidal effects. } \usage{distHaversine(p1, p2, r=6378137) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as above; or missing, in which case the sequential distance between the points in p1 is computed} \item{r}{radius of the earth; default = 6378137 m} } \details{ The Haversine ('half-versed-sine') formula was published by R.W. Sinnott in 1984, although it has been known for much longer. At that time computational precision was lower than today (15 digits precision). With current precision, the spherical law of cosines formula appears to give equally good results down to very small distances. If you want greater accuracy, you could use the \code{\link[geosphere]{distVincentyEllipsoid}} method. } \value{ Vector of distances in the same unit as \code{r} (default is meters) } \references{ Sinnott, R.W, 1984. Virtues of the Haversine. Sky and Telescope 68(2): 159 \url{https://www.movable-type.co.uk/scripts/latlong.html} \url{https://en.wikipedia.org/wiki/Great_circle_distance} } \author{ Chris Veness and Robert Hijmans } \seealso{ \code{\link[geosphere]{distGeo}, \link[geosphere]{distCosine}, \link[geosphere]{distVincentySphere}, \link[geosphere]{distVincentyEllipsoid}, \link{distMeeus}} } \examples{ distHaversine(c(0,0),c(90,90)) } \keyword{ spatial } geosphere/man/destPoint.Rd0000644000176200001440000000354214131145600015245 0ustar liggesusers\name{destPoint} \Rdversion{1.1} \alias{destPoint} \title{ Destination given bearing (direction) and distance } \description{ Given a start point, initial bearing (direction), and distance, this function computes the destination point travelling along a the shortest path on an ellipsoid (the geodesic). } \usage{ destPoint(p, b, d, a=6378137, f=1/298.257223563, ...) } \arguments{ \item{p}{Longitude and Latitude of point(s), in degrees. Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{b}{numeric. Bearing (direction) in degrees} \item{d}{numeric. Distance in meters} \item{a}{major (equatorial) radius of the ellipsoid. The default value is for WGS84 } \item{f}{ellipsoid flattening. The default value is for WGS84 } \item{...}{additional arguments. If an argument 'r' is supplied, this is taken as the radius of the earth (e.g. 6378137 m) and computations are for a sphere (great circle) instead of an ellipsoid (geodetic). This is for backwards compatibility only} } \note{ Direction changes continuously when travelling along a geodesic. Therefore, the final direction is not the same as the initial direction. You can compute the final direction with \code{\link{finalBearing}} (see examples, below) } \value{ A pair of coordinates (longitude/latitude) } \author{ This function calls GeographicLib code by C.F.F. Karney } \references{ C.F.F. Karney, 2013. Algorithms for geodesics, J. Geodesy 87: 43-55. \doi{10.1007/s00190-012-0578-z}. Addenda: \url{https://geographiclib.sourceforge.io/geod-addenda.html}. Also see \url{https://geographiclib.sourceforge.io/} } \examples{ p <- cbind(5,52) d <- destPoint(p,30,10000) d #final direction, when arriving at endpoint: finalBearing(d, p) } \keyword{ spatial } geosphere/man/refEllipsoids.Rd0000644000176200001440000000117513472155746016123 0ustar liggesusers\name{refEllipsoids} \alias{refEllipsoids} \title{Reference ellipsoids} \description{ This function returns a data.frame with parameters \code{a} (semi-major axis) and \code{1/f} (inverse flattening) for a set of reference ellipsoids. } \usage{ refEllipsoids() } \note{ To compute parameter \code{b} you can do } \value{ data.frame } \seealso{ \code{ \link[geosphere]{area}, \link[geosphere]{perimeter} } } \author{Robert J. Hijmans } \examples{ e <- refEllipsoids() e[e$code=='WE', ] #to compute semi-minor axis b: e$b <- e$a - e$a / e$invf } \keyword{methods} \keyword{spatial} geosphere/man/distVincentyEllipsoid.Rd0000644000176200001440000000701614131143521017624 0ustar liggesusers\name{distVincentyEllipsoid} \Rdversion{1.1} \alias{distVincentyEllipsoid} \title{ 'Vincenty' (ellipsoid) great circle distance } \description{ The shortest distance between two points (i.e., the 'great-circle-distance' or 'as the crow flies'), according to the 'Vincenty (ellipsoid)' method. This method uses an ellipsoid and the results are very accurate. The method is computationally more intensive than the other great-circled methods in this package. } \usage{ distVincentyEllipsoid(p1, p2, a=6378137, b=6356752.3142, f=1/298.257223563) } \arguments{ \item{p1}{longitude/latitude of point(s), in degrees 1; can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as above; or missing, in which case the sequential distance between the points in p1 is computed} \item{a}{Equatorial axis of ellipsoid} \item{b}{Polar axis of ellipsoid} \item{f}{Inverse flattening of ellipsoid} } \details{ The WGS84 ellipsoid is used by default. It is the best available global ellipsoid, but for some areas other ellipsoids could be preferable, or even necessary if you work with a printed map that refers to that ellipsoid. Here are parameters for some commonly used ellipsoids: \tabular{rllll}{ \tab \code{ ellipsoid } \tab \code{ a } \tab \code{ b } \tab \code{ f } \cr \tab \code{ WGS84 } \tab \code{ 6378137 } \tab \code{ 6356752.3142 } \tab \code{ 1/298.257223563 } \cr \tab \code{ GRS80 } \tab \code{ 6378137 } \tab \code{ 6356752.3141 } \tab \code{ 1/298.257222101 } \cr \tab \code{ GRS67 } \tab \code{ 6378160 } \tab \code{ 6356774.719 } \tab \code{ 1/298.25 } \cr \tab \code{ Airy 1830 } \tab \code{ 6377563.396 } \tab \code{ 6356256.909 } \tab \code{ 1/299.3249646 } \cr \tab \code{ Bessel 1841 } \tab \code{ 6377397.155 } \tab \code{ 6356078.965 } \tab \code{ 1/299.1528434 } \cr \tab \code{ Clarke 1880 } \tab \code{ 6378249.145 } \tab \code{ 6356514.86955 } \tab \code{ 1/293.465 } \cr \tab \code{ Clarke 1866 } \tab \code{ 6378206.4 } \tab \code{ 6356583.8 } \tab \code{ 1/294.9786982 } \cr \tab \code{ International 1924 } \tab \code{ 6378388 } \tab \code{ 6356911.946 } \tab \code{ 1/297 } \cr \tab \code{ Krasovsky 1940 } \tab \code{ 6378245 } \tab \code{ 6356863 } \tab \code{ 1/298.2997381 } \cr } \code{a} is the 'semi-major axis', and \code{b} is the 'semi-minor axis' of the ellipsoid. \code{f} is the flattening. Note that \code{f = (a-b)/a} more info: \url{https://en.wikipedia.org/wiki/Reference_ellipsoid} } \value{ Distance value in the same units as the ellipsoid (default is meters) } \references{ Vincenty, T. 1975. Direct and inverse solutions of geodesics on the ellipsoid with application of nested equations. Survey Review Vol. 23, No. 176, pp88-93. Available here: \url{https://www.movable-type.co.uk/scripts/latlong-vincenty.html} \url{https://en.wikipedia.org/wiki/Great_circle_distance} } \author{ Chris Veness and Robert Hijmans } \seealso{ \code{\link[geosphere]{distGeo}, \link{distVincentySphere}, \link{distHaversine}, \link{distCosine}, \link{distMeeus}} } \examples{ distVincentyEllipsoid(c(0,0),c(90,90)) # on a 'Clarke 1880' ellipsoid distVincentyEllipsoid(c(0,0),c(90,90), a=6378249.145, b=6356514.86955, f=1/293.465) } \keyword{ spatial } geosphere/man/distMeeus.Rd0000644000176200001440000000546614131143521015245 0ustar liggesusers\name{distMeeus} \Rdversion{1.1} \alias{distMeeus} \title{ 'Meeus' great circle distance } \description{ The shortest distance between two points on an ellipsoid (the 'geodetic'), according to the 'Meeus' method. \code{\link{distGeo}} should be more accurate. } \usage{ distMeeus(p1, p2, a=6378137, f=1/298.257223563) } \arguments{ \item{p1}{longitude/latitude of point(s), in degrees 1; can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as above; or missing, in which case the sequential distance between the points in p1 is computed} \item{a}{numeric. Major (equatorial) radius of the ellipsoid. The default value is for WGS84 } \item{f}{numeric. Ellipsoid flattening. The default value is for WGS84 } } \details{ Parameters from the WGS84 ellipsoid are used by default. It is the best available global ellipsoid, but for some areas other ellipsoids could be preferable, or even necessary if you work with a printed map that refers to that ellipsoid. Here are parameters for some commonly used ellipsoids: \tabular{rlll}{ \tab \code{ ellipsoid } \tab \code{ a } \tab \code{ f } \cr \tab \code{ WGS84 } \tab \code{ 6378137 } \tab \code{ 1/298.257223563 } \cr \tab \code{ GRS80 } \tab \code{ 6378137 } \tab \code{ 1/298.257222101 } \cr \tab \code{ GRS67 } \tab \code{ 6378160 } \tab \code{ 1/298.25 } \cr \tab \code{ Airy 1830 } \tab \code{ 6377563.396 } \tab \code{ 1/299.3249646 } \cr \tab \code{ Bessel 1841 } \tab \code{ 6377397.155 } \tab \code{ 1/299.1528434 } \cr \tab \code{ Clarke 1880 } \tab \code{ 6378249.145 } \tab \code{ 1/293.465 } \cr \tab \code{ Clarke 1866 } \tab \code{ 6378206.4 } \tab \code{ 1/294.9786982 } \cr \tab \code{ International 1924 } \tab \code{ 6378388 } \tab \code{ 1/297 } \cr \tab \code{ Krasovsky 1940 } \tab \code{ 6378245 } \tab \code{ 1/298.2997381 } \cr } more info: \url{https://en.wikipedia.org/wiki/Reference_ellipsoid} } \value{ Distance value in the same units as parameter \code{a} of the ellipsoid (default is meters) } \note{ This algorithm is also used in the \code{spDists} function in the sp package } \references{ Meeus, J., 1999 (2nd edition). Astronomical algoritms. Willman-Bell, 477p. } \author{ Robert Hijmans, based on a script by Stephen R. Schmitt } \seealso{ \code{\link[geosphere]{distGeo}, \link{distVincentyEllipsoid}, \link{distVincentySphere}, \link{distHaversine}, \link{distCosine}} } \examples{ distMeeus(c(0,0),c(90,90)) # on a 'Clarke 1880' ellipsoid distMeeus(c(0,0),c(90,90), a=6378249.145, f=1/293.465) } \keyword{ spatial } geosphere/man/antipode.Rd0000644000176200001440000000222714131143521015076 0ustar liggesusers\name{antipode} \Rdversion{1.1} \alias{antipode} \alias{antipodal} \title{ Antipodes } \description{ Compute an antipode, or check whether two points are antipodes. Antipodes are places on Earth that are diametrically opposite to one another; and could be connected by a straight line through the centre of the Earth. Antipodal points are connected by an infinite number of great circles (e.g. the meridians connecting the poles), and can therefore not be used in some great circle based computations. } \usage{ antipode(p) antipodal(p1, p2, tol=1e-9) } \arguments{ \item{p}{Longitude/latitude of a single point, in degrees; can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p1}{as above} \item{p2}{as above} \item{tol}{tolerance for equality} } \value{ antipodal points or a logical value (\code{TRUE} if antipodal) } \references{ \url{https://en.wikipedia.org/wiki/Antipodes} } \author{ Robert Hijmans } \examples{ antipode(rbind(c(5,52), c(-120,37), c(-60,0), c(0,70))) antipodal(c(0,0), c(180,0)) } \keyword{ spatial } geosphere/man/greatCircle.Rd0000644000176200001440000000163114131210620015510 0ustar liggesusers\name{greatCircle} \Rdversion{1.1} \alias{greatCircle} \title{ Great circle } \description{ Get points on a great circle as defined by the shortest distance between two specified points } \usage{ greatCircle(p1, p2, n=360, sp=FALSE) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as above} \item{n}{The requested number of points on the Great Circle} \item{sp}{Logical. Return a SpatialLines object?} } \value{ A matrix of points, or a list of such matrices (e.g., if multiple bearings are supplied) } \references{ \url{https://www.edwilliams.org/avform147.htm#Int} } \author{ Robert Hijmans, based on a formula provided by Ed Williams } \examples{ greatCircle(c(5,52), c(-120,37), n=36) } \keyword{ spatial } geosphere/man/data.Rd0000644000176200001440000000053613472155746014230 0ustar liggesusers\name{wrld} \alias{wrld} \alias{merc} \docType{data} \title{World countries} \description{ world coastline and country outlines in longitude/latitude (wrld) and in Mercator projection (merc). } \usage{ data(wrld) data(merc) } \source{ Derived from the wrld_simpl data set in package maptools } \keyword{datasets} geosphere/man/geomean.Rd0000644000176200001440000000141313472155746014725 0ustar liggesusers\name{geomean} \docType{methods} \alias{geomean} \title{ Mean location of sperhical coordinates } \description{ mean location for spherical (longitude/latitude) coordinates that deals with the angularity. I.e., the mean of longitudes -179 and 178 is 179.5 } \usage{ geomean(xy, w) } \arguments{ \item{xy}{matrix with two columns (longitude/latitude), or a SpatialPoints or SpatialPolygons object with a longitude/latitude CRS} \item{w}{weights (vector of numeric values, with a length that is equal to the number of spatial features in \code{x}} } \value{ Ccoordinate pair (numeric) } \examples{ xy <- cbind(x=c(-179,179, 177), y=c(12,14,16)) xy geomean(xy) } \author{Robert J. Hijmans} \keyword{methods} \keyword{spatial} geosphere/man/daylength.Rd0000644000176200001440000000172114253023226015254 0ustar liggesusers\name{daylength} \alias{daylength} \title{ Daylength } \description{ Compute daylength (photoperiod) for a latitude and date. } \usage{ daylength(lat, doy) } \arguments{ \item{lat}{latitude, in degrees. I.e. between -90.0 and 90.0 } \item{doy}{integer, day of the year (1..365) for common (non-leap) years; or an object of class Date; or a character that can be coerced into a date, using 'yyyy-mm-dd' format, e.g. '1982-11-23' } } \value{ Daylength in hours } \references{ Forsythe, William C., Edward J. Rykiel Jr., Randal S. Stahl, Hsin-i Wu and Robert M. Schoolfield, 1995. A model comparison for daylength as a function of latitude and day of the year. Ecological Modeling 80:87-95. } \author{ Robert J. Hijmans } \examples{ daylength(-25, '2010-10-10') daylength(45, 1:365) # average monthly daylength dl <- daylength(45, 1:365) tapply(dl, rep(1:12, c(31,28,31,30,31,30,31,31,30,31,30,31)), mean) } \keyword{ spatial } geosphere/man/geodesic.Rd0000644000176200001440000000663114131145601015061 0ustar liggesusers\name{geodesic} \Rdversion{1.1} \alias{geodesic} \alias{geodesic_inverse} \title{ geodesic and inverse geodesic problem } \description{ Highly accurate estimate of the 'geodesic problem' (find location and azimuth at arrival when departing from a location, given an direction (azimuth) at departure and distance) and the 'inverse geodesic problem' (find the distance between two points and the azimuth of departure and arrival for the shortest path. Computations are for an ellipsoid (default is WGS84 ellipsoid). This is a direct implementation of the the GeographicLib code by C.F.F. Karney that is also used in several other functions in this package (for example, in \code{\link{distGeo}} and \code{\link{areaPolygon}}). } \usage{ geodesic(p, azi, d, a=6378137, f=1/298.257223563, ...) geodesic_inverse(p1, p2, a=6378137, f=1/298.257223563, ...) } \arguments{ \item{p}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first column is longitude, second column is latitude) or a SpatialPoints* object} \item{p1}{as above} \item{p2}{as above} \item{azi}{numeric. Azimuth of departure in degrees} \item{d}{numeric. Distance in meters} \item{a}{numeric. Major (equatorial) radius of the ellipsoid. The default value is for WGS84 } \item{f}{numeric. Ellipsoid flattening. The default value is for WGS84 } \item{...}{additional arguments (none implemented)} } \value{ Three column matrix with columns 'longitude', 'latitude', 'azimuth' (geodesic); or 'distance' (in meters), 'azimuth1' (of departure), 'azimuth2' (of arrival) (geodesic_inverse) } \details{ Parameters from the WGS84 ellipsoid are used by default. It is the best available global ellipsoid, but for some areas other ellipsoids could be preferable, or even necessary if you work with a printed map that refers to that ellipsoid. Here are parameters for some commonly used ellipsoids. \tabular{rlll}{ \tab \code{ ellipsoid } \tab \code{ a } \tab \code{ f } \cr \tab \code{ WGS84 } \tab \code{ 6378137 } \tab \code{ 1/298.257223563 } \cr \tab \code{ GRS80 } \tab \code{ 6378137 } \tab \code{ 1/298.257222101 } \cr \tab \code{ GRS67 } \tab \code{ 6378160 } \tab \code{ 1/298.25 } \cr \tab \code{ Airy 1830 } \tab \code{ 6377563.396 } \tab \code{ 1/299.3249646 } \cr \tab \code{ Bessel 1841 } \tab \code{ 6377397.155 } \tab \code{ 1/299.1528434 } \cr \tab \code{ Clarke 1880 } \tab \code{ 6378249.145 } \tab \code{ 1/293.465 } \cr \tab \code{ Clarke 1866 } \tab \code{ 6378206.4 } \tab \code{ 1/294.9786982 } \cr \tab \code{ International 1924 } \tab \code{ 6378388 } \tab \code{ 1/297 } \cr \tab \code{ Krasovsky 1940 } \tab \code{ 6378245 } \tab \code{ 1/298.2997381 } \cr } more info: \url{https://en.wikipedia.org/wiki/Reference_ellipsoid} } \author{ This function calls GeographicLib code by C.F.F. Karney } \references{ C.F.F. Karney, 2013. Algorithms for geodesics, J. Geodesy 87: 43-55. \doi{10.1007/s00190-012-0578-z}. Addenda: \url{https://geographiclib.sourceforge.io/geod-addenda.html}. Also see \url{https://geographiclib.sourceforge.io/} } \seealso{ \code{\link{distGeo}} } \examples{ geodesic(cbind(0,0), 30, 1000000) geodesic_inverse(cbind(0,0), cbind(90,90)) } \keyword{ spatial } geosphere/man/mercator.Rd0000644000176200001440000000151213472155746015126 0ustar liggesusers\name{mercator} \Rdversion{1.1} \alias{mercator} \title{ Mercator projection } \description{ Transform longitude/latiude points to the Mercator projection. The main purpose of this function is to compute centroids, and to illustrate rhumb lines in the vignette. } \usage{ mercator(p, inverse=FALSE, r=6378137) } \arguments{ \item{p}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{inverse}{Logical. If \code{TRUE}, do the inverse projection (from Mercator to longitude/latitude} \item{r}{Numeric. Radius of the earth; default = 6378137 m} } \value{ matrix } \author{ Robert Hijmans } \examples{ a = mercator(c(5,52)) a mercator(a, inverse=TRUE) } \keyword{ spatial } geosphere/man/intermediate.Rd0000644000176200001440000000263214131210620015740 0ustar liggesusers\name{intermediate} \Rdversion{1.1} \alias{gcIntermediate} \title{ Intermediate points on a great circle (sphere) } \description{ Get intermediate points (way points) between the two locations with longitude/latitude coordinates. gcIntermediate is based on a spherical model of the earth and internally uses \code{\link{distCosine}}. } \usage{ gcIntermediate(p1, p2, n=50, breakAtDateLine=FALSE, addStartEnd=FALSE, sp=FALSE, sepNA) } \arguments{ \item{p1}{longitude/latitude of a single point, in degrees. This can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as for \code{p1}} \item{n}{integer. The desired number of intermediate points} \item{breakAtDateLine}{logical. Return two matrices if the dateline is crossed?} \item{addStartEnd}{logical. Add p1 and p2 to the result?} \item{sp}{logical. Return a SpatialLines object?} \item{sepNA}{logical. Rather than as a list, return the values as a two column matrix with lines seperated by a row of NA values? (for use in 'plot')} } \value{ matrix or list with intermediate points } \references{ \url{https://www.edwilliams.org/avform147.htm#Intermediate} } \author{ Robert Hijmans based on code by Ed Williams (great circle) } \examples{ gcIntermediate(c(5,52), c(-120,37), n=6, addStartEnd=TRUE) } \keyword{ spatial } geosphere/man/randomCoordinates.Rd0000644000176200001440000000211314131210415016735 0ustar liggesusers\name{randomCoordinates} \Rdversion{1.1} \alias{randomCoordinates} \alias{regularCoordinates} \title{ Random or regularly distributed coordinates on the globe } \description{ randomCoordinates returns a 'uniform random sample' in the sense that the probability that a point is drawn from any region is equal to the area of that region divided by the area of the entire sphere. This would not happen if you took a random uniform sample of longitude and latitude, as the sample would be biased towards the poles. regularCoordiaates returns a set of coordinates that are regularly distributed on the globe. } \usage{ randomCoordinates(n) regularCoordinates(N) } \arguments{ \item{n}{Sample size (number of points (coordinate pairs)) } \item{N}{Number of 'parts' in which the earth is subdived ) } } \value{ Matrix of lon/lat coordiantes } \author{ Robert Hijmans, based on code by Nils Haeck (regularCoordinates) and on suggstions by Michael Orion (randomCoordinates) } \examples{ randomCoordinates(3) regularCoordinates(1) } \keyword{ spatial } geosphere/man/span.Rd0000644000176200001440000000322513472155746014256 0ustar liggesusers\name{span} \alias{span} \alias{span,SpatialPolygons-method} \alias{span,matrix-method} \title{Span of polygons} \description{ Compute the approximate surface span of polygons in longitude and latitude direction. Span is computed by rasterizing the polygons; and precision increases with the number of 'scan lines'. You can either use a fixed number of scan lines for each polygon, or a fixed band-width. } \usage{ span(x, ...) } \arguments{ \item{x}{a SpatialPolygons* object or a 2-column matrix (longitude/latitude)} \item{...}{Additional arguments, see Details} } \details{ The following additional arguments can be passed, to replace default values for this function \tabular{rll}{ \tab \code{nbands} \tab Character. Method to determine the number of bands to 'scan' the polygon. Either 'fixed' or 'variable' \cr \tab \code{n} \tab Integer >= 1. If \code{nbands='fixed'}, how many bands should be used \cr \tab \code{res} \tab Numeric. If \code{nbands='variable'}, what should the bandwidth be (in degrees)? \cr \tab \code{fun} \tab Logical. A function such as mean or min. Mean computes the average span \cr \tab \code{...} \tab further additional arguments passed to distGeo\cr } } \value{ A list, or a matrix if a function \code{fun} is specified. Values are in the units of \code{r} (default is meter) } \author{Robert J. Hijmans } \examples{ pol <- rbind(c(-180,-20), c(-160,5), c(-60, 0), c(-160,-60), c(-180,-20)) plot(pol) lines(pol) # lon and lat span in m span(pol, fun=max) x <- span(pol) max(x$latspan) mean(x$latspan) plot(x$longitude, x$lonspan) } \keyword{methods} \keyword{spatial} geosphere/man/centroid.Rd0000644000176200001440000000255213472325401015111 0ustar liggesusers\name{centroid} \alias{centroid} \alias{centroid,matrix-method} \alias{centroid,data.frame-method} \alias{centroid,SpatialPolygons-method} \title{Centroid of spherical polygons} \description{ Compute the centroid of longitude/latitude polygons. Unlike other functions in this package, there is no spherical trigonometry involved in the implementation of this function. Instead, the function projects the polygon to the (conformal) Mercator coordinate reference system, computes the centroid, and then inversely projects it to longitude and latitude. This approach fails for polygons that include one of the poles (and is rather biased for anything close to the poles). The function should work for polygons that cross the -180/180 meridian (date line). } \usage{ centroid(x, ...) } \arguments{ \item{x}{SpatialPolygons* object, or a 2-column matrix or data.frame reprenting a single polgyon (longitude/latitude)} \item{...}{Additional arguments. None implemented} } \note{ For multi-part polygons, the centroid of the largest part is returned. } \value{ A matrix (longitude/latitude) } \seealso{ \code{ \link[geosphere]{area}, \link[geosphere]{perimeter} } } \author{Robert J. Hijmans } \examples{ pol <- rbind(c(-180,-20), c(-160,5), c(-60, 0), c(-160,-60), c(-180,-20)) centroid(pol) } \keyword{methods} \keyword{spatial} geosphere/man/midPoint.Rd0000644000176200001440000000137013472155746015077 0ustar liggesusers\name{midPoint} \Rdversion{1.1} \alias{midPoint} \title{Mid-point} \description{ Find the point half-way between two points along an ellipsoid } \usage{ midPoint(p1, p2, a=6378137, f = 1/298.257223563) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{As above} \item{a}{major (equatorial) radius of the ellipsoid} \item{f}{ellipsoid flattening. The default value is for WGS84 } } \value{ matrix with coordinate pairs } \author{ Elias Pipping and Robert Hijmans } \examples{ midPoint(c(0,0),c(90,90)) midPoint(c(0,0),c(90,90), f=0) } \keyword{spatial} geosphere/man/alongTrackDistance.Rd0000644000176200001440000000171413472155746017056 0ustar liggesusers\name{alongTrackDistance} \Rdversion{1.1} \alias{alongTrackDistance} \title{ Along Track Distance } \description{ The "along track distance" is the distance from the start point (p1) to the closest point on the path to a third point (p3), following a great circle path defined by points p1 and p2. See \code{\link{dist2gc}} for the "cross track distance" } \usage{ alongTrackDistance(p1, p2, p3, r=6378137) } \arguments{ \item{p1}{longitude/latitude of point(s). Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object} \item{p2}{as above} \item{p3}{as above} \item{r}{radius of the earth; default = 6378137m} } \value{ A distance in units of r (default is meters) } \author{ Ed Williams and Robert Hijmans } \seealso{ \code{ \link[geosphere]{dist2gc} } } \examples{ alongTrackDistance(c(0,0),c(60,60),c(50,40)) } \keyword{ spatial } geosphere/DESCRIPTION0000644000176200001440000000172214335012510013735 0ustar liggesusersPackage: geosphere Type: Package Title: Spherical Trigonometry Version: 1.5-18 Date: 2022-11-13 LinkingTo: Rcpp Imports: Rcpp, sp Depends: R (>= 3.0.0) Suggests: methods, raster Authors@R: c( person("Robert J.", "Hijmans", role = c("cre", "aut"), email = "r.hijmans@gmail.com"), person("Charles", "Karney", role = "ctb", comment="GeographicLib"), person("Ed", "Williams", role = "ctb"), person("Chris", "Vennes", role = "ctb")) Description: Spherical trigonometry for geographic applications. That is, compute distances and related measures for angular (longitude/latitude) locations. BugReports: https://github.com/rspatial/geosphere/issues/ License: GPL (>= 3) LazyLoad: yes NeedsCompilation: yes Packaged: 2022-11-13 17:35:52 UTC; rhijm Author: Robert J. Hijmans [cre, aut], Charles Karney [ctb] (GeographicLib), Ed Williams [ctb], Chris Vennes [ctb] Maintainer: Robert J. Hijmans Repository: CRAN Date/Publication: 2022-11-15 22:40:08 UTC geosphere/build/0000755000176200001440000000000014334225370013335 5ustar liggesusersgeosphere/build/vignette.rds0000644000176200001440000000033414334225370015674 0ustar liggesusersuQ0 Аx) b 3ěO.Skf!RBmLm}nxz)Ȳ@ApQ\oV2E:it'GgE`ߥ͡D+D and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #include #include "Rhumb.h" #if defined(_MSC_VER) // Squelch warnings about enum-float expressions # pragma warning (disable: 5055) #endif namespace GeographicLib { using namespace std; Rhumb::Rhumb(real a, real f, bool exact) : _ell(a, f) , _exact(exact) , _c2(_ell.Area() / (2 * Math::td)) { // Generated by Maxima on 2015-05-15 08:24:04-04:00 #if GEOGRAPHICLIB_RHUMBAREA_ORDER == 4 static const real coeff[] = { // R[0]/n^0, polynomial in n of order 4 691, 7860, -20160, 18900, 0, 56700, // R[1]/n^1, polynomial in n of order 3 1772, -5340, 6930, -4725, 14175, // R[2]/n^2, polynomial in n of order 2 -1747, 1590, -630, 4725, // R[3]/n^3, polynomial in n of order 1 104, -31, 315, // R[4]/n^4, polynomial in n of order 0 -41, 420, }; // count = 20 #elif GEOGRAPHICLIB_RHUMBAREA_ORDER == 5 static const real coeff[] = { // R[0]/n^0, polynomial in n of order 5 -79036, 22803, 259380, -665280, 623700, 0, 1871100, // R[1]/n^1, polynomial in n of order 4 41662, 58476, -176220, 228690, -155925, 467775, // R[2]/n^2, polynomial in n of order 3 18118, -57651, 52470, -20790, 155925, // R[3]/n^3, polynomial in n of order 2 -23011, 17160, -5115, 51975, // R[4]/n^4, polynomial in n of order 1 5480, -1353, 13860, // R[5]/n^5, polynomial in n of order 0 -668, 5775, }; // count = 27 #elif GEOGRAPHICLIB_RHUMBAREA_ORDER == 6 static const real coeff[] = { // R[0]/n^0, polynomial in n of order 6 128346268, -107884140, 31126095, 354053700, -908107200, 851350500, 0, 2554051500LL, // R[1]/n^1, polynomial in n of order 5 -114456994, 56868630, 79819740, -240540300, 312161850, -212837625, 638512875, // R[2]/n^2, polynomial in n of order 4 51304574, 24731070, -78693615, 71621550, -28378350, 212837625, // R[3]/n^3, polynomial in n of order 3 1554472, -6282003, 4684680, -1396395, 14189175, // R[4]/n^4, polynomial in n of order 2 -4913956, 3205800, -791505, 8108100, // R[5]/n^5, polynomial in n of order 1 1092376, -234468, 2027025, // R[6]/n^6, polynomial in n of order 0 -313076, 2027025, }; // count = 35 #elif GEOGRAPHICLIB_RHUMBAREA_ORDER == 7 static const real coeff[] = { // R[0]/n^0, polynomial in n of order 7 -317195588, 385038804, -323652420, 93378285, 1062161100, -2724321600LL, 2554051500LL, 0, 7662154500LL, // R[1]/n^1, polynomial in n of order 6 258618446, -343370982, 170605890, 239459220, -721620900, 936485550, -638512875, 1915538625, // R[2]/n^2, polynomial in n of order 5 -248174686, 153913722, 74193210, -236080845, 214864650, -85135050, 638512875, // R[3]/n^3, polynomial in n of order 4 114450437, 23317080, -94230045, 70270200, -20945925, 212837625, // R[4]/n^4, polynomial in n of order 3 15445736, -103193076, 67321800, -16621605, 170270100, // R[5]/n^5, polynomial in n of order 2 -27766753, 16385640, -3517020, 30405375, // R[6]/n^6, polynomial in n of order 1 4892722, -939228, 6081075, // R[7]/n^7, polynomial in n of order 0 -3189007, 14189175, }; // count = 44 #elif GEOGRAPHICLIB_RHUMBAREA_ORDER == 8 static const real coeff[] = { // R[0]/n^0, polynomial in n of order 8 71374704821LL, -161769749880LL, 196369790040LL, -165062734200LL, 47622925350LL, 541702161000LL, -1389404016000LL, 1302566265000LL, 0, 3907698795000LL, // R[1]/n^1, polynomial in n of order 7 -13691187484LL, 65947703730LL, -87559600410LL, 43504501950LL, 61062101100LL, -184013329500LL, 238803815250LL, -162820783125LL, 488462349375LL, // R[2]/n^2, polynomial in n of order 6 30802104839LL, -63284544930LL, 39247999110LL, 18919268550LL, -60200615475LL, 54790485750LL, -21709437750LL, 162820783125LL, // R[3]/n^3, polynomial in n of order 5 -8934064508LL, 5836972287LL, 1189171080, -4805732295LL, 3583780200LL, -1068242175, 10854718875LL, // R[4]/n^4, polynomial in n of order 4 50072287748LL, 3938662680LL, -26314234380LL, 17167059000LL, -4238509275LL, 43418875500LL, // R[5]/n^5, polynomial in n of order 3 359094172, -9912730821LL, 5849673480LL, -1255576140, 10854718875LL, // R[6]/n^6, polynomial in n of order 2 -16053944387LL, 8733508770LL, -1676521980, 10854718875LL, // R[7]/n^7, polynomial in n of order 1 930092876, -162639357, 723647925, // R[8]/n^8, polynomial in n of order 0 -673429061, 1929727800, }; // count = 54 #else #error "Bad value for GEOGRAPHICLIB_RHUMBAREA_ORDER" #endif static_assert(sizeof(coeff) / sizeof(real) == ((maxpow_ + 1) * (maxpow_ + 4))/2, "Coefficient array size mismatch for Rhumb"); real d = 1; int o = 0; for (int l = 0; l <= maxpow_; ++l) { int m = maxpow_ - l; // R[0] is just an integration constant so it cancels when evaluating a // definite integral. So don't bother computing it. It won't be used // when invoking SinCosSeries. if (l) _rR[l] = d * Math::polyval(m, coeff + o, _ell._n) / coeff[o + m + 1]; o += m + 2; d *= _ell._n; } // Post condition: o == sizeof(alpcoeff) / sizeof(real) } const Rhumb& Rhumb::WGS84() { static const Rhumb wgs84(Constants::WGS84_a(), Constants::WGS84_f(), false); return wgs84; } void Rhumb::GenInverse(real lat1, real lon1, real lat2, real lon2, unsigned outmask, real& s12, real& azi12, real& S12) const { real lon12 = Math::AngDiff(lon1, lon2), psi1 = _ell.IsometricLatitude(lat1), psi2 = _ell.IsometricLatitude(lat2), psi12 = psi2 - psi1, h = hypot(lon12, psi12); if (outmask & AZIMUTH) azi12 = Math::atan2d(lon12, psi12); if (outmask & DISTANCE) { real dmudpsi = DIsometricToRectifying(psi2, psi1); s12 = h * dmudpsi * _ell.QuarterMeridian() / Math::qd; } if (outmask & AREA) S12 = _c2 * lon12 * MeanSinXi(psi2 * Math::degree(), psi1 * Math::degree()); } RhumbLine Rhumb::Line(real lat1, real lon1, real azi12) const { return RhumbLine(*this, lat1, lon1, azi12); } void Rhumb::GenDirect(real lat1, real lon1, real azi12, real s12, unsigned outmask, real& lat2, real& lon2, real& S12) const { Line(lat1, lon1, azi12).GenPosition(s12, outmask, lat2, lon2, S12); } Math::real Rhumb::DE(real x, real y) const { const EllipticFunction& ei = _ell._ell; real d = x - y; if (x * y <= 0) return d != 0 ? (ei.E(x) - ei.E(y)) / d : 1; // See DLMF: Eqs (19.11.2) and (19.11.4) letting // theta -> x, phi -> -y, psi -> z // // (E(x) - E(y)) / d = E(z)/d - k2 * sin(x) * sin(y) * sin(z)/d // // tan(z/2) = (sin(x)*Delta(y) - sin(y)*Delta(x)) / (cos(x) + cos(y)) // = d * Dsin(x,y) * (sin(x) + sin(y))/(cos(x) + cos(y)) / // (sin(x)*Delta(y) + sin(y)*Delta(x)) // = t = d * Dt // sin(z) = 2*t/(1+t^2); cos(z) = (1-t^2)/(1+t^2) // Alt (this only works for |z| <= pi/2 -- however, this conditions holds // if x*y > 0): // sin(z) = d * Dsin(x,y) * (sin(x) + sin(y))/ // (sin(x)*cos(y)*Delta(y) + sin(y)*cos(x)*Delta(x)) // cos(z) = sqrt((1-sin(z))*(1+sin(z))) real sx = sin(x), sy = sin(y), cx = cos(x), cy = cos(y); real Dt = Dsin(x, y) * (sx + sy) / ((cx + cy) * (sx * ei.Delta(sy, cy) + sy * ei.Delta(sx, cx))), t = d * Dt, Dsz = 2 * Dt / (1 + t*t), sz = d * Dsz, cz = (1 - t) * (1 + t) / (1 + t*t); return ((sz != 0 ? ei.E(sz, cz, ei.Delta(sz, cz)) / sz : 1) - ei.k2() * sx * sy) * Dsz; } Math::real Rhumb::DRectifying(real latx, real laty) const { real tbetx = _ell._f1 * Math::tand(latx), tbety = _ell._f1 * Math::tand(laty); return (Math::pi()/2) * _ell._b * _ell._f1 * DE(atan(tbetx), atan(tbety)) * Dtan(latx, laty) * Datan(tbetx, tbety) / _ell.QuarterMeridian(); } Math::real Rhumb::DIsometric(real latx, real laty) const { real phix = latx * Math::degree(), tx = Math::tand(latx), phiy = laty * Math::degree(), ty = Math::tand(laty); return Dasinh(tx, ty) * Dtan(latx, laty) - Deatanhe(sin(phix), sin(phiy)) * Dsin(phix, phiy); } Math::real Rhumb::SinCosSeries(bool sinp, real x, real y, const real c[], int n) { // N.B. n >= 0 and c[] has n+1 elements 0..n, of which c[0] is ignored. // // Use Clenshaw summation to evaluate // m = (g(x) + g(y)) / 2 -- mean value // s = (g(x) - g(y)) / (x - y) -- average slope // where // g(x) = sum(c[j]*SC(2*j*x), j = 1..n) // SC = sinp ? sin : cos // CS = sinp ? cos : sin // // This function returns only s; m is discarded. // // Write // t = [m; s] // t = sum(c[j] * f[j](x,y), j = 1..n) // where // f[j](x,y) = [ (SC(2*j*x)+SC(2*j*y))/2 ] // [ (SC(2*j*x)-SC(2*j*y))/d ] // // = [ cos(j*d)*SC(j*p) ] // [ +/-(2/d)*sin(j*d)*CS(j*p) ] // (+/- = sinp ? + : -) and // p = x+y, d = x-y // // f[j+1](x,y) = A * f[j](x,y) - f[j-1](x,y) // // A = [ 2*cos(p)*cos(d) -sin(p)*sin(d)*d] // [ -4*sin(p)*sin(d)/d 2*cos(p)*cos(d) ] // // Let b[n+1] = b[n+2] = [0 0; 0 0] // b[j] = A * b[j+1] - b[j+2] + c[j] * I for j = n..1 // t = (c[0] * I - b[2]) * f[0](x,y) + b[1] * f[1](x,y) // c[0] is not accessed for s = t[2] real p = x + y, d = x - y, cp = cos(p), cd = cos(d), sp = sin(p), sd = d != 0 ? sin(d)/d : 1, m = 2 * cp * cd, s = sp * sd; // 2x2 matrices stored in row-major order const real a[4] = {m, -s * d * d, -4 * s, m}; real ba[4] = {0, 0, 0, 0}; real bb[4] = {0, 0, 0, 0}; real* b1 = ba; real* b2 = bb; if (n > 0) b1[0] = b1[3] = c[n]; for (int j = n - 1; j > 0; --j) { // j = n-1 .. 1 swap(b1, b2); // b1 = A * b2 - b1 + c[j] * I b1[0] = a[0] * b2[0] + a[1] * b2[2] - b1[0] + c[j]; b1[1] = a[0] * b2[1] + a[1] * b2[3] - b1[1]; b1[2] = a[2] * b2[0] + a[3] * b2[2] - b1[2]; b1[3] = a[2] * b2[1] + a[3] * b2[3] - b1[3] + c[j]; } // Here are the full expressions for m and s // m = (c[0] - b2[0]) * f01 - b2[1] * f02 + b1[0] * f11 + b1[1] * f12; // s = - b2[2] * f01 + (c[0] - b2[3]) * f02 + b1[2] * f11 + b1[3] * f12; if (sinp) { // real f01 = 0, f02 = 0; real f11 = cd * sp, f12 = 2 * sd * cp; // m = b1[0] * f11 + b1[1] * f12; s = b1[2] * f11 + b1[3] * f12; } else { // real f01 = 1, f02 = 0; real f11 = cd * cp, f12 = - 2 * sd * sp; // m = c[0] - b2[0] + b1[0] * f11 + b1[1] * f12; s = - b2[2] + b1[2] * f11 + b1[3] * f12; } return s; } Math::real Rhumb::DConformalToRectifying(real chix, real chiy) const { return 1 + SinCosSeries(true, chix, chiy, _ell.ConformalToRectifyingCoeffs(), tm_maxord); } Math::real Rhumb::DRectifyingToConformal(real mux, real muy) const { return 1 - SinCosSeries(true, mux, muy, _ell.RectifyingToConformalCoeffs(), tm_maxord); } Math::real Rhumb::DIsometricToRectifying(real psix, real psiy) const { if (_exact) { real latx = _ell.InverseIsometricLatitude(psix), laty = _ell.InverseIsometricLatitude(psiy); return DRectifying(latx, laty) / DIsometric(latx, laty); } else { psix *= Math::degree(); psiy *= Math::degree(); return DConformalToRectifying(gd(psix), gd(psiy)) * Dgd(psix, psiy); } } Math::real Rhumb::DRectifyingToIsometric(real mux, real muy) const { real latx = _ell.InverseRectifyingLatitude(mux/Math::degree()), laty = _ell.InverseRectifyingLatitude(muy/Math::degree()); return _exact ? DIsometric(latx, laty) / DRectifying(latx, laty) : Dgdinv(Math::taupf(Math::tand(latx), _ell._es), Math::taupf(Math::tand(laty), _ell._es)) * DRectifyingToConformal(mux, muy); } Math::real Rhumb::MeanSinXi(real psix, real psiy) const { return Dlog(cosh(psix), cosh(psiy)) * Dcosh(psix, psiy) + SinCosSeries(false, gd(psix), gd(psiy), _rR, maxpow_) * Dgd(psix, psiy); } RhumbLine::RhumbLine(const Rhumb& rh, real lat1, real lon1, real azi12) : _rh(rh) , _lat1(Math::LatFix(lat1)) , _lon1(lon1) , _azi12(Math::AngNormalize(azi12)) { real alp12 = _azi12 * Math::degree(); _salp = _azi12 == -Math::hd ? 0 : sin(alp12); _calp = fabs(_azi12) == Math::qd ? 0 : cos(alp12); _mu1 = _rh._ell.RectifyingLatitude(lat1); _psi1 = _rh._ell.IsometricLatitude(lat1); _r1 = _rh._ell.CircleRadius(lat1); } void RhumbLine::GenPosition(real s12, unsigned outmask, real& lat2, real& lon2, real& S12) const { real mu12 = s12 * _calp * Math::qd / _rh._ell.QuarterMeridian(), mu2 = _mu1 + mu12; real psi2, lat2x, lon2x; if (fabs(mu2) <= Math::qd) { if (_calp != 0) { lat2x = _rh._ell.InverseRectifyingLatitude(mu2); real psi12 = _rh.DRectifyingToIsometric( mu2 * Math::degree(), _mu1 * Math::degree()) * mu12; lon2x = _salp * psi12 / _calp; psi2 = _psi1 + psi12; } else { lat2x = _lat1; lon2x = _salp * s12 / (_r1 * Math::degree()); psi2 = _psi1; } if (outmask & AREA) S12 = _rh._c2 * lon2x * _rh.MeanSinXi(_psi1 * Math::degree(), psi2 * Math::degree()); lon2x = outmask & LONG_UNROLL ? _lon1 + lon2x : Math::AngNormalize(Math::AngNormalize(_lon1) + lon2x); } else { // Reduce to the interval [-180, 180) mu2 = Math::AngNormalize(mu2); // Deal with points on the anti-meridian if (fabs(mu2) > Math::qd) mu2 = Math::AngNormalize(Math::hd - mu2); lat2x = _rh._ell.InverseRectifyingLatitude(mu2); lon2x = Math::NaN(); if (outmask & AREA) S12 = Math::NaN(); } if (outmask & LATITUDE) lat2 = lat2x; if (outmask & LONGITUDE) lon2 = lon2x; } } // namespace GeographicLib geosphere/src/DST.h0000644000176200001440000001355114323400722013627 0ustar liggesusers/** * \file DST.hpp * \brief Header for GeographicLib::DST class * * Copyright (c) Charles Karney (2022) and licensed under * the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_DST_HPP) #define GEOGRAPHICLIB_DST_HPP 1 #include "Constants.h" #include #include template class kissfft; namespace GeographicLib { /** * \brief Discrete sine transforms * * This decomposes periodic functions \f$ f(\sigma) \f$ (period \f$ 2\pi \f$) * which are odd about \f$ \sigma = 0 \f$ and even about \f$ \sigma = \frac12 * \pi \f$ into a Fourier series * \f[ * f(\sigma) = \sum_{l=0}^\infty F_l \sin\bigl((2l+1)\sigma\bigr). * \f] * * The first \f$ N \f$ components of \f$ F_l \f$, for \f$0 \le l < N\f$ may * be approximated by * \f[ * F_l = \frac2N \sum_{j=1}^{N} * p_j f(\sigma_j) \sin\bigl((2l+1)\sigma_j\bigr), * \f] * where \f$ \sigma_j = j\pi/(2N) \f$ and \f$ p_j = \frac12 \f$ for \f$ j = N * \f$ and \f$ 1 \f$ otherwise. \f$ F_l \f$ is a discrete sine transform of * type DST-III and may be conveniently computed using the fast Fourier * transform, FFT; this is implemented with the DST::transform method. * * Having computed \f$ F_l \f$ based on \f$ N \f$ evaluations of \f$ * f(\sigma) \f$ at \f$ \sigma_j = j\pi/(2N) \f$, it is possible to * refine these transform values and add another \f$ N \f$ coefficients by * evaluating \f$ f(\sigma) \f$ at \f$ (j-\frac12)\pi/(2N) \f$; this is * implemented with the DST::refine method. * * Here we compute FFTs using the kissfft package * https://github.com/mborgerding/kissfft by Mark Borgerding. * * Example of use: * \include example-DST.cpp * * \note The FFTW package https://www.fftw.org/ can also be used. However * this is a more complicated dependency, its CMake support is broken, and it * doesn't work with mpreals (GEOGRAPHICLIB_PRECISION = 5). **********************************************************************/ class DST { private: typedef Math::real real; int _N; typedef kissfft fft_t; std::shared_ptr _fft; // Implement DST-III (centerp = false) or DST-IV (centerp = true) void fft_transform(real data[], real F[], bool centerp) const; // Add another N terms to F void fft_transform2(real data[], real F[]) const; public: /** * Constructor specifying the number of points to use. * @param[in] N the number of points to use. **********************************************************************/ GEOGRAPHICLIB_EXPORT DST(int N = 0); /** * Reset the given number of points. * @param[in] N the number of points to use. **********************************************************************/ void GEOGRAPHICLIB_EXPORT reset(int N); /** * Return the number of points. * @return the number of points to use. **********************************************************************/ int N() const { return _N; } /** * Determine first \e N terms in the Fourier series * @param[in] f the function used for evaluation. * @param[out] F the first \e N coefficients of the Fourier series. * * The evaluates \f$ f(\sigma) \f$ at \f$ \sigma = (j + 1) \pi / (2 N) \f$ * for integer \f$ j \in [0, N) \f$. \e F should be an array of length at * least \e N. **********************************************************************/ void GEOGRAPHICLIB_EXPORT transform(std::function f, real F[]) const; /** * Refine the Fourier series by doubling the number of points sampled * @param[in] f the function used for evaluation. * @param[inout] F on input the first \e N coefficents of the Fourier * series; on output the refined transform based on 2\e N points, i.e., * the first 2\e N coefficents. * * The evaluates \f$ f(\sigma) \f$ at additional points \f$ \sigma = (j + * \frac12) \pi / (2 N) \f$ for integer \f$ j \in [0, N) \f$, computes the * DST-IV transform of these, and combines this with the input \e F to * compute the 2\e N term DST-III discrete sine transform. This is * equivalent to calling transform with twice the value of \e N but is more * efficient, given that the \e N term coefficients are already known. See * the example code above. **********************************************************************/ void GEOGRAPHICLIB_EXPORT refine(std::function f, real F[]) const; /** * Evaluate the Fourier sum given the sine and cosine of the angle * @param[in] sinx sinσ. * @param[in] cosx cosσ. * @param[in] F the array of Fourier coefficients. * @param[in] N the number of Fourier coefficients. * @return the value of the Fourier sum. **********************************************************************/ static real GEOGRAPHICLIB_EXPORT eval(real sinx, real cosx, const real F[], int N); /** * Evaluate the integral of Fourier sum given the sine and cosine of the * angle * @param[in] sinx sinσ. * @param[in] cosx cosσ. * @param[in] F the array of Fourier coefficients. * @param[in] N the number of Fourier coefficients. * @return the value of the integral. * * The constant of integration is chosen so that the integral is zero at * \f$ \sigma = \frac12\pi \f$. **********************************************************************/ static real GEOGRAPHICLIB_EXPORT integral(real sinx, real cosx, const real F[], int N); }; } // namespace GeographicLib #endif // GEOGRAPHICLIB_DST_HPP geosphere/src/a_geodesic.cpp0000644000176200001440000001054414323401121015603 0ustar liggesusers #include "Rcpp.h" //#include "geodesic.h" #include #include "Geodesic.h" #include "PolygonArea.h" //#include "Constants.hpp" #include "GeodesicLine.h" //using namespace GeographicLib; /* Robert Hijmans May 2015 December 2021 */ //SEXP _geodesic(SEXP longitude, SEXP latitude, SEXP azimuth, SEXP distance, SEXP pa, SEXP pf) { /* //[[Rcpp::export(name = ".geodesic")]] std::vector geodesic(std::vector lon1, std::vector lat1, std::vector azi1, std::vector s12, double a, double f) { struct geod_geodesic g; geod_init(&g, a, f); size_t n = lat1.size(); std::vector r(n * 3); for (size_t i=0; i < n; i++) { size_t j = i * 3; geod_direct(&g, lat1[i], lon1[i], azi1[i], s12[i], &r[j], &r[j+1], &r[j+2]); } return r; } */ //[[Rcpp::export(name = ".geodesic")]] std::vector geodesic(std::vector lon1, std::vector lat1, std::vector azi1, std::vector s12, double a, double f) { GeographicLib::Geodesic geod(a, f); size_t n = lat1.size(); std::vector r(n * 3); for (size_t i=0; i < n; i++) { size_t j = i * 3; geod.Direct(lat1[i], lon1[i], azi1[i], s12[i], r[j+1], r[j], r[j+2]); } return r; } //SEXP _inversegeodesic(SEXP longitude1, SEXP latitude1, SEXP longitude2, SEXP latitude2, SEXP pa, SEXP pf) { /* //[[Rcpp::export(name = ".inversegeodesic")]] std::vector inversegeodesic(std::vector lon1, std::vector lat1, std::vector lon2, std::vector lat2, double a, double f) { struct geod_geodesic g; geod_init(&g, a, f); size_t n = lat1.size(); std::vector r(n * 3); for (size_t i=0; i < n; i++) { size_t j = i * 3; geod_inverse(&g, lat1[i], lon1[i], lat2[i], lon2[i], &r[j], &r[j+1], &r[j+2]); } return r; } */ //[[Rcpp::export(name = ".inversegeodesic")]] std::vector inversegeodesic(std::vector lon1, std::vector lat1, std::vector lon2, std::vector lat2, double a, double f) { const GeographicLib::Geodesic& geod = GeographicLib::Geodesic::WGS84(); size_t n = lat1.size(); std::vector r(n * 3); for (size_t i=0; i < n; i++) { size_t j = i * 3; geod.Inverse(lat1[i], lon1[i], lat2[i], lon2[i], r[j], r[j+1], r[j+2]); } return r; } //SEXP _polygonarea(SEXP longitude, SEXP latitude, SEXP pa, SEXP pf) { /* //[[Rcpp::export(name = ".polygonarea")]] std::vector polygonarea(std::vector lon, std::vector lat, double a, double f) { struct geod_geodesic g; struct geod_polygon p; geod_init(&g, a, f); geod_polygon_init(&p, 0); double A, P; for (size_t i=0; i r = {n, P, A}; return(r); } */ //[[Rcpp::export(name = ".polygonarea")]] std::vector polygonarea(std::vector lon, std::vector lat, double a, double f) { std::vector out(3); // n, perimeter, area; GeographicLib::Geodesic geod(a, f); GeographicLib::PolygonArea poly(geod); try { for (size_t i=0; i> geodesic_nodes(double lon1, double lat1, double lon2, double lat2, size_t n, double distance, bool arc, double a, double f) { GeographicLib::Geodesic geod(a, f); GeographicLib::GeodesicLine line = geod.InverseLine(lat1, lon1, lat2, lon2); // number of intervals if (n == 0) { if (distance <= 0) { n = 1; } else { n = int(ceil(line.Distance() / std::abs(distance))); } } std::vector> out(2); out[0].reserve(n+1); out[1].reserve(n+1); out[0].push_back(lon1); out[1].push_back(lat1); if (arc) { // intervals of equal arc length double da = line.Arc() / n; for (size_t i=1; i #include #include template class kissfft { public: typedef std::complex cpx_t; kissfft( const std::size_t nfft, const bool inverse ) :_nfft(nfft) ,_inverse(inverse) { using std::acos; using std::cos; using std::sin; if (_nfft == 0) return; // fill twiddle factors _twiddles.resize(_nfft); { const scalar_t s = _inverse ? 1 : -1; const scalar_t d = acos( (scalar_t) -1) / (2 * _nfft); int i = 0, N = int(_nfft); // signed ints needed for subtractions // enforce trigonometric symmetries by evaluating sin and cos // with arguments in the range [-pi/4, pi/4] for (; 8*i < N; ++i) _twiddles[i] = cpx_t(+ cos((4*i )*d), +s*sin((4*i )*d)); // pi/4*[0, 1) for (; 8*i < 3*N; ++i) _twiddles[i] = cpx_t(- sin((4*i- N)*d), +s*cos((4*i- N)*d)); // pi/4*[1, 3) for (; 8*i < 5*N; ++i) _twiddles[i] = cpx_t(- cos((4*i-2*N)*d), -s*sin((4*i-2*N)*d)); // pi/4*[3, 5) for (; 8*i < 7*N; ++i) _twiddles[i] = cpx_t(+ sin((4*i-3*N)*d), -s*cos((4*i-3*N)*d)); // pi/4*[5, 7) for (; i < N; ++i) _twiddles[i] = cpx_t(+ cos((4*i-4*N)*d), +s*sin((4*i-4*N)*d)); // pi/4*[5, 8) } //factorize //start factoring out 4's, then 2's, then 3,5,7,9,... std::size_t n= _nfft; std::size_t p=4; do { while (n % p) { switch (p) { case 4: p = 2; break; case 2: p = 3; break; default: p += 2; break; } if (p*p>n) p = n;// no more factors } n /= p; _stageRadix.push_back(p); _stageRemainder.push_back(n); }while(n>1); } /// Changes the FFT-length and/or the transform direction. /// /// @post The @c kissfft object will be in the same state as if it /// had been newly constructed with the passed arguments. /// However, the implementation may be faster than constructing a /// new fft object. void assign( const std::size_t nfft, const bool inverse ) { if ( nfft != _nfft ) { kissfft tmp( nfft, inverse ); // O(n) time. std::swap( tmp, *this ); // this is O(1) in C++11, O(n) otherwise. } else if ( inverse != _inverse ) { // conjugate the twiddle factors. for ( typename std::vector::iterator it = _twiddles.begin(); it != _twiddles.end(); ++it ) it->imag( -it->imag() ); } } /// Calculates the complex Discrete Fourier Transform. /// /// The size of the passed arrays must be passed in the constructor. /// The sum of the squares of the absolute values in the @c dst /// array will be @c N times the sum of the squares of the absolute /// values in the @c src array, where @c N is the size of the array. /// In other words, the l_2 norm of the resulting array will be /// @c sqrt(N) times as big as the l_2 norm of the input array. /// This is also the case when the inverse flag is set in the /// constructor. Hence when applying the same transform twice, but with /// the inverse flag changed the second time, then the result will /// be equal to the original input times @c N. void transform(const cpx_t * fft_in, cpx_t * fft_out, const std::size_t stage = 0, const std::size_t fstride = 1, const std::size_t in_stride = 1) const { if (_nfft == 0) return; const std::size_t p = _stageRadix[stage]; const std::size_t m = _stageRemainder[stage]; cpx_t * const Fout_beg = fft_out; cpx_t * const Fout_end = fft_out + p*m; if (m==1) { do{ *fft_out = *fft_in; fft_in += fstride*in_stride; }while(++fft_out != Fout_end ); }else{ do{ // recursive call: // DFT of size m*p performed by doing // p instances of smaller DFTs of size m, // each one takes a decimated version of the input transform(fft_in, fft_out, stage+1, fstride*p,in_stride); fft_in += fstride*in_stride; }while( (fft_out += m) != Fout_end ); } fft_out=Fout_beg; // recombine the p smaller DFTs switch (p) { case 2: kf_bfly2(fft_out,fstride,m); break; case 3: kf_bfly3(fft_out,fstride,m); break; case 4: kf_bfly4(fft_out,fstride,m); break; case 5: kf_bfly5(fft_out,fstride,m); break; default: kf_bfly_generic(fft_out,fstride,m,p); break; } } /// Calculates the Discrete Fourier Transform (DFT) of a real input /// of size @c 2*N. /// /// The 0-th and N-th value of the DFT are real numbers. These are /// stored in @c dst[0].real() and @c dst[0].imag() respectively. /// The remaining DFT values up to the index N-1 are stored in /// @c dst[1] to @c dst[N-1]. /// The other half of the DFT values can be calculated from the /// symmetry relation /// @code /// DFT(src)[2*N-k] == conj( DFT(src)[k] ); /// @endcode /// The same scaling factors as in @c transform() apply. /// /// @note For this to work, the types @c scalar_t and @c cpx_t /// must fulfill the following requirements: /// /// For any object @c z of type @c cpx_t, /// @c reinterpret_cast(z)[0] is the real part of @c z and /// @c reinterpret_cast(z)[1] is the imaginary part of @c z. /// For any pointer to an element of an array of @c cpx_t named @c p /// and any valid array index @c i, @c reinterpret_cast(p)[2*i] /// is the real part of the complex number @c p[i], and /// @c reinterpret_cast(p)[2*i+1] is the imaginary part of the /// complex number @c p[i]. /// /// Since C++11, these requirements are guaranteed to be satisfied for /// @c scalar_ts being @c float, @c double or @c long @c double /// together with @c cpx_t being @c std::complex. void transform_real( const scalar_t * const src, cpx_t * const dst ) const { using std::acos; using std::exp; const std::size_t N = _nfft; if ( N == 0 ) return; // perform complex FFT transform( reinterpret_cast(src), dst ); // post processing for k = 0 and k = N dst[0] = cpx_t( dst[0].real() + dst[0].imag(), dst[0].real() - dst[0].imag() ); // post processing for all the other k = 1, 2, ..., N-1 const scalar_t pi = acos( (scalar_t) -1); const scalar_t half_phi_inc = ( _inverse ? pi : -pi ) / N; const cpx_t twiddle_mul = exp( cpx_t(0, half_phi_inc) ); for ( std::size_t k = 1; 2*k < N; ++k ) { const cpx_t w = (scalar_t)0.5 * cpx_t( dst[k].real() + dst[N-k].real(), dst[k].imag() - dst[N-k].imag() ); const cpx_t z = (scalar_t)0.5 * cpx_t( dst[k].imag() + dst[N-k].imag(), -dst[k].real() + dst[N-k].real() ); const cpx_t twiddle = k % 2 == 0 ? _twiddles[k/2] : _twiddles[k/2] * twiddle_mul; dst[ k] = w + twiddle * z; dst[N-k] = std::conj( w - twiddle * z ); } if ( N % 2 == 0 ) dst[N/2] = std::conj( dst[N/2] ); } private: void kf_bfly2( cpx_t * Fout, const size_t fstride, const std::size_t m) const { for (std::size_t k=0;k _scratchbuf.size()) _scratchbuf.resize(p); for ( std::size_t u=0; u=_nfft) twidx-=_nfft; Fout[ k ] += _scratchbuf[q] * twiddles[twidx]; } k += m; } } } std::size_t _nfft; bool _inverse; std::vector _twiddles; std::vector _stageRadix; std::vector _stageRemainder; mutable std::vector _scratchbuf; }; #endif geosphere/src/DST.cpp0000644000176200001440000001026714323403614014166 0ustar liggesusers/** * \file DST.cpp * \brief Implementation for GeographicLib::DST class * * Copyright (c) Charles Karney (2022) and licensed under * the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #include "DST.h" #include #include "kissfft.h" namespace GeographicLib { using namespace std; DST::DST(int N) : _N(N < 0 ? 0 : N) , _fft(make_shared(fft_t(2 * _N, false))) {} void DST::reset(int N) { N = N < 0 ? 0 : N; if (N == _N) return; _N = N; _fft->assign(2 * _N, false); } void DST::fft_transform(real data[], real F[], bool centerp) const { // Implement DST-III (centerp = false) or DST-IV (centerp = true). // Elements (0,N], resp. [0,N), of data should be set on input for centerp // = false, resp. true. F must have a size of at least N and on output // elements [0,N) of F contain the transform. if (_N == 0) return; if (centerp) { for (int i = 0; i < _N; ++i) { data[_N+i] = data[_N-1-i]; data[2*_N+i] = -data[i]; data[3*_N+i] = -data[_N-1-i]; } } else { data[0] = 0; // set [0] for (int i = 1; i < _N; ++i) data[_N+i] = data[_N-i]; // set [N+1,2*N-1] for (int i = 0; i < 2*_N; ++i) data[2*_N+i] = -data[i]; // [2*N, 4*N-1] } vector> ctemp(2*_N); _fft->transform_real(data, ctemp.data()); if (centerp) { real d = -Math::pi()/(4*_N); for (int i = 0, j = 1; i < _N; ++i, j+=2) ctemp[j] *= exp(complex(0, j*d)); } for (int i = 0, j = 1; i < _N; ++i, j+=2) { F[i] = -ctemp[j].imag() / (2*_N); } } void DST::fft_transform2(real data[], real F[]) const { // Elements [0,N), of data should be set to the N grid center values and F // should have size of at least 2*N. On input elements [0,N) of F contain // the size N transform; on output elements [0,2*N) of F contain the size // 2*N transform. fft_transform(data, F+_N, true); // Copy DST-IV order N tx to [0,N) elements of data for (int i = 0; i < _N; ++i) data[i] = F[i+_N]; for (int i = _N; i < 2*_N; ++i) // (DST-IV order N - DST-III order N) / 2 F[i] = (data[2*_N-1-i] - F[2*_N-1-i])/2; for (int i = 0; i < _N; ++i) // (DST-IV order N + DST-III order N) / 2 F[i] = (data[i] + F[i])/2; } void DST::transform(function f, real F[]) const { vector data(4 * _N); real d = Math::pi()/(2 * _N); for (int i = 1; i <= _N; ++i) data[i] = f( i * d ); fft_transform(data.data(), F, false); } void DST::refine(function f, real F[]) const { vector data(4 * _N); real d = Math::pi()/(4 * _N); for (int i = 0; i < _N; ++i) data[i] = f( (2*i + 1) * d ); fft_transform2(data.data(), F); } Math::real DST::eval(real sinx, real cosx, const real F[], int N) { // Evaluate // y = sum(F[i] * sin((2*i+1) * x), i, 0, N-1) // using Clenshaw summation. // Approx operation count = (N + 5) mult and (2 * N + 2) add real ar = 2 * (cosx - sinx) * (cosx + sinx), // 2 * cos(2 * x) y0 = N & 1 ? F[--N] : 0, y1 = 0; // accumulators for sum // Now N is even while (N > 0) { // Unroll loop x 2, so accumulators return to their original role y1 = ar * y0 - y1 + F[--N]; y0 = ar * y1 - y0 + F[--N]; } return sinx * (y0 + y1); // sin(x) * (y0 + y1) } Math::real DST::integral(real sinx, real cosx, const real F[], int N) { // Evaluate // y = -sum(F[i]/(2*i+1) * cos((2*i+1) * x), i, 0, N-1) // using Clenshaw summation. // Approx operation count = (N + 5) mult and (2 * N + 2) add int l = N; real ar = 2 * (cosx - sinx) * (cosx + sinx), // 2 * cos(2 * x) y0 = N & 1 ? F[--N]/(2*(--l)+1) : 0, y1 = 0; // accumulators for sum // Now N is even while (N > 0) { // Unroll loop x 2, so accumulators return to their original role y1 = ar * y0 - y1 + F[--N]/(2*(--l)+1); y0 = ar * y1 - y0 + F[--N]/(2*(--l)+1); } return cosx * (y1 - y0); // cos(x) * (y1 - y0) } } // namespace GeographicLib geosphere/src/a_dist.c0000644000176200001440000000744114323373006014440 0ustar liggesusers/* Robert Hijmans, June 2011 */ #include #include #include "a_util.h" double distPlane(double x1, double y1, double x2, double y2) { return( sqrt(pow((x2-x1),2) + pow((y2-y1), 2)) ); } double distCos(double lon1, double lat1, double lon2, double lat2, double r) { double cosd; lon1 = toRad(lon1); lon2 = toRad(lon2); lat1 = toRad(lat1); lat2 = toRad(lat2); cosd = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon1-lon2); return acos(cosd) * r; } double distHav(double lon1, double lat1, double lon2, double lat2, double r) { double dLat, dLon, a; lon1 = toRad(lon1); lon2 = toRad(lon2); lat1 = toRad(lat1); lat2 = toRad(lat2); dLat = lat2-lat1; dLon = lon2-lon1; a = sin(dLat/2.) * sin(dLat/2.) + cos(lat1) * cos(lat2) * sin(dLon/2.) * sin(dLon/2.); return 2. * atan2(sqrt(a), sqrt(1.-a)) * r; } double distVinSph(double lon1, double lat1, double lon2, double lat2, double r) { double x, x1, x2, y; lon1 = toRad(lon1); lon2 = toRad(lon2); lat1 = toRad(lat1); lat2 = toRad(lat2); x1 = cos(lat2) * sin(lon1-lon2); x2 = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon1-lon2); x = sqrt(x1*x1 + x2*x2); y = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon1-lon2); return r * atan2(x, y); } double distVinEll(double lon1, double lat1, double lon2, double lat2, double a, double b, double f) { /* Calculate geodesic distance (in m) between two points specified by latitude/longitude (in numeric degrees) using Vincenty inverse formula for ellipsoids based on source http://www.movable-type.co.uk/scripts/latlong-vincenty.html by Chris Veness */ double L, U1, U2, sinU1, cosU1, sinU2, cosU2, lambda, sinLambda, cosLambda, sinSigma, cosSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM, C, lambdaP, uSq, A, B, deltaSigma; int iterLimit, cont; if ((lon1 == lon2) & (lat1 == lat2)) { return 0.; } else if ( isnan(lon1) | isnan(lat1) | isnan(lon2) | isnan(lat2)) { return NAN; } else { lon1 = toRad(lon1); lon2 = toRad(lon2); lat1 = toRad(lat1); lat2 = toRad(lat2); L = (lon2-lon1); U1 = atan((1.-f) * tan(lat1)); U2 = atan((1.-f) * tan(lat2)); sinU1 = sin(U1); cosU1 = cos(U1); sinU2 = sin(U2); cosU2 = cos(U2); lambda = L; iterLimit = 100; cont = 1; while (cont) { sinLambda = sin(lambda); cosLambda = cos(lambda); sinSigma = sqrt((cosU2*sinLambda) * (cosU2*sinLambda) + (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda)); cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda; sigma = atan2(sinSigma, cosSigma); sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma; cosSqAlpha = 1. - sinAlpha*sinAlpha; cos2SigmaM = cosSigma - 2.*sinU1*sinU2/cosSqAlpha; if (isnan(cos2SigmaM)) { cos2SigmaM = 0.; // equatorial line: cosSqAlpha=0 (par 6) } C = f/16.*cosSqAlpha*(4.+f*(4.-3.*cosSqAlpha)); lambdaP = lambda; lambda = L + (1.-C) * f * sinAlpha * (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1.+2.*cos2SigmaM*cos2SigmaM))); iterLimit = iterLimit - 1; cont = (fabs(lambda-lambdaP) > 1e-12 && iterLimit > 0); } if (iterLimit==0) { return NAN; // formula failed to converge } else { uSq = cosSqAlpha * (a*a - b*b) / (b*b); A = 1. + uSq/16384.*(4096.+uSq*(-768.+uSq*(320.-175.*uSq))); B = uSq/1024. * (256.+uSq*(-128.+uSq*(74.-47.*uSq))); deltaSigma = B*sinSigma*(cos2SigmaM+B/4.*(cosSigma*(-1.+2.*cos2SigmaM*cos2SigmaM)- B/6.*cos2SigmaM*(-3.+4.*sinSigma*sinSigma)*(-3.+4.*cos2SigmaM*cos2SigmaM))); return b*A*(sigma-deltaSigma); } } } void distanceEllipsoid(int *n, double *lon1, double *lat1, double *lon2, double *lat2, double *a, double *b, double *f, int *m, double *dist) { if (*m > 0) { for(size_t i=0; i < *n; i++) { dist[i] = distVinEll(lon1[i], lat1[i], lon2[i], lat2[i], a[i], b[i], f[i]); } } } geosphere/src/Rhumb.h0000644000176200001440000006260714323377037014274 0ustar liggesusers/** * \file Rhumb.hpp * \brief Header for GeographicLib::Rhumb and GeographicLib::RhumbLine classes * * Copyright (c) Charles Karney (2014-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_RHUMB_HPP) #define GEOGRAPHICLIB_RHUMB_HPP 1 #include "Constants.h" #include "Ellipsoid.h" #if !defined(GEOGRAPHICLIB_RHUMBAREA_ORDER) /** * The order of the series approximation used in rhumb area calculations. * GEOGRAPHICLIB_RHUMBAREA_ORDER can be set to any integer in [4, 8]. **********************************************************************/ # define GEOGRAPHICLIB_RHUMBAREA_ORDER \ (GEOGRAPHICLIB_PRECISION == 2 ? 6 : \ (GEOGRAPHICLIB_PRECISION == 1 ? 4 : 8)) #endif namespace GeographicLib { class RhumbLine; template class PolygonAreaT; /** * \brief Solve of the direct and inverse rhumb problems. * * The path of constant azimuth between two points on an ellipsoid at (\e * lat1, \e lon1) and (\e lat2, \e lon2) is called the rhumb line (also * called the loxodrome). Its length is \e s12 and its azimuth is \e azi12. * (The azimuth is the heading measured clockwise from north.) * * Given \e lat1, \e lon1, \e azi12, and \e s12, we can determine \e lat2, * and \e lon2. This is the \e direct rhumb problem and its solution is * given by the function Rhumb::Direct. * * Given \e lat1, \e lon1, \e lat2, and \e lon2, we can determine \e azi12 * and \e s12. This is the \e inverse rhumb problem, whose solution is given * by Rhumb::Inverse. This finds the shortest such rhumb line, i.e., the one * that wraps no more than half way around the earth. If the end points are * on opposite meridians, there are two shortest rhumb lines and the * east-going one is chosen. * * These routines also optionally calculate the area under the rhumb line, \e * S12. This is the area, measured counter-clockwise, of the rhumb line * quadrilateral with corners (lat1,lon1), (0,lon1), * (0,lon2), and (lat2,lon2). * * Note that rhumb lines may be appreciably longer (up to 50%) than the * corresponding Geodesic. For example the distance between London Heathrow * and Tokyo Narita via the rhumb line is 11400 km which is 18% longer than * the geodesic distance 9600 km. * * For more information on rhumb lines see \ref rhumb. * * Example of use: * \include example-Rhumb.cpp **********************************************************************/ class GEOGRAPHICLIB_EXPORT Rhumb { private: typedef Math::real real; friend class RhumbLine; template friend class PolygonAreaT; Ellipsoid _ell; bool _exact; real _c2; static const int tm_maxord = GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER; static const int maxpow_ = GEOGRAPHICLIB_RHUMBAREA_ORDER; // _rR[0] unused real _rR[maxpow_ + 1]; static real gd(real x) { using std::atan; using std::sinh; return atan(sinh(x)); } // Use divided differences to determine (mu2 - mu1) / (psi2 - psi1) // accurately // // Definition: Df(x,y,d) = (f(x) - f(y)) / (x - y) // See: // W. M. Kahan and R. J. Fateman, // Symbolic computation of divided differences, // SIGSAM Bull. 33(2), 7-28 (1999) // https://doi.org/10.1145/334714.334716 // http://www.cs.berkeley.edu/~fateman/papers/divdiff.pdf static real Dlog(real x, real y) { using std::sqrt; using std::asinh; real t = x - y; // Change // // atanh(t / (x + y)) // // to // // asinh(t / (2 * sqrt(x*y))) // // to avoid taking atanh(1) when x is large and y is 1. N.B., this // routine is invoked with positive x and y, so no need to guard against // taking the sqrt of a negative quantity. This fixes bogus results for // the area being returning when an endpoint is at a pole. return t != 0 ? 2 * asinh(t / (2 * sqrt(x*y))) / t : 1 / x; } // N.B., x and y are in degrees static real Dtan(real x, real y) { real d = x - y, tx = Math::tand(x), ty = Math::tand(y), txy = tx * ty; return d != 0 ? (2 * txy > -1 ? (1 + txy) * Math::tand(d) : tx - ty) / (d * Math::degree()) : 1 + txy; } static real Datan(real x, real y) { using std::atan; real d = x - y, xy = x * y; return d != 0 ? (2 * xy > -1 ? atan( d / (1 + xy) ) : atan(x) - atan(y)) / d : 1 / (1 + xy); } static real Dsin(real x, real y) { using std::sin; using std::cos; real d = (x - y) / 2; return cos((x + y)/2) * (d != 0 ? sin(d) / d : 1); } static real Dsinh(real x, real y) { using std::sinh; using std::cosh; real d = (x - y) / 2; return cosh((x + y) / 2) * (d != 0 ? sinh(d) / d : 1); } static real Dcosh(real x, real y) { using std::sinh; real d = (x - y) / 2; return sinh((x + y) / 2) * (d != 0 ? sinh(d) / d : 1); } static real Dasinh(real x, real y) { using std::asinh; using std::hypot; real d = x - y, hx = hypot(real(1), x), hy = hypot(real(1), y); return d != 0 ? asinh(x*y > 0 ? d * (x + y) / (x*hy + y*hx) : x*hy - y*hx) / d : 1 / hx; } static real Dgd(real x, real y) { using std::sinh; return Datan(sinh(x), sinh(y)) * Dsinh(x, y); } // N.B., x and y are the tangents of the angles static real Dgdinv(real x, real y) { return Dasinh(x, y) / Datan(x, y); } // Copied from LambertConformalConic... // Deatanhe(x,y) = eatanhe((x-y)/(1-e^2*x*y))/(x-y) real Deatanhe(real x, real y) const { real t = x - y, d = 1 - _ell._e2 * x * y; return t != 0 ? Math::eatanhe(t / d, _ell._es) / t : _ell._e2 / d; } // (E(x) - E(y)) / (x - y) -- E = incomplete elliptic integral of 2nd kind real DE(real x, real y) const; // (mux - muy) / (phix - phiy) using elliptic integrals real DRectifying(real latx, real laty) const; // (psix - psiy) / (phix - phiy) real DIsometric(real latx, real laty) const; // (sum(c[j]*sin(2*j*x),j=1..n) - sum(c[j]*sin(2*j*x),j=1..n)) / (x - y) static real SinCosSeries(bool sinp, real x, real y, const real c[], int n); // (mux - muy) / (chix - chiy) using Krueger's series real DConformalToRectifying(real chix, real chiy) const; // (chix - chiy) / (mux - muy) using Krueger's series real DRectifyingToConformal(real mux, real muy) const; // (mux - muy) / (psix - psiy) // N.B., psix and psiy are in degrees real DIsometricToRectifying(real psix, real psiy) const; // (psix - psiy) / (mux - muy) real DRectifyingToIsometric(real mux, real muy) const; real MeanSinXi(real psi1, real psi2) const; // The following two functions (with lots of ignored arguments) mimic the // interface to the corresponding Geodesic function. These are needed by // PolygonAreaT. void GenDirect(real lat1, real lon1, real azi12, bool, real s12, unsigned outmask, real& lat2, real& lon2, real&, real&, real&, real&, real&, real& S12) const { GenDirect(lat1, lon1, azi12, s12, outmask, lat2, lon2, S12); } void GenInverse(real lat1, real lon1, real lat2, real lon2, unsigned outmask, real& s12, real& azi12, real&, real& , real& , real& , real& S12) const { GenInverse(lat1, lon1, lat2, lon2, outmask, s12, azi12, S12); } public: /** * Bit masks for what calculations to do. They specify which results to * return in the general routines Rhumb::GenDirect and Rhumb::GenInverse * routines. RhumbLine::mask is a duplication of this enum. **********************************************************************/ enum mask { /** * No output. * @hideinitializer **********************************************************************/ NONE = 0U, /** * Calculate latitude \e lat2. * @hideinitializer **********************************************************************/ LATITUDE = 1U<<7, /** * Calculate longitude \e lon2. * @hideinitializer **********************************************************************/ LONGITUDE = 1U<<8, /** * Calculate azimuth \e azi12. * @hideinitializer **********************************************************************/ AZIMUTH = 1U<<9, /** * Calculate distance \e s12. * @hideinitializer **********************************************************************/ DISTANCE = 1U<<10, /** * Calculate area \e S12. * @hideinitializer **********************************************************************/ AREA = 1U<<14, /** * Unroll \e lon2 in the direct calculation. * @hideinitializer **********************************************************************/ LONG_UNROLL = 1U<<15, /** * Calculate everything. (LONG_UNROLL is not included in this mask.) * @hideinitializer **********************************************************************/ ALL = 0x7F80U, }; /** * Constructor for an ellipsoid with * * @param[in] a equatorial radius (meters). * @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere. * Negative \e f gives a prolate ellipsoid. * @param[in] exact if true (the default) use an addition theorem for * elliptic integrals to compute divided differences; otherwise use * series expansion (accurate for |f| < 0.01). * @exception GeographicErr if \e a or (1 − \e f) \e a is not * positive. * * See \ref rhumb, for a detailed description of the \e exact parameter. **********************************************************************/ Rhumb(real a, real f, bool exact = true); /** * Solve the direct rhumb problem returning also the area. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi12 azimuth of the rhumb line (degrees). * @param[in] s12 distance between point 1 and point 2 (meters); it can be * negative. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees). * @param[out] S12 area under the rhumb line (meters2). * * \e lat1 should be in the range [−90°, 90°]. The value of * \e lon2 returned is in the range [−180°, 180°]. * * If point 1 is a pole, the cosine of its latitude is taken to be * 1/ε2 (where ε is 2-52). This * position, which is extremely close to the actual pole, allows the * calculation to be carried out in finite terms. If \e s12 is large * enough that the rhumb line crosses a pole, the longitude of point 2 * is indeterminate (a NaN is returned for \e lon2 and \e S12). **********************************************************************/ void Direct(real lat1, real lon1, real azi12, real s12, real& lat2, real& lon2, real& S12) const { GenDirect(lat1, lon1, azi12, s12, LATITUDE | LONGITUDE | AREA, lat2, lon2, S12); } /** * Solve the direct rhumb problem without the area. **********************************************************************/ void Direct(real lat1, real lon1, real azi12, real s12, real& lat2, real& lon2) const { real t; GenDirect(lat1, lon1, azi12, s12, LATITUDE | LONGITUDE, lat2, lon2, t); } /** * The general direct rhumb problem. Rhumb::Direct is defined in terms * of this function. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi12 azimuth of the rhumb line (degrees). * @param[in] s12 distance between point 1 and point 2 (meters); it can be * negative. * @param[in] outmask a bitor'ed combination of Rhumb::mask values * specifying which of the following parameters should be set. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees). * @param[out] S12 area under the rhumb line (meters2). * * The Rhumb::mask values possible for \e outmask are * - \e outmask |= Rhumb::LATITUDE for the latitude \e lat2; * - \e outmask |= Rhumb::LONGITUDE for the latitude \e lon2; * - \e outmask |= Rhumb::AREA for the area \e S12; * - \e outmask |= Rhumb::ALL for all of the above; * - \e outmask |= Rhumb::LONG_UNROLL to unroll \e lon2 instead of wrapping * it into the range [−180°, 180°]. * . * With the Rhumb::LONG_UNROLL bit set, the quantity \e lon2 − * \e lon1 indicates how many times and in what sense the rhumb line * encircles the ellipsoid. **********************************************************************/ void GenDirect(real lat1, real lon1, real azi12, real s12, unsigned outmask, real& lat2, real& lon2, real& S12) const; /** * Solve the inverse rhumb problem returning also the area. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] lat2 latitude of point 2 (degrees). * @param[in] lon2 longitude of point 2 (degrees). * @param[out] s12 rhumb distance between point 1 and point 2 (meters). * @param[out] azi12 azimuth of the rhumb line (degrees). * @param[out] S12 area under the rhumb line (meters2). * * The shortest rhumb line is found. If the end points are on opposite * meridians, there are two shortest rhumb lines and the east-going one is * chosen. \e lat1 and \e lat2 should be in the range [−90°, * 90°]. The value of \e azi12 returned is in the range * [−180°, 180°]. * * If either point is a pole, the cosine of its latitude is taken to be * 1/ε2 (where ε is 2-52). This * position, which is extremely close to the actual pole, allows the * calculation to be carried out in finite terms. **********************************************************************/ void Inverse(real lat1, real lon1, real lat2, real lon2, real& s12, real& azi12, real& S12) const { GenInverse(lat1, lon1, lat2, lon2, DISTANCE | AZIMUTH | AREA, s12, azi12, S12); } /** * Solve the inverse rhumb problem without the area. **********************************************************************/ void Inverse(real lat1, real lon1, real lat2, real lon2, real& s12, real& azi12) const { real t; GenInverse(lat1, lon1, lat2, lon2, DISTANCE | AZIMUTH, s12, azi12, t); } /** * The general inverse rhumb problem. Rhumb::Inverse is defined in terms * of this function. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] lat2 latitude of point 2 (degrees). * @param[in] lon2 longitude of point 2 (degrees). * @param[in] outmask a bitor'ed combination of Rhumb::mask values * specifying which of the following parameters should be set. * @param[out] s12 rhumb distance between point 1 and point 2 (meters). * @param[out] azi12 azimuth of the rhumb line (degrees). * @param[out] S12 area under the rhumb line (meters2). * * The Rhumb::mask values possible for \e outmask are * - \e outmask |= Rhumb::DISTANCE for the latitude \e s12; * - \e outmask |= Rhumb::AZIMUTH for the latitude \e azi12; * - \e outmask |= Rhumb::AREA for the area \e S12; * - \e outmask |= Rhumb::ALL for all of the above; **********************************************************************/ void GenInverse(real lat1, real lon1, real lat2, real lon2, unsigned outmask, real& s12, real& azi12, real& S12) const; /** * Set up to compute several points on a single rhumb line. * * @param[in] lat1 latitude of point 1 (degrees). * @param[in] lon1 longitude of point 1 (degrees). * @param[in] azi12 azimuth of the rhumb line (degrees). * @return a RhumbLine object. * * \e lat1 should be in the range [−90°, 90°]. * * If point 1 is a pole, the cosine of its latitude is taken to be * 1/ε2 (where ε is 2-52). This * position, which is extremely close to the actual pole, allows the * calculation to be carried out in finite terms. **********************************************************************/ RhumbLine Line(real lat1, real lon1, real azi12) const; /** \name Inspector functions. **********************************************************************/ ///@{ /** * @return \e a the equatorial radius of the ellipsoid (meters). This is * the value used in the constructor. **********************************************************************/ Math::real EquatorialRadius() const { return _ell.EquatorialRadius(); } /** * @return \e f the flattening of the ellipsoid. This is the * value used in the constructor. **********************************************************************/ Math::real Flattening() const { return _ell.Flattening(); } /** * @return total area of ellipsoid in meters2. The area of a * polygon encircling a pole can be found by adding * Geodesic::EllipsoidArea()/2 to the sum of \e S12 for each side of the * polygon. **********************************************************************/ Math::real EllipsoidArea() const { return _ell.Area(); } ///@} /** * A global instantiation of Rhumb with the parameters for the WGS84 * ellipsoid. **********************************************************************/ static const Rhumb& WGS84(); }; /** * \brief Find a sequence of points on a single rhumb line. * * RhumbLine facilitates the determination of a series of points on a single * rhumb line. The starting point (\e lat1, \e lon1) and the azimuth \e * azi12 are specified in the call to Rhumb::Line which returns a RhumbLine * object. RhumbLine.Position returns the location of point 2 (and, * optionally, the corresponding area, \e S12) a distance \e s12 along the * rhumb line. * * There is no public constructor for this class. (Use Rhumb::Line to create * an instance.) The Rhumb object used to create a RhumbLine must stay in * scope as long as the RhumbLine. * * Example of use: * \include example-RhumbLine.cpp **********************************************************************/ class GEOGRAPHICLIB_EXPORT RhumbLine { private: typedef Math::real real; friend class Rhumb; const Rhumb& _rh; real _lat1, _lon1, _azi12, _salp, _calp, _mu1, _psi1, _r1; // copy assignment not allowed RhumbLine& operator=(const RhumbLine&) = delete; RhumbLine(const Rhumb& rh, real lat1, real lon1, real azi12); public: /** * Construction is via default copy constructor. **********************************************************************/ RhumbLine(const RhumbLine&) = default; /** * This is a duplication of Rhumb::mask. **********************************************************************/ enum mask { /** * No output. * @hideinitializer **********************************************************************/ NONE = Rhumb::NONE, /** * Calculate latitude \e lat2. * @hideinitializer **********************************************************************/ LATITUDE = Rhumb::LATITUDE, /** * Calculate longitude \e lon2. * @hideinitializer **********************************************************************/ LONGITUDE = Rhumb::LONGITUDE, /** * Calculate azimuth \e azi12. * @hideinitializer **********************************************************************/ AZIMUTH = Rhumb::AZIMUTH, /** * Calculate distance \e s12. * @hideinitializer **********************************************************************/ DISTANCE = Rhumb::DISTANCE, /** * Calculate area \e S12. * @hideinitializer **********************************************************************/ AREA = Rhumb::AREA, /** * Unroll \e lon2 in the direct calculation. * @hideinitializer **********************************************************************/ LONG_UNROLL = Rhumb::LONG_UNROLL, /** * Calculate everything. (LONG_UNROLL is not included in this mask.) * @hideinitializer **********************************************************************/ ALL = Rhumb::ALL, }; /** * Compute the position of point 2 which is a distance \e s12 (meters) from * point 1. The area is also computed. * * @param[in] s12 distance between point 1 and point 2 (meters); it can be * negative. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees). * @param[out] S12 area under the rhumb line (meters2). * * The value of \e lon2 returned is in the range [−180°, * 180°]. * * If \e s12 is large enough that the rhumb line crosses a pole, the * longitude of point 2 is indeterminate (a NaN is returned for \e lon2 and * \e S12). **********************************************************************/ void Position(real s12, real& lat2, real& lon2, real& S12) const { GenPosition(s12, LATITUDE | LONGITUDE | AREA, lat2, lon2, S12); } /** * Compute the position of point 2 which is a distance \e s12 (meters) from * point 1. The area is not computed. **********************************************************************/ void Position(real s12, real& lat2, real& lon2) const { real t; GenPosition(s12, LATITUDE | LONGITUDE, lat2, lon2, t); } /** * The general position routine. RhumbLine::Position is defined in term so * this function. * * @param[in] s12 distance between point 1 and point 2 (meters); it can be * negative. * @param[in] outmask a bitor'ed combination of RhumbLine::mask values * specifying which of the following parameters should be set. * @param[out] lat2 latitude of point 2 (degrees). * @param[out] lon2 longitude of point 2 (degrees). * @param[out] S12 area under the rhumb line (meters2). * * The RhumbLine::mask values possible for \e outmask are * - \e outmask |= RhumbLine::LATITUDE for the latitude \e lat2; * - \e outmask |= RhumbLine::LONGITUDE for the latitude \e lon2; * - \e outmask |= RhumbLine::AREA for the area \e S12; * - \e outmask |= RhumbLine::ALL for all of the above; * - \e outmask |= RhumbLine::LONG_UNROLL to unroll \e lon2 instead of * wrapping it into the range [−180°, 180°]. * . * With the RhumbLine::LONG_UNROLL bit set, the quantity \e lon2 − \e * lon1 indicates how many times and in what sense the rhumb line encircles * the ellipsoid. * * If \e s12 is large enough that the rhumb line crosses a pole, the * longitude of point 2 is indeterminate (a NaN is returned for \e lon2 and * \e S12). **********************************************************************/ void GenPosition(real s12, unsigned outmask, real& lat2, real& lon2, real& S12) const; /** \name Inspector functions **********************************************************************/ ///@{ /** * @return \e lat1 the latitude of point 1 (degrees). **********************************************************************/ Math::real Latitude() const { return _lat1; } /** * @return \e lon1 the longitude of point 1 (degrees). **********************************************************************/ Math::real Longitude() const { return _lon1; } /** * @return \e azi12 the azimuth of the rhumb line (degrees). **********************************************************************/ Math::real Azimuth() const { return _azi12; } /** * @return \e a the equatorial radius of the ellipsoid (meters). This is * the value inherited from the Rhumb object used in the constructor. **********************************************************************/ Math::real EquatorialRadius() const { return _rh.EquatorialRadius(); } /** * @return \e f the flattening of the ellipsoid. This is the value * inherited from the Rhumb object used in the constructor. **********************************************************************/ Math::real Flattening() const { return _rh.Flattening(); } }; } // namespace GeographicLib #endif // GEOGRAPHICLIB_RHUMB_HPP geosphere/src/Geodesic.h0000644000176200001440000012770414323377037014741 0ustar liggesusers/** * \file Geodesic.hpp * \brief Header for GeographicLib::Geodesic class * * Copyright (c) Charles Karney (2009-2022) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_GEODESIC_HPP) #define GEOGRAPHICLIB_GEODESIC_HPP 1 #include "Constants.h" #if !defined(GEOGRAPHICLIB_GEODESIC_ORDER) /** * The order of the expansions used by Geodesic. * GEOGRAPHICLIB_GEODESIC_ORDER can be set to any integer in [3, 8]. **********************************************************************/ # define GEOGRAPHICLIB_GEODESIC_ORDER \ (GEOGRAPHICLIB_PRECISION == 2 ? 6 : \ (GEOGRAPHICLIB_PRECISION == 1 ? 3 : \ (GEOGRAPHICLIB_PRECISION == 3 ? 7 : 8))) #endif namespace GeographicLib { class GeodesicLine; /** * \brief %Geodesic calculations * * The shortest path between two points on an ellipsoid at (\e lat1, \e lon1) * and (\e lat2, \e lon2) is called the geodesic. Its length is \e s12 and * the geodesic from point 1 to point 2 has azimuths \e azi1 and \e azi2 at * the two end points. (The azimuth is the heading measured clockwise from * north. \e azi2 is the "forward" azimuth, i.e., the heading that takes you * beyond point 2 not back to point 1.) In the figure below, latitude is * labeled φ, longitude λ (with λ12 = * λ2 − λ1), and azimuth α. * * spheroidal triangle * * Given \e lat1, \e lon1, \e azi1, and \e s12, we can determine \e lat2, \e * lon2, and \e azi2. This is the \e direct geodesic problem and its * solution is given by the function Geodesic::Direct. (If \e s12 is * sufficiently large that the geodesic wraps more than halfway around the * earth, there will be another geodesic between the points with a smaller \e * s12.) * * Given \e lat1, \e lon1, \e lat2, and \e lon2, we can determine \e azi1, \e * azi2, and \e s12. This is the \e inverse geodesic problem, whose solution * is given by Geodesic::Inverse. Usually, the solution to the inverse * problem is unique. In cases where there are multiple solutions (all with * the same \e s12, of course), all the solutions can be easily generated * once a particular solution is provided. * * The standard way of specifying the direct problem is the specify the * distance \e s12 to the second point. However it is sometimes useful * instead to specify the arc length \e a12 (in degrees) on the auxiliary * sphere. This is a mathematical construct used in solving the geodesic * problems. The solution of the direct problem in this form is provided by * Geodesic::ArcDirect. An arc length in excess of 180° indicates that * the geodesic is not a shortest path. In addition, the arc length between * an equatorial crossing and the next extremum of latitude for a geodesic is * 90°. * * This class can also calculate several other quantities related to * geodesics. These are: * - reduced length. If we fix the first point and increase \e azi1 * by \e dazi1 (radians), the second point is displaced \e m12 \e dazi1 in * the direction \e azi2 + 90°. The quantity \e m12 is called * the "reduced length" and is symmetric under interchange of the two * points. On a curved surface the reduced length obeys a symmetry * relation, \e m12 + \e m21 = 0. On a flat surface, we have \e m12 = \e * s12. The ratio s12/\e m12 gives the azimuthal scale for an * azimuthal equidistant projection. * - geodesic scale. Consider a reference geodesic and a second * geodesic parallel to this one at point 1 and separated by a small * distance \e dt. The separation of the two geodesics at point 2 is \e * M12 \e dt where \e M12 is called the "geodesic scale". \e M21 is * defined similarly (with the geodesics being parallel at point 2). On a * flat surface, we have \e M12 = \e M21 = 1. The quantity 1/\e M12 gives * the scale of the Cassini-Soldner projection. * - area. The area between the geodesic from point 1 to point 2 and * the equation is represented by \e S12; it is the area, measured * counter-clockwise, of the geodesic quadrilateral with corners * (lat1,lon1), (0,lon1), (0,lon2), and * (lat2,lon2). It can be used to compute the area of any * geodesic polygon. * * Overloaded versions of Geodesic::Direct, Geodesic::ArcDirect, and * Geodesic::Inverse allow these quantities to be returned. In addition * there are general functions Geodesic::GenDirect, and Geodesic::GenInverse * which allow an arbitrary set of results to be computed. The quantities \e * m12, \e M12, \e M21 which all specify the behavior of nearby geodesics * obey addition rules. If points 1, 2, and 3 all lie on a single geodesic, * then the following rules hold: * - \e s13 = \e s12 + \e s23 * - \e a13 = \e a12 + \e a23 * - \e S13 = \e S12 + \e S23 * - \e m13 = \e m12 \e M23 + \e m23 \e M21 * - \e M13 = \e M12 \e M23 − (1 − \e M12 \e M21) \e m23 / \e m12 * - \e M31 = \e M32 \e M21 − (1 − \e M23 \e M32) \e m12 / \e m23 * * Additional functionality is provided by the GeodesicLine class, which * allows a sequence of points along a geodesic to be computed. * * The shortest distance returned by the solution of the inverse problem is * (obviously) uniquely defined. However, in a few special cases there are * multiple azimuths which yield the same shortest distance. Here is a * catalog of those cases: * - \e lat1 = −\e lat2 (with neither point at a pole). If \e azi1 = * \e azi2, the geodesic is unique. Otherwise there are two geodesics and * the second one is obtained by setting [\e azi1, \e azi2] → [\e * azi2, \e azi1], [\e M12, \e M21] → [\e M21, \e M12], \e S12 → * −\e S12. (This occurs when the longitude difference is near * ±180° for oblate ellipsoids.) * - \e lon2 = \e lon1 ± 180° (with neither point at a pole). If * \e azi1 = 0° or ±180°, the geodesic is unique. Otherwise * there are two geodesics and the second one is obtained by setting [\e * azi1, \e azi2] → [−\e azi1, −\e azi2], \e S12 → * −\e S12. (This occurs when \e lat2 is near −\e lat1 for * prolate ellipsoids.) * - Points 1 and 2 at opposite poles. There are infinitely many geodesics * which can be generated by setting [\e azi1, \e azi2] → [\e azi1, \e * azi2] + [\e d, −\e d], for arbitrary \e d. (For spheres, this * prescription applies when points 1 and 2 are antipodal.) * - \e s12 = 0 (coincident points). There are infinitely many geodesics * which can be generated by setting [\e azi1, \e azi2] → * [\e azi1, \e azi2] + [\e d, \e d], for arbitrary \e d. * * The calculations are accurate to better than 15 nm (15 nanometers) for the * WGS84 ellipsoid. See Sec. 9 of * arXiv:1102.1215v1 for * details. The algorithms used by this class are based on series expansions * using the flattening \e f as a small parameter. These are only accurate * for |f| < 0.02; however reasonably accurate results will be * obtained for |f| < 0.2. Here is a table of the approximate * maximum error (expressed as a distance) for an ellipsoid with the same * equatorial radius as the WGS84 ellipsoid and different values of the * flattening.