LoginSignup
1
2

楕円弧長計算

Last updated at Posted at 2014-10-30

こんにちは。
楕円弧長は、下記の第二種不完全楕円積分で表されます。与えられた緯度に対し赤道からの子午線弧長です。

プログラムでは小さい扁平率を仮定し、倍精度浮動小数点数に現れない$n^7$(第三扁平率の冪乗)以上の級数展開項は近似で切り捨てています。このベッセルの級数式は優れた収束ですね。これの級数係数の計算については分数の表示(リスト)。参考:https://en.wikipedia.org/wiki/Meridian_arc#Expansions_in_the_third_flattening_.28n.29

\textrm{An elliptic arc length formula from a modification of Bessel (1825)}\\
\begin{aligned}
m(\varphi) &= \int_0^\varphi M(\varphi) d\varphi \\ 
 &=\frac{a}{1+n}\left( \int_0^\varphi \sqrt{1+2n\cos2\varphi+n^2} \, d\varphi - \frac{2n \sin2\varphi}{\sqrt{1 + 2n \cos2\varphi + n^2}} \right) \\
 &=\frac{a}{1+n}\left( c_0 \, \varphi + \sum_{l=1}^\infty c_l \, l^{-1}  \sin 2 l \varphi - \frac{2n \sin2\varphi}{\sqrt{1 + 2n \cos2\varphi + n^2}} \right) \\
M(\varphi) &= \frac{a(1-e^2)}{(1-e^2\sin^2\varphi)^{3/2}} \\
e^2 &= \frac{4 n}{\left(1+n\right)^2} \\
c_l &= n^l \sum_{j=0}^\infty n^{2j} \binom{1/2}{j} \, \binom{1/2}{j+l}  
\end{aligned}
import math
DEGREE = math.pi / 180
PIHALF = math.pi / 2

# Bessel (1825); elliptic (meridian) arc; incomplete integral
def meridanArc(lat, n):
    n2 = n * n
    coef = [1, 1/4., 1/64., 1/256.]
    ma = lat * poly(n2, coef)
    if lat != PIHALF:  # PIHALF: complete integral
        coef = [[1/2., -1/16., -1/128.], [-1/16., 1/64., 5/2048.], [1/48., -5/768.], [-5/512., 7/2048.], [7/1280.], [-7/2048.],]
        nn, cs, cslat2 = 1, csmake(0), csmake(lat*2)
        for c in coef:
            nn *= n  # n**(i+1)
            cs = csadd(cs, cslat2)  # cos(lat*2*(i+1))
            ma += nn * cs['sin'] * poly(n2, c)
        ma -= 2*n*cslat2['sin']/math.sqrt(1+2*n*cslat2['cos']+n2)
    return ma / (1 + n)

def poly(x, coef):
    sum = 0.0
    for a in coef[::-1]:
        sum = a + sum * x
    return sum

def csmake(arg):
    c, s = math.cos(arg), math.sin(arg)
    return {'cos': c, 'sin': s}

def csadd(cs1, cs2):
    c = cs1['cos']*cs2['cos'] - cs1['sin']*cs2['sin']
    s = cs1['sin']*cs2['cos'] + cs1['cos']*cs2['sin']
    return {'cos': c, 'sin': s}

def main():
    RE = 6378137.0  # GRS80
    f = 1/298.257222101  # GRS80
    n = f / (2 - f)   # the third flattening
    for lat in range(0,100,10):
        ma = meridanArc(lat*DEGREE, n)
        print "%4.1f degree: %12.3f m" % (lat, RE*ma)

出力結果

 0.0 degree:        0.000 m
10.0 degree:  1105854.833 m
20.0 degree:  2212366.254 m
30.0 degree:  3320113.398 m
40.0 degree:  4429529.030 m
50.0 degree:  5540847.042 m
60.0 degree:  6654072.819 m
70.0 degree:  7768980.728 m
80.0 degree:  8885139.872 m
90.0 degree: 10001965.729 m
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2