134 lines
4.3 KiB
Python
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)
|