Files
weather/tasks/WeatherServer_VectorTileGenerator.md
OpenAI Codex c957fef15b Initial import
2026-03-17 19:52:51 +08:00

248 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NavSea Weather Server
Task: WeatherServer_VectorTileGenerator
Architecture: NavSea V11
Codex: codex6
Status: TODO
---
# 1 任务目标
实现 Vector Tile Generator。
功能:
将 Weather Grid JSON 转换为 MapLibre Vector Tile (PBF)。
输入:
data/grid/*.json
输出:
output/weather/{time}/{z}/{x}/{y}.pbf
用于 NavSea 客户端加载天气图层。
---
# 2 使用库
需要安装:
pip install mercantile
pip install mapbox-vector-tile
---
# 3 输入数据
GridBuilder v2 生成:
data/grid/
grid_20260312_00_f000.json
grid_20260312_00_f003.json
结构:
{
"time": "...",
"grid": {
"lat": [...],
"lon": [...],
"wind_speed": [[...]],
"wind_dir": [[...]],
"rain": [[...]],
"temp": [[...]],
"pressure": [[...]]
}
}
grid 尺寸:
121 × 121
---
# 4 Tile Zoom 设计
Weather tile 只需要 4 个 zoom
2
4
6
8
---
# 5 Tile 输出结构
output/weather/
time/
z/
x/
y.pbf
示例:
output/weather/20260312_00_f000/4/10/7.pbf
---
# 6 Feature 结构
每个 grid 点 → 一个 feature
geometry
POINT(lon lat)
properties
{
"ws": wind_speed
"wd": wind_dir
"r": rain
"t": temp
"p": pressure
}
字段缩写减少 tile 大小。
---
# 7 创建文件
weather_server/tiles/vector_tile_generator.py
---
# 8 实现代码
```python
import os
import json
import mercantile
import mapbox_vector_tile
GRID_DIR = "data/grid"
OUTPUT_DIR = "output/weather"
ZOOMS = [2,4,6,8]
def load_grid(path):
with open(path) as f:
data = json.load(f)
return data["time"], data["grid"]
def grid_to_features(grid):
lat = grid["lat"]
lon = grid["lon"]
ws = grid["wind_speed"]
wd = grid["wind_dir"]
rain = grid["rain"]
temp = grid["temp"]
pres = grid["pressure"]
features = []
for i in range(len(lat)):
for j in range(len(lon)):
feature = {
"geometry":{
"type":"Point",
"coordinates":[lon[j], lat[i]]
},
"properties":{
"ws":ws[i][j],
"wd":wd[i][j],
"r":rain[i][j],
"t":temp[i][j],
"p":pres[i][j]
}
}
features.append(feature)
return features
def generate_tiles(time, features):
for z in ZOOMS:
tiles = mercantile.tiles(120,20,150,50,z)
for tile in tiles:
bounds = mercantile.bounds(tile)
tile_features = []
for f in features:
lon, lat = f["geometry"]["coordinates"]
if (
bounds.west <= lon <= bounds.east
and bounds.south <= lat <= bounds.north
):
tile_features.append(f)
if not tile_features:
continue
layer = {
"weather": tile_features
}
tile_data = mapbox_vector_tile.encode(layer)
path = os.path.join(
OUTPUT_DIR,
time,
str(z),
str(tile.x)
)
os.makedirs(path, exist_ok=True)
filename = os.path.join(
path,
f"{tile.y}.pbf"
)
with open(filename,"wb") as f:
f.write(tile_data)
print("tile", time, z, tile.x, tile.y)
def main():
for file in os.listdir(GRID_DIR):
if not file.endswith(".json"):
continue
path = os.path.join(GRID_DIR, file)
print("processing", file)
time, grid = load_grid(path)
features = grid_to_features(grid)
generate_tiles(time, features)
if __name__ == "__main__":
main()