見出し画像

Pythonで3次メッシュコードを中心とした周囲のメッシュコードを生成する

この記事では、Pythonを使って3次メッシュコードを中心とした周囲のメッシュコードを生成する方法について解説します。メッシュコードは地理情報を扱う際に便利なコード体系で、日本では特に利用されています。以下のコードは、指定された3次メッシュコードを中心とした周囲のメッシュコードを生成する方法を示しています。

コードの概要

以下のコードは、8桁の3次メッシュコードを受け取り、そのメッシュコードを中心とした指定された範囲(n)の周囲のメッシュコードを生成します。

  • generate_surrounding_mesh3:8桁の3次メッシュコードを中心とした周囲のメッシュコードリストを生成する

    • decompose_mesh3_code:8桁の3次メッシュコードを受け取り、緯度と経度の部分に分解する

    • generate_surrounding_codes:指定された範囲(-nからnまで)のコードを生成する

      • calculate_mesh_code:3次メッシュの進法ルールに従って計算する

    • combine_lon_lat_codes:経度コードと緯度コードのリストを組み合わせてメッシュコードを生成する

# 8桁の3次メッシュコードを受け取り、緯度と経度の部分に分解する
def decompose_mesh3_code(mesh_code: str) -> str:
    # メッシュコードが8桁でない場合はエラーを発生させる
    if len(mesh_code) != 8:
        raise ValueError("メッシュコードは8桁である必要があります。")

    # 緯度部分を分解(上2桁 + 5桁目 + 7桁目)
    decompose_lat = mesh_code[:2] + mesh_code[4] + mesh_code[6]
    
    # 経度部分を分解(3-4桁目 + 6桁目 + 8桁目)
    decompose_lon = mesh_code[2:4] + mesh_code[5] + mesh_code[7]

    # 経度と緯度の分解結果を返す
    return decompose_lon, decompose_lat

# 3次メッシュの進法ルールに従って計算する
def calculate_mesh_code(decompose_code:str, value:int) -> str:
    if not len(decompose_code)==4:
        raise ValueError("入力値は4桁である必要があります。")

    # 上4桁は10進法
    value4 = int(decompose_code[3]) + value
    carry4 = value4 // 10
    calculate_code4 = str(value4 % 10)

    # 上3桁は8進法
    value3 = int(decompose_code[2]) + carry4
    carry3 = value3 // 8
    calculate_code3 = str(value3 % 8)

    # 上1~2桁は10進法
    calculate_code1_2 = str(int(decompose_code[:2]) + carry3)

    # 結果を結合する
    calculate_code = calculate_code1_2 + calculate_code3 + calculate_code4

    return calculate_code

# 指定された範囲(-nからnまで)のコードを生成する
def generate_surrounding_codes(decompose_code: str, n: int) -> list[str]:
    # 結果を格納するリスト
    calculate_codes = []
    # -nからnまでの範囲でループ
    for r in range(-1 * n, n + 1):
        # rが0の場合は元のコードをそのまま追加
        if r == 0:
            calculate_codes.append(decompose_code)
            continue
        
        # calculate_mesh_code関数を使ってコードを計算
        calculate_code = calculate_mesh_code(decompose_code, r)
        
        # 計算結果をリストに追加
        calculate_codes.append(calculate_code)

    # 計算されたコードのリストを返す
    return calculate_codes

# 経度コードと緯度コードのリストを組み合わせてメッシュコードを生成する
def combine_lon_lat_codes(surrounding_lon_codes: list[str], surrounding_lat_codes: list[str]) -> list[str]:
    # 結果を格納するリスト
    surrounding_mesh_codes = []
    
    # 経度コードのリストをループ
    for lon_code in surrounding_lon_codes:
        # 緯度コードのリストをループ
        for lat_code in surrounding_lat_codes:
            # 緯度と経度のコードを組み合わせてメッシュコードを生成
            surrounding_mesh_code = f"{lat_code[:2]}{lon_code[:2]}{lat_code[2]}{lon_code[2]}{lat_code[3]}{lon_code[3]}"
            # 生成されたメッシュコードをリストに追加
            surrounding_mesh_codes.append(surrounding_mesh_code)

    # 生成されたメッシュコードのリストを返す
    return surrounding_mesh_codes

# 8桁の3次メッシュコードを中心とした周囲のメッシュコードリストを生成する
def generate_surrounding_mesh3(mesh_code:str, n:int) -> list[str]:
    # 8桁の3次メッシュコードを受け取り、緯度と経度の部分に分解する
    decompose_lon, decompose_lat = decompose_mesh3_code(mesh_code)
    
    # 指定された範囲(-nからnまで)の経度コードを生成する
    surrounding_lon_codes = generate_surrounding_codes(decompose_lon, n)
    # 指定された範囲(-nからnまで)の緯度コードを生成する
    surrounding_lat_codes = generate_surrounding_codes(decompose_lat, n)
    
    # 経度コードと緯度コードのリストを組み合わせてメッシュコードを生成する
    surrounding_mesh3_codes = combine_lon_lat_codes(surrounding_lon_codes, surrounding_lat_codes)

    return surrounding_mesh3_codes

mesh_code = "53393599"
n = 2
surrounding_mesh3_codes = generate_surrounding_mesh3(mesh_code, n)

import numpy as np
np.flipud(np.array(surrounding_mesh3_codes).reshape((5, 5)).T)

# 出力結果
# array([['53394517', '53394518', '53394519', '53394610', '53394611'],
#        ['53394507', '53394508', '53394509', '53394600', '53394601'],
#        ['53393597', '53393598', '53393599', '53393690', '53393691'],
#        ['53393587', '53393588', '53393589', '53393680', '53393681'],
#        ['53393577', '53393578', '53393579', '53393670', '53393671']],
#       dtype='<U8')

コードの詳細

ここから詳細な解説をします。

3次メッシュコードの分解

まず、3次メッシュコードを緯度と経度の部分に分解する関数を定義します。

def decompose_mesh3_code(mesh_code: str) -> str:
    # メッシュコードが8桁でない場合はエラーを発生させる
    if len(mesh_code) != 8:
        raise ValueError("メッシュコードは8桁である必要があります。")

    # 緯度部分を分解(上2桁 + 5桁目 + 7桁目)
    decompose_lat = mesh_code[:2] + mesh_code[4] + mesh_code[6]

    # 経度部分を分解(3-4桁目 + 6桁目 + 8桁目)
    decompose_lon = mesh_code[2:4] + mesh_code[5] + mesh_code[7]

    # 経度と緯度の分解結果を返す
    return decompose_lon, decompose_lat

# 使用例
mesh_code = "53393599"
decompose_lon, decompose_lat = decompose_mesh3_code(mesh_code)
print(f"decompose_lon: {decompose_lon}, decompose_lat: {decompose_lat}")
# decompose_lon: 3959, decompose_lat: 5339

この関数は、8桁の3次メッシュコードを受け取り、緯度と経度の部分に分解して返します。

緯度部分の分解

次に、緯度部分を分解します。緯度部分は、メッシュコードの上2桁、5桁目、7桁目を組み合わせて作成します。

decompose_lat = mesh_code[:2] + mesh_code[4] + mesh_code[6]
  • mesh_code[:2]は、メッシュコードの上2桁を取得します。

  • mesh_code[4]は、メッシュコードの5桁目を取得します。

  • mesh_code[6]は、メッシュコードの7桁目を取得します。

経度部分の分解

次に、経度部分を分解します。経度部分は、メッシュコードの3-4桁目、6桁目、8桁目を組み合わせて作成します。

decompose_lon = mesh_code[2:4] + mesh_code[5] + mesh_code[7]
  • mesh_code[2:4]は、メッシュコードの3-4桁目を取得します。

  • mesh_code[5]は、メッシュコードの6桁目を取得します。

  • mesh_code[7]は、メッシュコードの8桁目を取得します。

特定の進法ルールに従った計算

以下のコードは、4桁の分解されたメッシュコード(decompose_code)に対して特定の値(value)を加算し、特定の進法ルールに従って計算します。

def calculate_mesh_code(decompose_code: str, value: int) -> str:
    if not len(decompose_code) == 4:
        raise ValueError("入力値は4桁である必要があります。")

    # 上4桁は10進法
    value4 = int(decompose_code[3]) + value
    carry4 = value4 // 10
    calculate_code4 = str(value4 % 10)

    # 上3桁は8進法
    value3 = int(decompose_code[2]) + carry4
    carry3 = value3 // 8
    calculate_code3 = str(value3 % 8)

    # 上1~2桁は10進法
    calculate_code1_2 = str(int(decompose_code[:2]) + carry3)

    # 結果を結合する
    calculate_code = calculate_code1_2 + calculate_code3 + calculate_code4

    return calculate_code

# 使用例
value2 = 3
result = calculate_mesh_code(decompose_lon, value2)
print(result) 
# 3962

上4桁の計算(10進法)

4桁目は3次メッシュコードに当たります。 4桁目にvalueを加算し、10進法で計算します。繰り上がりが発生する場合は次の桁に繰り上げます。

value4 = int(decompose_code[3]) + value
carry4 = value4 // 10
calculate_code4 = str(value4 % 10)
  • value4は、4桁目にvalueを加算した結果です。

  • carry4は、繰り上がりの値です。

  • calculate_code4は、4桁目の計算結果の1桁目を文字列として取得します。

上3桁の計算(8進法)

3桁目は2次メッシュコードに当たります。 3桁目に繰り上がりを加算し、8進法で計算します。繰り上がりが発生する場合は次の桁に繰り上げます。

value3 = int(decompose_code[2]) + carry4
carry3 = value3 // 8
calculate_code3 = str(value3 % 8)
  • value3は、3桁目に繰り上がりを加算した結果です。

  • carry3は、繰り上がりの値です。

  • calculate_code3は、3桁目の計算結果の1桁目を文字列として取得します。

上1~2桁の計算(10進法)

1~2桁目は1次メッシュコードに当たります。 次に、上1~2桁に繰り上がりを加算し、10進法で計算します。

calculate_code1_2 = str(int(decompose_code[:2]) + carry3)
  • calculate_code1_2は、上1~2桁に繰り上がりを加算した結果を文字列として取得します。

結果の結合

最後に、計算結果を結合して新しい4桁の数値を返します。

calculate_code = calculate_code1_2 + calculate_code3 + calculate_code4
return calculate_code

使用例

以下は、実際に4桁の分解されたメッシュコードに対して特定の値を加算して計算する例です。

value2 = 3
result = calculate_mesh_code(decompose_lon, value2)
print(result) 
# 3962

この例では、decompose_lonに対してvalue2を加算して計算しています。

周囲のコードを生成

以下のコードは、4桁の分解されたメッシュコード(decompose_code)に対して、指定された範囲(n)の周囲のコードを生成します。

def generate_surrounding_codes(decompose_code: str, n: int) -> list[str]:
    # 結果を格納するリスト
    calculate_codes = []
    # -nからnまでの範囲でループ
    for r in range(-1 * n, n + 1):
        # rが0の場合は元のコードをそのまま追加
        if r == 0:
            calculate_codes.append(decompose_code)
            continue

        # calculate_mesh_code関数を使ってコードを計算
        calculate_code = calculate_mesh_code(decompose_code, r)

        # 計算結果をリストに追加
        calculate_codes.append(calculate_code)

    # 計算されたコードのリストを返す
    return calculate_codes

# 使用例
n = 2
surrounding_lon_codes = generate_surrounding_codes(decompose_lon, n)
surrounding_lat_codes = generate_surrounding_codes(decompose_lat, n)
print(surrounding_lon_codes)
# ['3957', '3958', '3959', '3960', '3961']
print(surrounding_lat_codes)
# ['5337', '5338', '5339', '5340', '5341']

結果を格納するリストの初期化

まず、結果を格納するためのリストを初期化します。

calculate_codes = []

指定された範囲でループ

次に、指定された範囲(-nからnまで)でループを実行します。

for r in range(-1 * n, n + 1):
  • range(-1 * n, n + 1)は、-nからnまでの範囲を生成します。

元のコードをそのまま追加

ループ内で、rが0の場合は元のコードをそのままリストに追加します。

if r == 0:
    calculate_codes.append(decompose_code)
    continue

コードの計算

rが0でない場合は、calculate_mesh_code関数を使ってコードを計算します。

calculate_code = calculate_mesh_code(decompose_code, r)
  • calculate_mesh_code関数は、分解されたメッシュコードに対してrを加算して新しいコードを計算します。

計算結果をリストに追加

計算結果をリストに追加します。

calculate_codes.append(calculate_code)

計算されたコードのリストを返す

最後に、計算されたコードのリストを返します。

return calculate_codes

使用例

以下は、実際に4桁の分解されたメッシュコードに対して指定された範囲の周囲のコードを生成する例です。

n = 2
surrounding_lon_codes = generate_surrounding_codes(decompose_lon, n)
surrounding_lat_codes = generate_surrounding_codes(decompose_lat, n)
print(surrounding_lon_codes)
# ['3957', '3958', '3959', '3960', '3961']
print(surrounding_lat_codes)
# ['5337', '5338', '5339', '5340', '5341']

この例では、decompose_lonとdecompose_latに対して、範囲nの周囲のコードを生成しています。

経度と緯度のコードを組み合わせ

以下のコードは、経度コードと緯度コードのリストを受け取り、それらを組み合わせてメッシュコードを生成します。

def combine_lon_lat_codes(surrounding_lon_codes: list[str], surrounding_lat_codes: list[str]) -> list[str]:
    # 結果を格納するリスト
    surrounding_mesh_codes = []

    # 経度コードのリストをループ
    for lon_code in surrounding_lon_codes:
        # 緯度コードのリストをループ
        for lat_code in surrounding_lat_codes:
            # 緯度と経度のコードを組み合わせてメッシュコードを生成
            surrounding_mesh_code = f"{lat_code[:2]}{lon_code[:2]}{lat_code[2]}{lon_code[2]}{lat_code[3]}{lon_code[3]}"
            # 生成されたメッシュコードをリストに追加
            surrounding_mesh_codes.append(surrounding_mesh_code)

    # 生成されたメッシュコードのリストを返す
    return surrounding_mesh_codes

# 使用例
n = 2
surrounding_mesh3_codes = combine_lon_lat_codes(surrounding_lon_codes, surrounding_lat_codes)
print(surrounding_mesh3_codes)

# 出力結果
# ['53393577', '53393587', '53393597', '53394507', '53394517', 
# '53393578', '53393588', '53393598', '53394508', '53394518', 
# '53393579', '53393589', '53393599', '53394509', '53394519', 
# '53393670', '53393680', '53393690', '53394600', '53394610', 
# '53393671', '53393681', '53393691', '53394601', '53394611']

結果を格納するリストの初期化

まず、結果を格納するためのリストを初期化します。

surrounding_mesh_codes = []

経度コードのリストをループ

次に、経度コードのリストをループします。

for lon_code in surrounding_lon_codes:
  • surrounding_lon_codesは、周囲の経度コードのリストです。

緯度コードのリストをループ

経度コードのループ内で、緯度コードのリストをループします。

for lat_code in surrounding_lat_codes:
  • surrounding_lat_codesは、周囲の緯度コードのリストです。

緯度と経度のコードを組み合わせてメッシュコードを生成

緯度と経度のコードを組み合わせてメッシュコードを生成します。

surrounding_mesh_code = f"{lat_code[:2]}{lon_code[:2]}{lat_code[2]}{lon_code[2]}{lat_code[3]}{lon_code[3]}"
  • lat_code[:2]は、緯度コードの上2桁を取得します。(1次メッシュの緯度)

  • lon_code[:2]は、経度コードの上2桁を取得します。(1次メッシュの経度)

  • lat_code[2]は、緯度コードの3桁目を取得します。(2次メッシュの緯度)

  • lon_code[2]は、経度コードの3桁目を取得します。(2次メッシュの経度)

  • lat_code[3]は、緯度コードの4桁目を取得します。(3次メッシュの緯度)

  • lon_code[3]は、経度コードの4桁目を取得します。(3次メッシュの経度)

生成されたメッシュコードをリストに追加

生成されたメッシュコードをリストに追加します。

surrounding_mesh_codes.append(surrounding_mesh_code)

生成されたメッシュコードのリストを返す

最後に、生成されたメッシュコードのリストを返します。

return surrounding_mesh_codes

使用例

以下は、実際に経度コードと緯度コードのリストを組み合わせてメッシュコードを生成する例です。

n = 2
surrounding_mesh3_codes = combine_lon_lat_codes(surrounding_lon_codes, surrounding_lat_codes)
print(surrounding_mesh3_codes)

# 出力結果
# ['53393577', '53393587', '53393597', '53394507', '53394517', 
# '53393578', '53393588', '53393598', '53394508', '53394518', 
# '53393579', '53393589', '53393599', '53394509', '53394519', 
# '53393670', '53393680', '53393690', '53394600', '53394610', 
# '53393671', '53393681', '53393691', '53394601', '53394611']

この例では、surrounding_lon_codesとsurrounding_lat_codesを組み合わせてメッシュコードを生成しています。

周囲のメッシュコードリストを生成

最後に、8桁の3次メッシュコードを中心とした周囲のメッシュコードリストを生成する関数を定義します。

def generate_surrounding_mesh3(mesh_code: str, n: int) -> list[str]:
    # 8桁の3次メッシュコードを受け取り、緯度と経度の部分に分解する
    decompose_lon, decompose_lat = decompose_mesh3_code(mesh_code)

    # 指定された範囲(-nからnまで)の経度コードを生成する
    surrounding_lon_codes = generate_surrounding_codes(decompose_lon, n)
    # 指定された範囲(-nからnまで)の緯度コードを生成する
    surrounding_lat_codes = generate_surrounding_codes(decompose_lat, n)

    # 経度コードと緯度コードのリストを組み合わせてメッシュコードを生成する
    surrounding_mesh3_codes = combine_lon_lat_codes(surrounding_lon_codes, surrounding_lat_codes)

    return surrounding_mesh3_codes

# 使用例
mesh_code = "53393597"
n = 1
surrounding_mesh3_codes = generate_surrounding_mesh3(mesh_code, n)

import numpy as np
np.flipud(np.array(surrounding_mesh3_codes).reshape((5, 5)).T)

# 出力結果
# array([['53394517', '53394518', '53394519', '53394610', '53394611'],
#        ['53394507', '53394508', '53394509', '53394600', '53394601'],
#        ['53393597', '53393598', '53393599', '53393690', '53393691'],
#        ['53393587', '53393588', '53393589', '53393680', '53393681'],
#        ['53393577', '53393578', '53393579', '53393670', '53393671']],
#       dtype='<U8')

この関数は、指定された3次メッシュコードを中心とした周囲のメッシュコードを生成します。

まとめ

このコードは、8桁の3次メッシュコードを中心とした指定された範囲の周囲のメッシュコードを生成する方法を示しています。個人的に作りたかっただけです。


いいなと思ったら応援しよう!