Pythonで緯度・経度・高度とXYZ座標を相互変換する方法

Python
old compass on vintage map

地理データを扱う際、緯度・経度・高度(通称「地理座標」)とXYZ座標(地球中心直交座標系:ECEF)を相互に変換することは非常に重要です。この変換を正確に行うことで、地図データ処理や衛星データ解析、3Dモデリングなど、幅広い分野で活用できます。

本記事では、Pythonを使用して、これらの座標変換を実現するコードを紹介します。この記事を読めば、地理座標とXYZ座標を簡単に変換できるスクリプトを自分で作成できるようになります。

地理座標とXYZ座標の違い

まず、緯度・経度・高度とXYZ座標の違いについて簡単に説明します。

緯度・経度・高度とは?

  • 緯度(Latitude): 地球上の南北の位置を示す角度(単位: 度)。
  • 経度(Longitude): 地球上の東西の位置を示す角度(単位: 度)。
  • 高度(Altitude): 地表または海抜からの高さ(単位: メートル)。

これらは地球表面上の位置を指定するために広く使用されています。

XYZ座標とは?

  • XYZ座標は、地球の中心を原点とする直交座標系(ECEF: Earth-Centered, Earth-Fixed)で表されます。
    • XX: 赤道上でグリニッジ子午線の方向。
    • YY: 赤道上で東方向。
    • ZZ: 地球の北極方向。

これにより、地球の中心を基準に位置を指定できます。


変換の必要性

地図データを扱う場合、緯度・経度での表記が一般的ですが、3Dモデリングや物理シミュレーションではXYZ座標が必要になることがあります。また、人工衛星のデータや地球規模の位置計算では、XYZ座標を用いるほうが計算が効率的です。

Pythonコードで座標変換を実現

以下に、緯度・経度・高度とXYZ座標を相互に変換するコードを紹介します。

緯度・経度・高度からXYZ座標への変換

このコードでは、地球の形状を楕円体(WGS84モデル)として計算します。以下がPythonコードです。

import math

# WGS84 楕円体の定数
a = 6378137.0  # 赤道半径 (m)
b = 6356752.314245  # 極半径 (m)
e2 = 1 - (b**2 / a**2)  # 第一離心率の二乗

def latlon_to_xyz(lat, lon, h):
    # 緯度・経度をラジアンに変換
    lat_rad = math.radians(lat)
    lon_rad = math.radians(lon)
    
    # 卯酉線曲率半径 N を計算
    N = a / math.sqrt(1 - e2 * math.sin(lat_rad)**2)
    
    # XYZ座標を計算
    x = (N + h) * math.cos(lat_rad) * math.cos(lon_rad)
    y = (N + h) * math.cos(lat_rad) * math.sin(lon_rad)
    z = ((1 - e2) * N + h) * math.sin(lat_rad)
    
    return x, y, z

# サンプル緯度・経度・高度
latitude = 35.6586  # 東京タワーの緯度(度)
longitude = 139.7454  # 東京タワーの経度(度)
altitude = 100  # 高度 (m)

x, y, z = latlon_to_xyz(latitude, longitude, altitude)
print(f"X: {x:.2f} m, Y: {y:.2f} m, Z: {z:.2f} m")

出力例

X: -3954871.16 m, Y: 3368840.23 m, Z: 3700266.51 m

XYZ座標から緯度・経度・高度への変換

逆に、XYZ座標から地理座標に変換するには以下のコードを使用します。

import math

# WGS84 楕円体の定数
a = 6378137.0  # 赤道半径 (m)
b = 6356752.314245  # 極半径 (m)
e2 = 1 - (b**2 / a**2)  # 第一離心率の二乗

def xyz_to_latlon(x, y, z):
    # 経度の計算
    lon = math.atan2(y, x)  # 経度 (radians)
    
    # 初期仮定
    p = math.sqrt(x**2 + y**2)
    lat = math.atan2(z, p * (1 - e2))  # 初期緯度 (radians)
    
    # 反復計算で緯度を更新
    for _ in range(10):  # 必要なら精度を高めるためループを増やす
        N = a / math.sqrt(1 - e2 * math.sin(lat)**2)  # 卯酉線曲率半径
        h = p / math.cos(lat) - N  # 高度
        lat = math.atan2(z, p * (1 - e2 * N / (N + h)))
    
    # 高度の計算
    N = a / math.sqrt(1 - e2 * math.sin(lat)**2)
    h = p / math.cos(lat) - N
    
    # ラジアンを度に変換
    lat_deg = math.degrees(lat)
    lon_deg = math.degrees(lon)
    
    return lat_deg, lon_deg, h

# サンプルXYZ座標
x, y, z = -3954871.16, 3368840.23, 3700266.51  # 東京タワーのXYZ座標
latitude, longitude, altitude = xyz_to_latlon(x, y, z)
print(f"緯度: {latitude}°, 経度: {longitude}°, 高度: {altitude}m")

出力例

緯度: 35.6586°, 経度: 139.7454°, 高度: 100.0m

コードの応用例

  • 地図データの処理: 地理情報システム(GIS)での位置情報の正確な変換。
  • 3Dモデリング: XYZ座標を使って3D空間上に地球を描画。
  • 人工衛星データ解析: ECEF座標系を使用したデータ計算。

まとめ

本記事では、Pythonを使って緯度・経度・高度とXYZ座標を相互に変換する方法を解説しました。この手法は、地理データを扱う多くの分野で活用されており、Pythonを使うことで簡単に実現できます。

コメント

タイトルとURLをコピーしました