diff --git a/.vscode/settings.json b/.vscode/settings.json index 32c8f3a..a0e76ff 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,6 @@ { - "python.formatting.provider": "black", - "editor.formatOnSave": true + "[python]": { + "editor.defaultFormatter": "ms-python.black-formatter", + "editor.formatOnSave": true + } } \ No newline at end of file diff --git a/dev-requirements.txt b/dev-requirements.txt index 600538a..d7d464c 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -40,7 +40,7 @@ pluggy==1.0.0 plyfile==1.0.1 psutil==5.9.5 psycopg2-binary==2.9.7 -py3dtiles==6.0.0 +git+https://gitlab.com/Oslandia/py3dtiles.git@489289d2f7310fbcb8e95710e250d893999adf5d#egg=py3dtiles Pygments==2.15.1 pyproj==3.6.1 pyproject_hooks==1.0.0 diff --git a/doc/plateauutils.citygmlfinder.rst b/doc/plateauutils.citygmlfinder.rst index 807c2d7..620df2d 100644 --- a/doc/plateauutils.citygmlfinder.rst +++ b/doc/plateauutils.citygmlfinder.rst @@ -2,7 +2,7 @@ plateauutils.citygmlfinder パッケージ ====================================== plateauutils.citygmlfinder.from_reearth_cms モジュール --------------------------------------------------- +------------------------------------------------------- .. automodule:: plateauutils.citygmlfinder.from_reearth_cms :members: diff --git a/plateauutils/abc/numpy_tile_parser.py b/plateauutils/abc/numpy_tile_parser.py index daab502..98bf541 100644 --- a/plateauutils/abc/numpy_tile_parser.py +++ b/plateauutils/abc/numpy_tile_parser.py @@ -17,17 +17,28 @@ def _parse_tile(self): tile_list = self.__make_tile_list() lons = [] # 経度 lats = [] # 緯度 - maps = [] # 標高 + dems = [] # 標高 + classifications = [] # 属性値 # それぞれのタイルをパース for tile in tile_list: t = np.load(tile) lons.append(t["lons"]) lats.append(t["lats"]) - map = t["map"] - # 標高がnanの場合は0にする - map[np.isnan(map)] = 0 - maps.append(map) - return np.concatenate(lons), np.concatenate(lats), np.concatenate(maps) + dems.append(t["dem"]) + classifications.append(t["classification"]) + # np.arrayに変換 + np_lons, np_lats, np_dems, np_classifications = ( + np.concatenate(lons), + np.concatenate(lats), + np.concatenate(dems), + np.concatenate(classifications), + ) + # nanを除去 + np_lons = np_lons[~np.isnan(np_dems)] + np_lats = np_lats[~np.isnan(np_dems)] + np_classifications = np_classifications[~np.isnan(np_dems)] + np_dems = np_dems[~np.isnan(np_dems)] + return np_lons, np_lats, np_dems, np_classifications def __make_tile_list(self): """タイルのリストを作成するメソッド""" diff --git a/plateauutils/flood_converter/flood_to_3dtiles.py b/plateauutils/flood_converter/flood_to_3dtiles.py index 3a9693e..b60fa9c 100644 --- a/plateauutils/flood_converter/flood_to_3dtiles.py +++ b/plateauutils/flood_converter/flood_to_3dtiles.py @@ -27,7 +27,7 @@ def convert( """ # xyzファイルを作成 xyz = FloodToXyz(path).parse() - tmp = tempfile.mktemp(suffix=".xyz") + tmp = tempfile.mktemp(suffix=".csv") # 一時ファイルにxyzを書き込み with open(tmp, "w") as f: f.write(xyz) diff --git a/plateauutils/flood_converter/flood_to_png.py b/plateauutils/flood_converter/flood_to_png.py index dc50232..036181f 100644 --- a/plateauutils/flood_converter/flood_to_png.py +++ b/plateauutils/flood_converter/flood_to_png.py @@ -26,49 +26,50 @@ def parse(self, output_dir: str = ""): output_dir : str pngの出力先 """ - # lontitude, latitude, altitudeを取得 - lons, lats, maps = self._parse_tile() - # storeを作成 - store = Store() - # storeのaddメソッドをベクトル化 - vfunc = np.vectorize(store.add) - # storeにlontitude, latitude, altitudeを追加 - vfunc(lons, lats, maps) - # pngを書き出す - writer = PngWriter(output_dir, 15) - writer.setStore(store) - writer.write() + # lontitude, latitude, classificationsを取得 + lons, lats, _, classifications = self._parse_tile() + # ズームレベル8から15までのpngを作成 + for zoom in range(8, 16): + # storeを作成 + store = Store(zoom) + # storeのaddメソッドをベクトル化 + vfunc = np.vectorize(store.add) + # storeにlontitude, latitude, classificationsを追加 + vfunc(lons, lats, classifications) + # pngを書き出す + writer = PngWriter(output_dir, zoom) + writer.setStore(store) + writer.write() class Store(object): """タイルの座標及び標高を保持するクラス""" - def __init__(self): - self.zoom = 15 + def __init__(self, zoom): + self.zoom = zoom self.storage = dict() - def add(self, x, y, z): + def add(self, x, y, classification): """タイルの座標及び標高を格納するメソッド""" - longitude, latitude, altitude = x, y, z + longitude, latitude = x, y # 座標からタイルの座標とタイル内の座標を取得 x, y, pos_x, pos_y = self._coordinate_to_position(longitude, latitude) # storageに格納 - self._insert(x, y, pos_x, pos_y, altitude) + self._insert(x, y, pos_x, pos_y, classification) - def _insert(self, x, y, pos_x, pos_y, altitude): + def _insert(self, x, y, pos_x, pos_y, classification): # keyがstorageに存在する場合はその値を取得 key = (x, y) if key in self.storage.keys(): array = self.storage[key] else: # 存在しない場合は256*256の配列を作成 - array = np.zeros((256, 256)) - array.fill(-np.inf) + array = np.zeros((256, 256), dtype=np.int32) self.storage[key] = array # 標高を格納 current = array[pos_x][pos_y] - if current < altitude: - array[pos_x][pos_y] = altitude + if current < classification: + array[pos_x][pos_y] = classification self.storage[key] = array def _coordinate_to_position(self, longitude, latitude): @@ -157,55 +158,50 @@ def _write(self, x, y, value): sys.exit(-1) # 標高をpngに変換 dt = np.dtype( - {"names": ["r", "g", "b"], "formats": [np.uint8, np.uint8, np.uint8]} + { + "names": ["r", "g", "b", "a"], + "formats": [np.uint8, np.uint8, np.uint8, np.uint8], + } ) converted1 = np.array( - [tuple(self._dem_to_png(v)) for v in value.reshape(value.size)], dtype=dt + [tuple(self._classification_to_png(v)) for v in value.reshape(value.size)], + dtype=dt, ) converted2 = converted1.reshape(value.shape) filename = f"{self.directory}/{self.zoom}/{x}/{y}.png" width = 256 - img = Image.new("RGB", (width, width), (128, 0, 0)) + img = Image.new("RGBA", (width, width), (128, 0, 0, 0)) draw = ImageDraw.Draw(img) for i in range(0, width): for j in range(0, width): p = converted2[i][j] - draw.point([(i, j)], (int(p[0]), int(p[1]), int(p[2]))) + draw.point([(i, j)], (int(p[0]), int(p[1]), int(p[2]), int(p[3]))) img.save(filename) - def _dem_to_png(self, dem): - # 標高をPNGのRGBに変換するメソッド - # 内容が入っていなかったら白色 - if dem == -np.inf: - return (0xFF, 0xFF, 0xFF) - # 標高に応じて色を変更 - if dem > 20: - # 185 26 248 - return (0xB9, 0x1A, 0xF8) - if dem > 10: - # 169 8 91 - return (0xA9, 0x08, 0x5B) - if dem > 5: - # 253 35 21 - return (0xFD, 0x23, 0x15) - if dem > 4: - # 236 106 141 - return (0xEC, 0x6A, 0x8D) - if dem > 3: - # 254 115 117 - return (0xFE, 0x73, 0x75) - if dem > 2: - # 236 182 182 - return (0xEC, 0xB6, 0xB6) - if dem > 1: - # 255 141 36 - return (0xFF, 0x8D, 0x24) - if dem > 0.3: - # 255 225 53 - return (0xFF, 0xE1, 0x35) - if dem > 0.01: - # 48 254 55 - return (0x30, 0xFE, 0x37) - # 0.01以下は白色 + def _classification_to_png(self, classification): + # 属性をPNGのRGBに変換するメソッド + # 内容が入っていなかったら透明色 + if classification == 0: + return (0xFF, 0xFF, 0xFF, 0x00) + # 属性に応じて色を変更 + if classification == 6: + # 220 122 220 + return (0xDC, 0x7A, 0xDC, 0xFF) + if classification == 5: + # 242 133 201 + return (0xF2, 0x85, 0xC9, 0xFF) + if classification == 4: + # 255 145 145 + return (0xFF, 0x91, 0x91, 0xFF) + if classification == 3: + # 255 183 183 + return (0xFF, 0xB7, 0xB7, 0xFF) + if classification == 2: + # 255 216 192 + return (0xFF, 0xD8, 0xC0, 0xFF) + if classification == 1: + # 247 245 169 + return (0xF7, 0xF5, 0xA9, 0xFF) + # 例外は透明色 # 255 255 255 - return (0xFF, 0xFF, 0xFF) + return (0xFF, 0xFF, 0xFF, 0x00) diff --git a/plateauutils/flood_converter/flood_to_xyz.py b/plateauutils/flood_converter/flood_to_xyz.py index 3f7e39e..f7c9b66 100644 --- a/plateauutils/flood_converter/flood_to_xyz.py +++ b/plateauutils/flood_converter/flood_to_xyz.py @@ -1,3 +1,4 @@ +import numpy as np import pandas as pd from plateauutils.abc.numpy_tile_parser import NumpyTileParser @@ -16,7 +17,23 @@ def __init__(self, path: str = ""): def parse(self): """洪水浸水域をxyzに変換するメソッド""" - lons, lats, maps = self._parse_tile() - # xyzファイルを作成, 並びはlatitude, longitude, altitude - df = pd.DataFrame({"lat": lats, "lon": lons, "map": maps}) - return df.to_csv(index=False, header=False, sep=" ") + lons, lats, dems, classifications = self._parse_tile() + # IRGB値を作成 + i_values = np.ones_like(dems, dtype=np.int32) * 1 + r_values = np.ones_like(dems, dtype=np.int32) * 0 + g_values = np.ones_like(dems, dtype=np.int32) * 191 + b_values = np.ones_like(dems, dtype=np.int32) * 255 + # xyzファイルを作成, 並びはlatitude, longitude, altitude, i, r, g, b, classification + df = pd.DataFrame( + { + "lat": lats, + "lon": lons, + "dem": dems, + "i": i_values, + "r": r_values, + "g": g_values, + "b": b_values, + "classification": classifications, + } + ) + return df.to_csv(index=False, header=True, sep=" ") diff --git a/plateauutils/flood_converter/tests/fixtures/15/28264/13160.npz b/plateauutils/flood_converter/tests/fixtures/15/28264/13160.npz index b31fb2e..1f9b630 100644 Binary files a/plateauutils/flood_converter/tests/fixtures/15/28264/13160.npz and b/plateauutils/flood_converter/tests/fixtures/15/28264/13160.npz differ diff --git a/plateauutils/flood_converter/tests/test_flood_to_3dtiles.py b/plateauutils/flood_converter/tests/test_flood_to_3dtiles.py index a6673ac..3c96471 100644 --- a/plateauutils/flood_converter/tests/test_flood_to_3dtiles.py +++ b/plateauutils/flood_converter/tests/test_flood_to_3dtiles.py @@ -22,4 +22,4 @@ def test_convert(tmp_dir: str): assert Path(tmp_dir, "tileset.json").exists() assert Path(tmp_dir, "r.pnts").exists() tileset_path = tmp_dir / "tileset.json" - assert 256 * 256 == number_of_points_in_tileset(tileset_path) + assert 62615 == number_of_points_in_tileset(tileset_path) diff --git a/plateauutils/flood_converter/tests/test_flood_to_xyz.py b/plateauutils/flood_converter/tests/test_flood_to_xyz.py index 52697cb..b3fce55 100644 --- a/plateauutils/flood_converter/tests/test_flood_to_xyz.py +++ b/plateauutils/flood_converter/tests/test_flood_to_xyz.py @@ -18,3 +18,4 @@ def test_convert(tmp_dir: str): flood_to_png = FloodToPng(str(DATA_DIRECTORY)) flood_to_png.parse(output_dir=str(tmp_dir)) assert Path(tmp_dir, "15/28264/13160.png").exists() + assert Path(tmp_dir, "8/220/102.png").exists() diff --git a/pyproject.toml b/pyproject.toml index cc52867..ded3536 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,13 +11,13 @@ classifiers = [ "Development Status :: 2 - Pre-Alpha", "Programming Language :: Python :: 3", ] -version = "0.0.12" +version = "0.0.13" dependencies = [ "click", "numpy", "pandas", "Pillow", - "py3dtiles", + "py3dtiles @ git+https://gitlab.com/Oslandia/py3dtiles.git@489289d2f7310fbcb8e95710e250d893999adf5d", "pyproj", "requests", "reearthcmsapi", @@ -34,6 +34,9 @@ keywords = ['plateau'] [tool.hatch.build] exclude = ["tests/*"] +[tool.hatch.metadata] +allow-direct-references = true + [project.urls] "Homepage" = "https://eukarya-inc.github.io/plateauutils/" "Bug Reports" = "https://github.com/eukarya-inc/plateauutils/issues" diff --git a/requirements.txt b/requirements.txt index 88be88e..6a15357 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ reearthcmsapi==0.0.3 numpy==1.22.4 pandas==2.1.0 Pillow==10.0.1 -py3dtiles==6.0.0 +git+https://gitlab.com/Oslandia/py3dtiles.git@489289d2f7310fbcb8e95710e250d893999adf5d#egg=py3dtiles pyproj==3.6.1 requests==2.31.0 shapely==2.0.1