Initial import of NavSea pbf project
This commit is contained in:
118
navsea_mvt_to_geojson.py
Normal file
118
navsea_mvt_to_geojson.py
Normal file
@@ -0,0 +1,118 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import math
|
||||
from pathlib import Path
|
||||
|
||||
import mapbox_vector_tile
|
||||
|
||||
|
||||
INPUT_ROOT = Path("/home/wwwroot/newpec/exported_auto/tile.mapple-on.jp__newpec-mvt-20260106__z___x___y_.pbf/tiles")
|
||||
OUTPUT_ROOT = Path("/home/wwwroot/newpec/exported_auto/geojson_linux")
|
||||
|
||||
|
||||
def tile_coord_to_lonlat(z: int, x: int, y: int, tx: float, ty: float, extent: int) -> list[float]:
|
||||
lon = ((x + (tx / extent)) / (2**z)) * 360.0 - 180.0
|
||||
lat = math.degrees(
|
||||
math.atan(
|
||||
math.sinh(
|
||||
math.pi * (1.0 - (2.0 * (y + (ty / extent)) / (2**z)))
|
||||
)
|
||||
)
|
||||
)
|
||||
return [lon, lat]
|
||||
|
||||
|
||||
def convert_geometry(geometry: dict, z: int, x: int, y: int, extent: int) -> dict:
|
||||
geom_type = geometry["type"]
|
||||
coords = geometry["coordinates"]
|
||||
|
||||
if geom_type == "Point":
|
||||
return {"type": "Point", "coordinates": tile_coord_to_lonlat(z, x, y, coords[0], coords[1], extent)}
|
||||
if geom_type == "MultiPoint":
|
||||
return {
|
||||
"type": "MultiPoint",
|
||||
"coordinates": [tile_coord_to_lonlat(z, x, y, px, py, extent) for px, py in coords],
|
||||
}
|
||||
if geom_type == "LineString":
|
||||
return {
|
||||
"type": "LineString",
|
||||
"coordinates": [tile_coord_to_lonlat(z, x, y, px, py, extent) for px, py in coords],
|
||||
}
|
||||
if geom_type == "MultiLineString":
|
||||
return {
|
||||
"type": "MultiLineString",
|
||||
"coordinates": [
|
||||
[tile_coord_to_lonlat(z, x, y, px, py, extent) for px, py in line]
|
||||
for line in coords
|
||||
],
|
||||
}
|
||||
if geom_type == "Polygon":
|
||||
return {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[tile_coord_to_lonlat(z, x, y, px, py, extent) for px, py in ring]
|
||||
for ring in coords
|
||||
],
|
||||
}
|
||||
if geom_type == "MultiPolygon":
|
||||
return {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[tile_coord_to_lonlat(z, x, y, px, py, extent) for px, py in ring]
|
||||
for ring in polygon
|
||||
]
|
||||
for polygon in coords
|
||||
],
|
||||
}
|
||||
raise RuntimeError(f"unsupported geometry type: {geom_type}")
|
||||
|
||||
|
||||
def convert_tile(path: Path) -> tuple[dict, int]:
|
||||
z = int(path.parent.parent.name)
|
||||
x = int(path.parent.name)
|
||||
y = int(path.stem)
|
||||
|
||||
with path.open("rb") as fh:
|
||||
decoded = mapbox_vector_tile.decode(fh.read())
|
||||
|
||||
features = []
|
||||
for vt_layer, payload in decoded.items():
|
||||
extent = int(payload.get("extent") or 4096)
|
||||
for feature in payload.get("features", []):
|
||||
properties = dict(feature.get("properties") or {})
|
||||
properties["vt_layer"] = vt_layer
|
||||
out_feature = {
|
||||
"type": "Feature",
|
||||
"geometry": convert_geometry(feature["geometry"], z, x, y, extent),
|
||||
"properties": properties,
|
||||
}
|
||||
if feature.get("id") is not None:
|
||||
out_feature["id"] = feature["id"]
|
||||
features.append(out_feature)
|
||||
|
||||
return {"type": "FeatureCollection", "features": features}, len(features)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
OUTPUT_ROOT.mkdir(parents=True, exist_ok=True)
|
||||
tile_paths = sorted(INPUT_ROOT.glob("*/*/*.pbf"))
|
||||
total_features = 0
|
||||
|
||||
for index, path in enumerate(tile_paths, start=1):
|
||||
collection, count = convert_tile(path)
|
||||
total_features += count
|
||||
output_path = OUTPUT_ROOT / f"{path.parent.parent.name}_{path.parent.name}_{path.stem}.json"
|
||||
output_path.write_text(
|
||||
json.dumps(collection, ensure_ascii=False, separators=(",", ":")),
|
||||
encoding="utf-8",
|
||||
)
|
||||
if index % 5000 == 0:
|
||||
print(f"processed {index}/{len(tile_paths)} tiles, wrote {total_features} features")
|
||||
|
||||
print(f"Converted {len(tile_paths)} tiles into {OUTPUT_ROOT} with {total_features} features")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user