File: tmseries.mac

package info (click to toggle)
geographiclib 2.7-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,572 kB
  • sloc: cpp: 27,765; sh: 5,463; makefile: 695; python: 12; ansic: 10
file content (220 lines) | stat: -rw-r--r-- 7,462 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/*
Compute series approximations for Transverse Mercator Projection

Copyright (c) Charles Karney (2009-2010) <karney@alum.mit.edu> 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

Compute coefficient for forward and inverse trigonometric series for
conversion from conformal latitude to rectifying latitude.  This prints
out assignments which with minor editing are suitable for insertion into
C++ code.  (N.B. n^3 in the output means n*n*n; 3/5 means 0.6.)

To run, start maxima and enter

    writefile("tmseries.out")$
    load("tmseries.mac")$
    closefile()$

With maxpow = 6, the output (after about 5 secs) is

A=a/(n+1)*(1+n^2/4+n^4/64+n^6/256);
alpha[1]=n/2-2*n^2/3+5*n^3/16+41*n^4/180-127*n^5/288+7891*n^6/37800;
alpha[2]=13*n^2/48-3*n^3/5+557*n^4/1440+281*n^5/630-1983433*n^6/1935360;
alpha[3]=61*n^3/240-103*n^4/140+15061*n^5/26880+167603*n^6/181440;
alpha[4]=49561*n^4/161280-179*n^5/168+6601661*n^6/7257600;
alpha[5]=34729*n^5/80640-3418889*n^6/1995840;
alpha[6]=+212378941*n^6/319334400;
beta[1]=n/2-2*n^2/3+37*n^3/96-n^4/360-81*n^5/512+96199*n^6/604800;
beta[2]=n^2/48+n^3/15-437*n^4/1440+46*n^5/105-1118711*n^6/3870720;
beta[3]=17*n^3/480-37*n^4/840-209*n^5/4480+5569*n^6/90720;
beta[4]=4397*n^4/161280-11*n^5/504-830251*n^6/7257600;
beta[5]=4583*n^5/161280-108847*n^6/3991680;
beta[6]=+20648693*n^6/638668800;

Notation of output matches that of

 L. Krueger,
 Konforme Abbildung des Erdellipsoids in der Ebene
 Royal Prussian Geodetic Institute, New Series 52, 172 pp. (1912).

with gamma replaced by alpha.

Alter maxpow to generate more or less terms for the series
approximations to the forward and reverse projections.  This has been
tested out to maxpow = 30; but this takes a long time (see below).

*/

/* Timing:
  maxpow  time
    4      2s
    6      5s
    8     11s
   10     24s
   12     52s
   20    813s = 14m
   30  13535s = 226m
*/

maxpow:8$ /* Max power for forward and reverse projections */
/* Notation

   e = eccentricity
   e2 = e^2 = f*(2-f)
   n = third flattening = f/(2-f)
   phi = (complex) geodetic latitude
   zetap = Gauss-Schreiber TM = complex conformal latitude
   psi = Mercator = complex isometric latitude
   zeta = scaled UTM projection = complex rectifying latitude
*/

taylordepth:6$
triginverses:'all$
/*
    revert
       var2 = expr(var1) = series in eps
    to
       var1 = revertexpr(var2) = series in eps

Require that expr(var1) = var1 to order eps^0.  This throws in a
trigreduce to convert to multiple angle trig functions.
*/
reverta(expr,var1,var2,eps,pow):=block([tauacc:1,sigacc:0,dsig],
  dsig:ratdisrep(taylor(expr-var1,eps,0,pow)),
  dsig:subst([var1=var2],dsig),
  for n:1 thru pow do (tauacc:trigreduce(ratdisrep(taylor(
    -dsig*tauacc/n,eps,0,pow))),
    sigacc:sigacc+expand(diff(tauacc,var2,n-1))),
  var2+sigacc)$

/* Expansion for atan(x+eps) for small eps.  Equivalent to
   taylor(atan(x + eps), eps, 0, maxpow) but tidied up a bit.
 */
atanexp(x,eps):=''(ratdisrep(taylor(atan(x+eps),eps,0,maxpow)))$

/* Convert from n to e^2 */
e2:4*n/(1+n)^2$

/* zetap in terms of phi.  The expansion of
   atan(sinh( asinh(tan(phi)) + e * atanh(e * sin(phi)) ))
*/
zetap_phi:block([psiv,tanzetap,zetapv,qq,e],
    /* Here qq = atanh(sin(phi)) = asinh(tan(phi)) */
    psiv:qq-e*atanh(e*tanh(qq)),
    psiv:subst([e=sqrt(e2),qq=atanh(sin(phi))],
      ratdisrep(taylor(psiv,e,0,2*maxpow)))
    +asinh(sin(phi)/cos(phi))-atanh(sin(phi)),
    tanzetap:subst([abs(cos(phi))=cos(phi),sqrt(sin(phi)^2+cos(phi)^2)=1],
      ratdisrep(taylor(sinh(psiv),n,0,maxpow)))+tan(phi)-sin(phi)/cos(phi),
    zetapv:atanexp(tan(phi),tanzetap-tan(phi)),
    zetapv:subst([cos(phi)=sqrt(1-sin(phi)^2),
      tan(phi)=sin(phi)/sqrt(1-sin(phi)^2)],
      (zetapv-phi)/cos(phi))*cos(phi)+phi,
    zetapv:ratdisrep(taylor(zetapv,n,0,maxpow)),
    expand(trigreduce(zetapv)))$

/* phi in terms of zetap */
phi_zetap:reverta(zetap_phi,phi,zetap,n,maxpow)$

/* Mean radius of meridian */
a1:expand(integrate(
      ratdisrep(taylor((1+n)*(1-e2)/(1-e2*sin(phi)^2)^(3/2),
          n,0,maxpow)),
      phi, 0, %pi/2)/(%pi/2))/(1+n)$

/* zeta in terms of phi.  The expansion of
   zeta = pi/(2*a1) * int( (1-e^2)/(1-e^2*sin(phi)^2)^(3/2) )
*/
zeta_phi:block([zetav],
    zetav:integrate(trigreduce(ratdisrep(taylor(
            (1-e2)/(1-e2*sin(phi)^2)^(3/2)/a1,
            n,0,maxpow))),phi),
    expand(zetav))$

/* phi in terms of zeta */
phi_zeta:reverta(zeta_phi,phi,zeta,n,maxpow)$

/* zeta in terms of zetap */
/* This is slow.  The next version speeds it up a little.
zeta_zetap:expand(trigreduce(ratdisrep(
        taylor(subst([phi=phi_zetap],zeta_phi),n,0,maxpow))))$
*/
zeta_zetap:block([phiv:phi_zetap,zetav:expand(zeta_phi),acc:0],
    for i:0 thru maxpow do (
      phiv:ratdisrep(taylor(phiv,n,0,maxpow-i)),
      acc:acc + expand(n^i * trigreduce(ratdisrep(taylor(
              subst([phi=phiv],coeff(zetav,n,i)),n,0,maxpow-i))))),
    acc)$

/* zetap in terms of zeta */
/* This is slow.  The next version speeds it up a little.
zetap_zeta:expand(trigreduce(ratdisrep(
        taylor(subst([phi=phi_zeta],zetap_phi),n,0,maxpow))))$
*/
zetap_zeta:block([phiv:phi_zeta,zetapv:expand(zetap_phi),acc:0],
    for i:0 thru maxpow do (
      phiv:ratdisrep(taylor(phiv,n,0,maxpow-i)),
      acc:acc + expand(n^i * trigreduce(ratdisrep(taylor(
              subst([phi=phiv],coeff(zetapv,n,i)),n,0,maxpow-i))))),
    acc)$

printa1():=block([],
  print(concat("A=",string(a/(n+1)),"*(",
      string(taylor(a1*(1+n),n,0,maxpow)),");")),
  0)$
printtxf():=block([alpha:zeta_zetap,t],
  for i:1 thru maxpow do (t:coeff(alpha,sin(2*i*zetap)),
    print(concat("alpha[",i,"]=",string(taylor(t,n,0,maxpow)),";")),
    alpha:alpha-expand(t*sin(2*i*zetap))),
/* should return zero */
  alpha:alpha-zetap)$
printtxr():=block([beta:zetap_zeta,t],
  for i:1 thru maxpow do (t:coeff(beta,sin(2*i*zeta)),
    print(concat("beta[",i,"]=",string(taylor(-t,n,0,maxpow)),";")),
    beta:beta-expand(t*sin(2*i*zeta))),
/* should return zero */
  beta:beta-zeta)$

printseries():=[printa1(),printtxf(),printtxr()]$

/* Define array functions which are be read by tm.mac */
defarrayfuns():=block([aa:a1*(1+n),alpha:zeta_zetap,beta:zetap_zeta,t],
  for i:1 thru maxpow do (
    define(a1_a[i](n),ratdisrep(taylor(aa,n,0,i))/(1+n)),
    t:expand(ratdisrep(taylor(alpha,n,0,i))),
    define(zeta_a[i](zp,n),
      zp+sum(coeff(t,sin(2*k*zetap))*sin(2*k*zp),k,1,i)),
    t:diff(t,zetap),
    define(zeta_d[i](zp,n),
      1+sum(coeff(t,cos(2*k*zetap))*cos(2*k*zp),k,1,i)),
    t:expand(ratdisrep(taylor(beta,n,0,i))),
    define(zetap_a[i](z,n),
      z+sum(coeff(t,sin(2*k*zeta))*sin(2*k*z),k,1,i)),
    t:diff(t,zeta),
    define(zetap_d[i](z,n),
      1+sum(coeff(t,cos(2*k*zeta))*cos(2*k*z),k,1,i))))$

printseries()$
(b1:a1,
  for i:1 thru maxpow do (alp[i]:coeff(zeta_zetap,sin(2*i*zetap)),
    bet[i]:coeff(expand(-zetap_zeta),sin(2*i*zeta))))$
load("polyprint.mac")$
printtm():=block([macro:GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER],
  value1('(b1*(1+n)),'n,2,0),
  array1('alp,'n,1,0),
  array1('bet,'n,1,0))$
printtm()$
/*
defarrayfuns()$
save("tmseries.lsp",maxpow,arrays)$
*/