【Python】1～4次までの地域メッシュコードを計算する

# はじめに

緯度経度から、地域メッシュコードを1～4次まで計算するPythonのPGを作成しました。

# メッシュコードとは
緯度経度を基に四角の区域に分けたものです。交通量分析やPTでメッシュコード単位で分析をしているとよく出てきます。
詳細は下記を参照してください
- [総務省統計局　地域メッシュ統計の特質・沿革](https://www.stat.go.jp/data/mesh/pdf/gaiyo1.pdf)
- [地域メッシュまとめ](https://qiita.com/nkuchiii/items/a3a83d5a2cdd5d8d630c)

# 環境
- python  version 3.7.4
- windows10

# 実装
```python:test.py
# coding: UTF-8
# メッシュコード変換設定用変数
MILLISECOND = 3600000 # 計算の単位(ミリ秒)に変換して計算する

#*************************************************************************
# クラス一覧
#*************************************************************************
#*************************************************************************
# メッシュ変換用クラス
#*************************************************************************
class FirstGrid(object):
    def __init__(self, lat, lon):
        lat = float(lat)
        lon = float(lon)
        #1次メッシュコード計算
        self.lat = lat
        self.lon = lon
        # メッシュの高さ
        self.height_ms = MILLISECOND * (40 / 60)
        # メッシュの幅
        self.width_ms = MILLISECOND
        # メッシュコードの上位桁
        self.upper = int(math.floor(lat * 15 / 10))
        # メッシュコードの下位桁
        self.lower = int(math.floor(lon - 100))
        # 南端(緯度)
        self.south_ms = self.upper * MILLISECOND / 1.5
        # 西端(経度)
        self.west_ms = (self.lower + 100) * MILLISECOND
    def code(self):
        # メッシュコード
        return f"{self.upper}{self.lower}"
    def origin(self):
        # メッシュの南西端(緯度経度)
        return self.south_ms / MILLISECOND, self.west_ms / MILLISECOND
class Grid(FirstGrid):
    def __init__(self, parent, divide):
        # 2,3次メッシュコード計算
        self.lat = parent.lat
        self.lon = parent.lon
        lat_ms = parent.lat * MILLISECOND
        lon_ms = parent.lon * MILLISECOND
        
        # 親メッシュの高さと幅から当該メッシュの高さと幅を算出する
        self.height_ms = parent.height_ms / divide
        self.width_ms = parent.width_ms / divide
        h = self.height_ms
        w = self.width_ms
        # 上位桁
        self.upper = int(math.floor((lat_ms - parent.south_ms) / h))
        # 下位桁
        self.lower = int(math.floor((lon_ms - parent.west_ms) / w))
        # 南端
        self.south_ms = self.upper * h + parent.south_ms
        # 西端
        self.west_ms = self.lower * w + parent.west_ms
    def code(self):
        return f"{self.upper}{self.lower}"
    # 分割メッシュ用
    def scode(self):
        return (self.upper * 2) + self.lower + 1
    def origin(self):
        return self.south_ms / MILLISECOND, self.west_ms / MILLISECOND

#*************************************************************************
# 関数一覧
#*************************************************************************
#*************************************************************************
# LatLon2Code(緯度,経度)
#
# 処理内容：緯度経度[度ddd.ddd]から地域メッシュコードを算出する
#     引数：(I)[float]lat
#         ：(I)[float]lon
#         ：(i)[int]order
#         ：(r)[string]MESHCODE
#*************************************************************************
def LatLon2Code(lat, lon, order):
    # 1次メッシュの計算
    f = FirstGrid(lat, lon)
    # 2次メッシュは1次メッシュを8分割する
    s = Grid(f, 8)
    # 3次メッシュは2次メッシュを10分割する
    t = Grid(s, 10)
    # 4次メッシュは3次メッシュを2分割する
    fth = Grid(t, 2)
    if (order == 1):
        return f"{f.code()}"
    elif (order == 2):
        return f"{f.code()}{s.code()}"
    elif (order == 3):
        return f"{f.code()}{s.code()}{t.code()}"
    elif (order == 4):
        return f"{f.code()}{s.code()}{t.code()}{fth.scode()}"

```
# 使い方
引数として下記を与えれば、対応するメッシュコードを返り値として渡します
`LatLon2Code([LAT],[LON], [N])`

 | 引数名 | 入力内容 |
|:-:|:-:|
|LAT|   緯度|
|LON| 経度  |
|N|取得したいメッシュコード（例：4次メッシュコードなら、「4」）|

:::note warn
緯度経度の小数点以下の桁数が不十分だと、異なるメッシュコードになります（Pythonだと型を意識していないと桁落ちする。。。。）。
関数中では、floatでなるべく桁落ちがしないようにしていますが注意してください。
:::

# 参考
- [Python を使って地域メッシュコードから緯度経度ポリゴンを算出する](https://glassonion.hatenablog.com/entry/2019/05/02/183027)