ADD: new track message, Entity class and Position class
This commit is contained in:
399
libs/geographiclib/maxima/tm.mac
Normal file
399
libs/geographiclib/maxima/tm.mac
Normal file
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
|
||||
Arbitrary precision Transverse Mercator Projection
|
||||
|
||||
Copyright (c) Charles Karney (2009-2017) <charles@karney.com> and
|
||||
licensed under the MIT/X11 License. For more information, see
|
||||
https://geographiclib.sourceforge.io/
|
||||
|
||||
Reference:
|
||||
|
||||
Charles F. F. Karney,
|
||||
Transverse Mercator with an accuracy of a few nanometers,
|
||||
J. Geodesy 85(8), 475-485 (Aug. 2011).
|
||||
DOI 10.1007/s00190-011-0445-3
|
||||
preprint https://arxiv.org/abs/1002.1417
|
||||
resource page https://geographiclib.sourceforge.io/tm.html
|
||||
|
||||
The parameters for the transformation are set by
|
||||
|
||||
setparams(a,f,k0)$
|
||||
sets the equatorial radius, inverse flattening, and central scale
|
||||
factor. The default is
|
||||
setparams(6378137b0, 1/298.257223563b0, 0.9996b0)$
|
||||
appropriate for UTM applications.
|
||||
|
||||
tm(lat,lon);
|
||||
takes lat and lon args (in degrees) and returns
|
||||
[x, y, convergence, scale]
|
||||
[x, y] do not include false eastings/northings but do include the
|
||||
scale factor k0. convergence is in degrees.
|
||||
|
||||
ll(x,y);
|
||||
takes x and y args (in meters) and returns
|
||||
[lat, lon, convergence, scale].
|
||||
|
||||
Example:
|
||||
|
||||
$ maxima
|
||||
Maxima 5.15.0 http://maxima.sourceforge.net
|
||||
Using Lisp CLISP 2.43 (2007-11-18)
|
||||
Distributed under the GNU Public License. See the file COPYING.
|
||||
Dedicated to the memory of William Schelter.
|
||||
The function bug_report() provides bug reporting information.
|
||||
(%i1) load("tm.mac")$
|
||||
(%i2) tm(10b0,20b0);
|
||||
(%o2) [2.235209504622466691587930831718465965864199221939781808953597771095103\
|
||||
6690000464b6, 1.17529734503138466792126931904154130080533935727351398258511134\
|
||||
68541970512119385b6, 3.6194756227592979778565787394402350354250845160819430786\
|
||||
093514889500602612857052b0, 1.062074627142564335518604915718789933200854739344\
|
||||
8664109599248189291146283796933b0]
|
||||
(%i3) ll(%[1],%[2]);
|
||||
(%o3) [1.0b1, 2.0b1, 3.6194756227592979778565787394402350354250845160819430786\
|
||||
093514889500602612857053b0, 1.062074627142564335518604915718789933200854739344\
|
||||
8664109599248189291146283796933b0]
|
||||
(%i4) float(%o2);
|
||||
(%o4) [2235209.504622467, 1175297.345031385, 3.619475622759298,
|
||||
1.062074627142564]
|
||||
(%i5) float(%o3);
|
||||
(%o5) [10.0, 20.0, 3.619475622759298, 1.062074627142564]
|
||||
|
||||
This implements GeographicLib::TransverseMercatorExact (i.e., Lee, 1976)
|
||||
using bfloats. However fewer changes from Lee 1976 have been made since
|
||||
we rely more heavily on the high precision to deal with problem cases.
|
||||
|
||||
To change the precision, change fpprec below and reload.
|
||||
|
||||
*/
|
||||
|
||||
fpprec:80$
|
||||
load("ellint.mac")$ /* Load elliptic functions */
|
||||
|
||||
tol:0.1b0^fpprec$
|
||||
tol1:0.1b0*sqrt(tol)$ /* For Newton's method */
|
||||
tol2:sqrt(0.01*tol*tol1)$ /* Also for Newton's method but more conservative */
|
||||
ahypover:log(10b0^fpprec)+2$
|
||||
|
||||
pi:bfloat(%pi)$
|
||||
degree:pi/180$
|
||||
ratprint:false$
|
||||
debugprint:false$
|
||||
setparams(a1,f1,k1):=(a:bfloat(a1),f:bfloat(f1),k0:bfloat(k1),
|
||||
e2:f*(2-f),
|
||||
e:sqrt(e2),
|
||||
kcu:kc(e2),
|
||||
kcv:kc(1-e2),
|
||||
ecu:ec(e2),
|
||||
ecv:ec(1-e2),
|
||||
n:f/(2-f),
|
||||
'done)$
|
||||
setparams(6378137b0, 1/298.257223563b0, 0.9996b0)$ /* WGS 84 */
|
||||
/* setparams(6378388b0, 1/297b0, 0.9996b0)$ International */
|
||||
/* setparams(1/ec(0.01b0), 1/(30*sqrt(11b0)+100), 1b0)$ testing, eps = 0.1*/
|
||||
|
||||
/*
|
||||
Interpret x_y(y) as x <- y, i.e., "transform quantity y to quantity x"
|
||||
|
||||
Let
|
||||
|
||||
phi = geodetic latitude
|
||||
psi = isometric latitude ( + i * lambda )
|
||||
sigma = TM coords
|
||||
thom = Thompson coords
|
||||
|
||||
*/
|
||||
|
||||
/* sqrt(x^2 + y^2) -- Real only */
|
||||
hypot(x,y):=sqrt(x^2 + y^2)$
|
||||
|
||||
/* log(1 + x) -- Real only */
|
||||
log1p(x) := block([y : 1b0+x],
|
||||
if y = 1b0 then x else x*log(y)/(y - 1))$
|
||||
|
||||
/* Real only */
|
||||
/* Some versions of Maxima have a buggy atanh
|
||||
atnh(x) := block([y : abs(x)],
|
||||
y : log1p(2 * y/(1 - y))/2,
|
||||
if x < 0 then -y else y)$ */
|
||||
atnh(x) := atanh(x)$
|
||||
|
||||
/* exp(x)-1 -- Real only */
|
||||
expm1(x) := block([y : exp(bfloat(x)),z],
|
||||
z : y - 1b0,
|
||||
if abs(x) > 1b0 then z else if z = 0b0 then x else x * z/log(y))$
|
||||
|
||||
/* Real only */
|
||||
/* Some versions of Maxima have a buggy sinh */
|
||||
snh(x) := block([u : expm1(x)],
|
||||
(u / (u + 1)) * (u + 2) /2);
|
||||
|
||||
/* Real only */
|
||||
psi_phi(phi):=block([s:sin(phi)],
|
||||
asinh(s/max(cos(phi),0.1b0*tol)) - e * atnh(e * s))$
|
||||
|
||||
/* Real only */
|
||||
phi_psi(psi):=block([q:psi,t,dq],
|
||||
for i do (
|
||||
t:tanh(q),
|
||||
dq : -(q - e * atnh(e * t) - psi) * (1 - e2 * t^2) / (1 - e2),
|
||||
q : q + dq,
|
||||
if debugprint then print(float(q), float(dq)),
|
||||
if abs(dq) < tol1 then return(false)),
|
||||
atan(snh(q)))$
|
||||
|
||||
psi_thom_comb(w):=block([jacr:sncndn(bfloat(realpart(w)),1-e2),
|
||||
jaci:sncndn(bfloat(imagpart(w)),e2),d,d1,d2],
|
||||
d:(1-e2)*(jaci[2]^2 + e2 * (jacr[1] * jaci[1])^2)^2,
|
||||
d1:sqrt(jacr[2]^2 + (1-e2) * (jacr[1] * jaci[1])^2),
|
||||
d2:sqrt(e2 * jacr[2]^2 + (1-e2) * jaci[2]^2),
|
||||
[
|
||||
(if d1 > 0b0 then asinh(jacr[1]*jaci[3]/ d1) else signnum(snu) * ahypover)
|
||||
- (if d2 > 0b0 then e * asinh(e * jacr[1] / d2) else signnum(snu) * ahypover)
|
||||
+ %i * (if d1 > 0b0 and d2 > 0b0 then
|
||||
atan2(jacr[3]*jaci[1],jacr[2]*jaci[2])
|
||||
- e * atan2(e*jacr[2]*jaci[1],jacr[3]*jaci[2]) else 0),
|
||||
jacr[2]*jacr[3]*jaci[3]*(jaci[2]^2-e2*(jacr[1]*jaci[1])^2)/d
|
||||
-%i * jacr[1]*jaci[1]*jaci[2]*((jacr[3]*jaci[3])^2+e2*jacr[2]^2)/d]
|
||||
)$
|
||||
|
||||
psi_thom(w):=block([tt:psi_thom_comb(w)],tt[1])$
|
||||
inv_diff_psi_thom(w):=block([tt:psi_thom_comb(w)],tt[2])$
|
||||
|
||||
w0a(psi):=block([lam:bfloat(imagpart(psi)),psia:bfloat(realpart(psi))],
|
||||
rectform(kcu/(pi/2)*( atan2(snh(psia),cos(lam))
|
||||
+%i*asinh(sin(lam)/sqrt(cos(lam)^2 + snh(psia)^2)))))$
|
||||
|
||||
w0c(psi):=block([m,a,dlam],
|
||||
dlam:bfloat(imagpart(psi))-pi/2*(1-e),
|
||||
psi:bfloat(realpart(psi)),
|
||||
m:sqrt(psi^2+dlam^2)*3/(1-e2)/e,
|
||||
a:if m = 0b0 then 0 else atan2(dlam-psi, psi+dlam) - 0.75b0*pi,
|
||||
m:m^(1/3), a:a/3,
|
||||
m*cos(a)+%i*(m*sin(a)+kcv))$
|
||||
|
||||
w0d(psi):=block([psir:-realpart(psi)/e+1b0,lam:(pi/2-imagpart(psi))/e,uu,vv],
|
||||
uu:asinh(sin(lam)/sqrt(cos(lam)^2+snh(psir)^2))*(1+e2/2),
|
||||
vv:atan2(cos(lam), snh(psir)) *(1+e2/2),
|
||||
(-uu+kcu) + %i * (-vv+kcv))$
|
||||
|
||||
w0m(psi):=if realpart(psi)<-e/2*pi/2 and
|
||||
imagpart(psi)>pi/2*(1-2*e) and
|
||||
realpart(psi) < imagpart(psi)-(pi/2*(1-e)) then w0d(psi) else
|
||||
if realpart(psi)<e*pi/2 and imagpart(psi)>pi/2*(1-2*e)
|
||||
then w0c(psi) else w0a(psi)$
|
||||
w0(psi):=w0m(psi)$
|
||||
|
||||
thom_psi(psi):=block([w:w0(psi),dw,v,vv],
|
||||
if not(abs(psi-pi/2*(1-e)*%i) < e * tol^0.6b0) then
|
||||
for i do (
|
||||
if i > 100 then error("too many iterations"),
|
||||
vv:psi_thom_comb(w),
|
||||
v:vv[1],
|
||||
dw:-rectform((v-psi)*vv[2]),
|
||||
w:w+dw,
|
||||
dw:abs(dw),
|
||||
if debugprint then print(float(w),float(dw)),
|
||||
/* error is approx dw^2/2 */
|
||||
if dw < tol2 then return(false)
|
||||
),
|
||||
w
|
||||
)$
|
||||
|
||||
sigma_thom_comb(w):=block([u:bfloat(realpart(w)),v:bfloat(imagpart(w)),
|
||||
jacr,jaci,phi,iu,iv,den,den1,er,ei,dnr,dni],
|
||||
jacr:sncndn(u,1-e2),jaci:sncndn(v,e2),
|
||||
er:eirx(jacr[1],jacr[2],jacr[3],e2,ecu),
|
||||
ei:eirx(jaci[1],jaci[2],jaci[3],1-e2,ecv),
|
||||
den:e2*jacr[2]^2+(1-e2)*jaci[2]^2,
|
||||
den1:(1-e2)*(jaci[2]^2 + e2 * (jacr[1] * jaci[1])^2)^2,
|
||||
dnr:jacr[3]*jaci[2]*jaci[3],
|
||||
dni:-e2*jacr[1]*jacr[2]*jaci[1],
|
||||
[ er - e2*jacr[1]*jacr[2]*jacr[3]/den
|
||||
+ %i*(v - ei + (1-e2)*jaci[1]*jaci[2]*jaci[3]/den),
|
||||
(dnr^2-dni^2)/den1 + %i * 2*dnr*dni/den1])$
|
||||
|
||||
sigma_thom(w):=block([tt:sigma_thom_comb(w)],tt[1])$
|
||||
inv_diff_sigma_thom(w):=block([tt:sigma_thom_comb(w)],tt[2])$
|
||||
|
||||
wx0a(sigma):=rectform(sigma*kcu/ecu)$
|
||||
wx0b(sigma):=block([m,aa],
|
||||
sigma:rectform(sigma-%i*(kcv-ecv)),
|
||||
m:abs(sigma)*3/(1-e2),
|
||||
aa:atan2(imagpart(sigma),realpart(sigma)),
|
||||
if aa<-pi/2 then aa:aa+2*pi,
|
||||
aa:aa-pi,
|
||||
rectform(m^(1/3)*(cos(aa/3b0)+%i*sin(aa/3b0))+%i*kcv))$
|
||||
wx0c(sigma):=rectform(1/(sigma-(ecu+%i*(kcv-ecv))) + kcu+%i*kcv)$
|
||||
wx0m(sigma):=block([eta:bfloat(imagpart(sigma)),
|
||||
xi:bfloat(realpart(sigma))],
|
||||
if eta > 1.25b0 * (kcv-ecv) or (xi < -0.25*ecu and xi < eta-(kcv-ecv)) then
|
||||
wx0c(sigma) else
|
||||
if (eta > 0.75b0 * (kcv-ecv) and xi < 0.25b0 * ecu) or
|
||||
eta > kcv-ecv or xi < 0 then wx0b(sigma) else wx0a(sigma))$
|
||||
wx0(sigma):=wx0m(sigma)$
|
||||
thom_sigma(sigma):=block([w:wx0(sigma),dw,v,vv],
|
||||
for i do (
|
||||
if i > 100 then error("too many iterations"),
|
||||
vv:sigma_thom_comb(w),
|
||||
v:vv[1],
|
||||
dw:-rectform((v-sigma)*vv[2]),
|
||||
w:w+dw,
|
||||
dw:abs(dw),
|
||||
if debugprint then print(float(w),float(dw)),
|
||||
/* error is approx dw^2/2 */
|
||||
if dw < tol2 then return(false)
|
||||
),
|
||||
w
|
||||
)$
|
||||
|
||||
/* Lee/Thompson's method forward */
|
||||
|
||||
tm(phi,lam):=block([psi,thom,jacr,jaci,sigma,gam,scale,c],
|
||||
phi:phi*degree,
|
||||
lam:lam*degree,
|
||||
psi:psi_phi(phi),
|
||||
thom:thom_psi(psi+%i*lam),
|
||||
jacr:sncndn(bfloat(realpart(thom)),1-e2),
|
||||
jaci:sncndn(bfloat(imagpart(thom)),e2),
|
||||
sigma:sigma_thom(thom),
|
||||
c:cos(phi),
|
||||
if c > tol1 then (
|
||||
gam:atan2((1-e2)*jacr[1]*jaci[1]*jaci[2],
|
||||
jacr[2]*jacr[3]*jaci[3]),
|
||||
scale:sqrt(1-e2 + e2 * c^2)/c*
|
||||
sqrt(((1-e2)*jaci[1]^2 + (jacr[2]*jaci[3])^2)/
|
||||
(e2*jacr[2]^2 + (1-e2)*jaci[2]^2)))
|
||||
else (gam : lam, scale : 1b0),
|
||||
[imagpart(sigma)*k0*a,realpart(sigma)*k0*a,gam/degree,k0*scale])$
|
||||
|
||||
/* Lee/Thompson's method reverse */
|
||||
|
||||
ll(x,y):=block([sigma,thom,jacr,jaci,psi,lam,phi,gam,scale,c],
|
||||
sigma:y/(a*k0)+%i*x/(a*k0),
|
||||
thom:thom_sigma(sigma),
|
||||
jacr:sncndn(bfloat(realpart(thom)),1-e2),
|
||||
jaci:sncndn(bfloat(imagpart(thom)),e2),
|
||||
psi:psi_thom(thom),
|
||||
lam:bfloat(imagpart(psi)),
|
||||
psi:bfloat(realpart(psi)),
|
||||
phi:phi_psi(psi),
|
||||
c:cos(phi),
|
||||
if c > tol1 then (
|
||||
gam:atan2((1-e2)*jacr[1]*jaci[1]*jaci[2],
|
||||
jacr[2]*jacr[3]*jaci[3]),
|
||||
scale:sqrt(1-e2 + e2 * c^2)/c*
|
||||
sqrt(((1-e2)*jaci[1]^2 + (jacr[2]*jaci[3])^2)/
|
||||
(e2*jacr[2]^2 + (1-e2)*jaci[2]^2)))
|
||||
else (gam : lam, scale : 1b0),
|
||||
[phi/degree,lam/degree,gam/degree,k0*scale])$
|
||||
|
||||
/* Return lat/lon/x/y for a point specified in Thompson coords */
|
||||
/* Pick u in [0, kcu] and v in [0, kcv] */
|
||||
lltm(u,v):=block([jacr,jaci,psi,lam,phi,c,gam,scale,sigma,x,y],
|
||||
u:bfloat(u), v:bfloat(v),
|
||||
jacr:sncndn(u,1-e2),
|
||||
jaci:sncndn(v,e2),
|
||||
psi:psi_thom(u+%i*v),
|
||||
sigma:sigma_thom(u+%i*v),
|
||||
x:imagpart(sigma)*k0*a,y:realpart(sigma)*k0*a,
|
||||
lam:bfloat(imagpart(psi)),
|
||||
psi:bfloat(realpart(psi)),
|
||||
phi:phi_psi(psi),
|
||||
c:cos(phi),
|
||||
if c > tol1 then (
|
||||
gam:atan2((1-e2)*jacr[1]*jaci[1]*jaci[2],
|
||||
jacr[2]*jacr[3]*jaci[3]),
|
||||
scale:sqrt(1-e2 + e2 * c^2)/c*
|
||||
sqrt(((1-e2)*jaci[1]^2 + (jacr[2]*jaci[3])^2)/
|
||||
(e2*jacr[2]^2 + (1-e2)*jaci[2]^2)))
|
||||
else (gam : lam, scale : 1b0),
|
||||
[phi/degree,lam/degree,x,y,gam/degree,k0*scale])$
|
||||
|
||||
/* Gauss-Krueger series to order n^i forward
|
||||
|
||||
Uses the array functions
|
||||
|
||||
a1_a[i](n), zeta_a[i](z,n), zeta_d[i](z,n), zetap_a[i](s,n), zetap_d[i](s,n),
|
||||
|
||||
defined in tmseries.mac.
|
||||
*/
|
||||
|
||||
tms(phi,lam,i):=block([psi,xip,etap,z,sigma,sp,gam,k,b1],
|
||||
phi:phi*degree,
|
||||
lam:lam*degree,
|
||||
psi:psi_phi(phi),
|
||||
xip:atan2(snh(psi), cos(lam)),
|
||||
etap:asinh(sin(lam)/hypot(snh(psi),cos(lam))),
|
||||
k:sqrt(1 - e2*sin(phi)^2)/(cos(phi)*hypot(snh(psi),cos(lam))),
|
||||
gam:atan(tan(xip)*tanh(etap)),
|
||||
z:xip+%i*etap,
|
||||
b1:a1_a[i](n),
|
||||
sigma:rectform(b1*zeta_a[i](z,n)),
|
||||
sp:rectform(zeta_d[i](z,n)),
|
||||
gam : gam - atan2(imagpart(sp),realpart(sp)),
|
||||
k : k * b1 * cabs(sp),
|
||||
[imagpart(sigma)*k0*a,realpart(sigma)*k0*a,gam/degree,k*k0])$
|
||||
|
||||
/* Gauss-Krueger series to order n^i reverse */
|
||||
|
||||
lls(x,y,i):=block([sigma,b1,s,z,zp,xip,etap,s,c,r,gam,k,lam,psi,phi],
|
||||
sigma:y/(a*k0)+%i*x/(a*k0),
|
||||
b1:a1_a[i](n),
|
||||
s:rectform(sigma/b1),
|
||||
z:rectform(zetap_a[i](s,n)),
|
||||
zp:rectform(zetap_d[i](s,n)),
|
||||
gam : atan2(imagpart(zp), realpart(zp)),
|
||||
k : b1 / cabs(zp),
|
||||
xip:realpart(z),
|
||||
etap:imagpart(z),
|
||||
s:snh(etap),
|
||||
c:cos(xip),
|
||||
r:hypot(s, c),
|
||||
lam:atan2(s, c),
|
||||
psi : asinh(sin(xip)/r),
|
||||
phi :phi_psi(psi),
|
||||
k : k * sqrt(1 - e2*sin(phi)^2) * r/cos(phi),
|
||||
gam : gam + atan(tan(xip) * tanh(etap)),
|
||||
[phi/degree,lam/degree,gam/degree,k*k0])$
|
||||
|
||||
/* Approx geodesic distance valid for small displacements */
|
||||
|
||||
dist(phi0,lam0,phi,lam):=block([dphi,dlam,nn,hlon,hlat],
|
||||
dphi:(phi-phi0)*degree,
|
||||
dlam:(lam-lam0)*degree,
|
||||
phi0:phi0*degree,
|
||||
lam0:lam0*degree,
|
||||
nn : 1/sqrt(1 - e2 * sin(phi0)^2),
|
||||
hlon : cos(phi0) * nn,
|
||||
hlat : (1 - e2) * nn^3,
|
||||
a * hypot(dphi*hlat, dlam*hlon))$
|
||||
|
||||
/* Compute truncation errors for all truncation levels */
|
||||
|
||||
check(phi,lam):=block([vv,x,y,gam,k,vf,vb,errf,errr,err2,errlist],
|
||||
phi:min(90-0.01b0,phi),
|
||||
lam:min(90-0.01b0,lam),
|
||||
vv:tm(phi,lam),
|
||||
errlist:[],
|
||||
x:vv[1], y:vv[2], gam:vv[3], k:vv[4],
|
||||
for i:1 thru maxpow do (
|
||||
vf:tms(phi,lam,i),
|
||||
errf:hypot(vf[1]-x,vf[2]-y)/k,
|
||||
errfg:abs(vf[3]-gam),
|
||||
errfk:abs((vf[4]-k)/k),
|
||||
vb:lls(x,y,i),
|
||||
errr:dist(phi,lam,vb[1],vb[2]),
|
||||
errrg:abs(vb[3]-gam),
|
||||
errrk:abs((vb[4]-k)/k),
|
||||
errlist:append(errlist,
|
||||
[max(errf, errr), max(errfg, errrg), max(errfk, errrk)])),
|
||||
errlist)$
|
||||
|
||||
/* Max of output of check over a set of points */
|
||||
|
||||
checka(lst):=block([errlist:[],errx],
|
||||
for i:1 thru 3*maxpow do errlist:cons(0b0,errlist),
|
||||
for vv in lst do (
|
||||
errx:check(vv[1],vv[2]),
|
||||
for i:1 thru 3*maxpow do errlist[i]:max(errlist[i],errx[i])),
|
||||
errlist)$
|
||||
Reference in New Issue
Block a user