river-sim/v2.py
2024-11-07 17:53:11 +08:00

134 lines
4.3 KiB
Python

import geopandas as gpd
import numpy as np
from datetime import datetime, timedelta
import json
import random
def simulate_river_flow(hours=336):
"""模拟河流径流数据
使用简单的正弦函数加随机波动来模拟径流变化
"""
# 基础流量(立方米/秒)
base_flow = random.uniform(50, 200)
# 生成时间序列数据
time_steps = np.linspace(0, 2 * np.pi, hours)
# 使用正弦函数生成周期性变化
flow = base_flow + base_flow * 0.3 * np.sin(time_steps)
# 添加随机波动
flow += np.random.normal(0, base_flow * 0.1, hours)
return flow.clip(min=0) # 确保流量非负
def flow_to_color(flow, min_flow, max_flow):
"""根据径流量生成颜色
低流量 (0-30%): 深蓝 [0, 0, 180, 255]
中等流量 (30-65%): 绿色过渡 [0, 180, 0, 255]
高流量 (65-100%): 深红 [180, 0, 0, 255]
"""
# 将流量归一化到0-1区间
normalized_flow = (flow - min_flow) / (max_flow - min_flow)
transition_point = 0.7 # 70%处开始第一次过渡
if normalized_flow < transition_point:
# 从蓝色过渡到绿色 (0-70%)
ratio = normalized_flow / transition_point # 将0-0.3映射到0-1
red = 0
green = int(180 * ratio)
blue = int(180 * (1 - ratio))
else:
# 从绿色过渡到红色 (70%-100%)
ratio = (normalized_flow - transition_point) / (
1 - transition_point
) # 将0.3-1映射到0-1
red = int(180 * ratio)
green = int(180 * (1 - ratio))
blue = 0
return [red, green, blue, 255] # RGBA格式
def create_czml(geojson_path, output_path, year=2024, month=6, day=1, hours=168):
# 读取GeoJSON数据
gdf = gpd.read_file(geojson_path)
# 设置时间范围
start_time = datetime(year, month, day, 0, 0, 0)
# 创建CZML文档
czml = [
{
"id": "document",
"name": "River Network Visualization",
"version": "1.0",
"clock": {
"interval": f"{start_time.isoformat()}Z/{(start_time + timedelta(hours=hours)).isoformat()}Z",
"currentTime": f"{start_time.isoformat()}Z",
"multiplier": 3600, # 1小时/秒
},
}
]
# 为每条河流生成数据
for idx, row in gdf.iterrows():
# 模拟径流数据
flow_data = simulate_river_flow(hours)
min_flow = flow_data.min()
max_flow = flow_data.max()
# 提取坐标
coords = []
if row.geometry.type == "MultiLineString":
for line in row.geometry.geoms:
coords.extend([[x, y, 0] for x, y in line.coords])
# 创建每个时间点的颜色数据
color_property = []
for hour in range(hours):
current_time = start_time + timedelta(hours=hour)
color = flow_to_color(flow_data[hour], min_flow, max_flow)
color_property.append(
{
"interval": f"{current_time.isoformat()}Z/{(current_time + timedelta(hours=1)).isoformat()}Z",
"rgba": color,
}
)
# 创建河流对象
river = {
"id": f"river_{row['Index']}",
"name": f"River {row['Index']}",
"polyline": {
"positions": {
"cartographicDegrees": [
coord for point in coords for coord in point
]
},
"material": {"solidColor": {"color": color_property}},
"width": 3,
"clampToGround": True, # 贴地显示
"classificationType": "BOTH", # 同时在地形和3D切片上显示
"zIndex": 1, # 控制叠加顺序
"distanceDisplayCondition": {
"nearFar": [0, 1000000] # 显示距离范围(米)
},
"heightReference": "CLAMP_TO_GROUND", # 确保贴地
},
}
czml.append(river)
# 保存CZML文件
with open(output_path, "w") as f:
json.dump(czml, f, indent=2)
if __name__ == "__main__":
# 使用示例
geojson_path = "input/1.geojson"
czml_output = "output/rivers.czml"
create_czml(geojson_path, czml_output, hours=168)