cesium-uvw-wind
v0.3.0
Published
Cesium UVW 3D wind field renderer with particles and analysis overlays.
Downloads
557
Maintainers
Readme
Cesium UVW Wind
Cesium UVW Wind 是一个基于 Cesium 的三维 u / v / w 矢量场渲染图层,适合展示风场、洋流、数值模式输出等规则网格数据。
安装
npm install cesium-uvw-wind基本用法
import { UvwWindLayer } from "cesium-uvw-wind";
const layer = new UvwWindLayer(viewer);
await layer.load({
source: "/data/demo-uvw.json",
format: "json",
preset: {
particlesTextureSize: 64,
particleHeight: { min: 20000, max: 640000 },
speedFactor: 2,
displayRange: { min: 0, max: 50 },
lineLength: { min: 40, max: 220 },
},
});UvwWindLayer
const layer = new UvwWindLayer(viewer);| 参数 | 必填 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| viewer | 是 | Cesium.Viewer | 无 | 已创建好的 Cesium Viewer。 |
layer.load(config)
加载数据源并创建粒子图层。
| 字段 | 必填 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| source | 是 | string \| object | 无 | 数据源。支持 URL、JSON 元数据对象、GeoTIFF 分量对象。 |
| format | 否 | "json" \| "netcdf" \| "geotiff" | 按扩展名推断 | 数据格式。无法从扩展名判断时必须传。 |
| sourceOptions | 否 | object | {} | 数据解析参数。不同格式支持的字段不同。 |
| preset | 否 | object | 见 preset 表 | 粒子渲染参数。 |
layer.update(config)
更新同网格尺寸的数据,复用当前粒子图层。
await layer.update({
source: "/data/typhoon/2022-09-02T06.json",
format: "json",
});config 字段与 load(config) 相同。width / height / depth 必须一致;bounds 可以变化。
layer.setPreset(preset)
更新粒子渲染参数,不重新加载数据。
layer.setPreset({
speedFactor: 3,
useViewerBounds: true,
viewBoundsPadding: 0.4,
});| 字段 | 类型 | 默认值 | 取值约束 | 说明 |
| --- | --- | --- | --- | --- |
| particlesTextureSize | number | 48 | 正整数 | 粒子纹理边长。实际粒子数为 particlesTextureSize * particlesTextureSize。 |
| particleHeight | number \| { min, max } | { min: 20000, max: 520000 } | 必须与数据高度范围有交集 | 粒子出生和运动的高度范围,最终会裁剪到数据高度范围内。 |
| speedFactor | number | 1 | 有限数字 | 整体运动速度系数。 |
| speedContrast | number | 0 | 0..2 | 速度差异增强系数。值越大,快慢粒子速度差越明显。 |
| verticalFactor | number | 1 | 有限数字 | 垂直速度 w 放大系数。 |
| dropRate | number | 0.003 | 0..1 | 粒子随机重生率。 |
| dropRateBump | number | 0.01 | 0..1 | 强风区域额外重生率。 |
| domain | { min, max } | { min: 0, max: 55 } | min <= max | 速度归一化的数据域。 |
| displayRange | { min, max } | { min: 0, max: 55 } | min <= max | 色带和尾迹可见长度的映射范围。 |
| lineLength | { min, max } | { min: 40, max: 180 } | 0 <= min <= max | 粒子尾迹长度范围。速度越高越接近 max。 |
| colorRamp | string[] | ["#47c7ff", "#73ff9e", "#ffbf38"] | 至少 2 个 CSS 颜色 | 按速度映射的色带。 |
| opacity | number | 0.82 | 0..1 | 粒子透明度。 |
| useViewerBounds | boolean | true | - | 是否按当前相机视窗裁剪粒子。 |
| viewBoundsPadding | number | 0.35 | 0..2 | 视窗裁剪外扩比例。 |
| adaptiveParticleCount | boolean | true | - | 是否按可视面积动态降低活动粒子数。 |
| adaptiveParticleMinRatio | number | 0.18 | 0..1 | 自适应粒子数最低保留比例。 |
| adaptiveSegmentCount | boolean | true | - | 是否按可视面积动态降低尾迹段数。 |
| adaptiveSegmentMinRatio | number | 0.45 | 0..1 | 自适应尾迹段数最低保留比例。 |
| updateStride | number | 1 | 整数 1..8 | 分批更新步长。值越大,每帧更新的粒子越少。 |
| dynamic | boolean | true | - | 是否更新粒子动画。 |
layer.setAnalysis(options)
更新分析图层,返回切面和点位风廓线数据。
const result = layer.setAnalysis({
slice: {
enabled: true,
mode: "vertical",
height: 180000,
heading: 90,
pitch: 90,
roll: 0,
fill: true,
contours: false,
barbs: false,
contourThreshold: 12,
barbScale: 1,
barbDensity: 1,
barbColor: "#ffffff",
contourLineColor: "#ffffff",
contourLineWidth: 1,
contourInterval: 4,
particleFilter: { mode: "side", side: "negative", widthKm: 120 },
},
profile: {
enabled: true,
layers: 16,
probe: { lon: 114, lat: 24 },
},
});入参:
options.slice
| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| enabled | boolean | false | 是否启用切面分析。 |
| mode | "horizontal" \| "vertical" \| "custom" | "horizontal" | horizontal 为固定高度面;vertical 为按方位角穿过数据范围的垂直剖面;custom 为按 heading / pitch / roll 定义的任意姿态平面。 |
| height | number | 0 | 切面高度,单位米。水平切面和自定义切面的中心高度使用该值。 |
| heading | number | 90 | 方位角,单位度。 |
| pitch | number | 水平 0,其他 90 | 自定义姿态俯仰角,单位度。 |
| roll | number | 0 | 自定义姿态翻滚角,单位度。 |
| offset | number | 0 | 切面相对数据中心的偏移,范围 -100..100。 |
| samples | number | 96 | 切面横向采样数,整数 8..1000。值越大,小格子越细,开销越高。 |
| layers | number | 36 | 切面纵向采样数,整数 8..1000。值越大,小格子越细,开销越高。 |
| fillOpacity | number | 0.4 | 速度填色面的整体透明度,范围 0..1。 |
| fill | boolean | true | 是否显示速度填色。 |
| contours | boolean | false | 是否显示等值线。 |
| barbs | boolean | false | 是否显示风羽。 |
| contourThreshold | number | 12 | 等值线阈值。 |
| barbScale | number | 1 | 风羽大小倍率,范围 0.1..5。 |
| barbDensity | number | 1 | 风羽密度倍率,范围 0.25..4。 |
| barbColor | string | "#ffffff" | 风羽轮廓色。 |
| contourLineColor | string | "#ffffff" | 等值线轮廓色。 |
| contourLineWidth | number | 1 | 等值线轮廓粗细倍率,范围 0..5。 |
| contourInterval | number \| "auto" | "auto" | 等值线间距,单位 m/s;不传或 "auto" 时按最大风速自动计算。 |
| particleFilter.mode | "all" \| "band" \| "side" | "side" | 主粒子场切面过滤方式。 |
| particleFilter.widthKm | number | 120 | band 模式带宽,单位千米。 |
| particleFilter.side | "positive" \| "negative" | "negative" | side 模式保留的切面一侧。 |
options.profile
| 字段 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| enabled | boolean | false | 是否启用点位垂直廓线。 |
| layers | number | 16 | 点位风廓线采样层数,整数 4..256。 |
| probe | { lon, lat } | 无 | 启用 profile.enabled 时必填。 |
返回值:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| slice | object \| null | 切面分析结果。水平、垂直、自定义姿态都返回到这个字段;未启用 slice.enabled 时为 null。 |
| profile | object \| null | 点位垂直廓线结果。未启用 profile.enabled 时为 null。 |
返回值中的 slice 字段:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| mode | "horizontal" \| "vertical" \| "custom" | 切面模式。 |
| height | number | 切面高度,单位米。 |
| bearing | number | 方位角,单位度。水平切面通常不使用。 |
| pitch | number | 自定义姿态俯仰角,单位度。 |
| roll | number | 自定义姿态翻滚角,单位度。 |
| widthMeters | number | 切面横向长度,单位米。 |
| heightMeters | number | 切面纵向长度,单位米。 |
| points | Array | 切面采样点,顺序为 z * samples + x。 |
| speeds | Float32Array | 每个采样点的三维风速模长。 |
| along | Float32Array | 每个采样点沿切面横轴的风速分量。 |
| vertical | Float32Array | 每个采样点沿切面纵轴的风速分量。 |
| minSpeed | number | 最小风速。 |
| maxSpeed | number | 最大风速。 |
| meanSpeed | number | 平均风速。 |
| sampleCount | number | 统计采样点数量。 |
| strongRatio | number | 达到阈值的采样点占比,范围 0..1。 |
其他方法
| 方法 | 返回值 | 说明 |
| --- | --- | --- |
| update(config) | Promise<UvwWindLayer> | 更新同网格尺寸数据,复用当前粒子图层。 |
| clearAnalysis() | UvwWindLayer | 移除分析图层,并取消粒子剖面过滤。 |
| pickLonLat(windowPosition) | null \| { lon, lat } | 将 Cesium 屏幕坐标拾取为地球表面经纬度。 |
| setPaused(paused) | UvwWindLayer | 设置粒子动画暂停状态。 |
| reset() | UvwWindLayer | 重置粒子位置和生命周期。 |
| destroy() | void | 销毁图层创建的 Cesium 资源。 |
数据格式
JSON
JSON 支持纯 JSON 和 JSON + BIN 两种形式。
纯 JSON:
{
"type": "uvw-grid",
"width": 2,
"height": 2,
"depth": 1,
"bounds": {
"west": 110,
"south": 20,
"east": 120,
"north": 30,
"minHeight": 10000,
"maxHeight": 10000
},
"u": [1, 2, 3, 4],
"v": [0, 0, 0, 0],
"w": [0, 0, 0, 0]
}JSON + BIN:
{
"type": "uvw-grid",
"width": 28,
"height": 22,
"depth": 10,
"bounds": {
"west": 112,
"south": 18,
"east": 126,
"north": 38,
"minHeight": 20000,
"maxHeight": 640000
},
"layout": "uvw-float32",
"data": "/data/demo/json/demo-uvw.bin"
}| 字段 | 必填 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| type | 否 | "uvw-grid" | 无 | UVW 网格标识。 |
| name | 否 | string | "UVW grid" | 数据名称。 |
| unit | 否 | string | "m/s" | 数据单位。 |
| width | 是 | number | 无 | 经度方向网格数,正整数。 |
| height | 是 | number | 无 | 纬度方向网格数,正整数。 |
| depth | 是 | number | 无 | 高度方向网格数,正整数。 |
| bounds | 是 | object | 无 | 数据经纬度和高度范围。 |
| u | 纯 JSON 必填 | array \| typed array | 无 | U 分量。 |
| v | 纯 JSON 必填 | array \| typed array | 无 | V 分量。 |
| w | 纯 JSON 必填 | array \| typed array | 无 | W 分量。 |
| layout | JSON + BIN 必填 | "uvw-float32" | 无 | BIN 布局。 |
| data | JSON + BIN 必填 | string | 无 | BIN 文件地址。传 JSON 对象时必须是根路径或绝对 URL。 |
u / v / w 的长度必须等于 width * height * depth,数组顺序为 z -> y -> x,纬度行按北到南排列。
BIN 文件必须是交错 Float32:u0, v0, w0, u1, v1, w1, ...。
| sourceOptions 字段 | 必填 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| baseUrl | 否 | string | 按 JSON URL 推断 | 当 JSON 元数据里的 data 是相对路径时使用。 |
| spawnThreshold | 否 | number | undefined | 出生点速度阈值。速度小于等于该值的格点不会作为出生点。 |
NetCDF v3
NetCDF 加载器支持 NetCDF v3 classic 文件,不支持 NetCDF4/HDF5。
await layer.load({
source: "/data/demo-uvw-v3.nc",
format: "netcdf",
});自定义变量名:
await layer.load({
source: "/data/reanalysis.nc",
format: "netcdf",
sourceOptions: {
variables: {
u: "uwnd",
v: "vwnd",
w: "omega",
lon: "lon",
lat: "lat",
height: "level",
},
minHeight: 0,
maxHeight: 12000,
},
});规则:
source必须是 URL 字符串。- 必须存在 U 和 V 变量。
- W 变量可缺省,缺省时按
0处理。 - 需要 lon/lat 坐标变量,或者显式传
sourceOptions.bounds。 - 变量维度应为规则网格,常见形式为
(height, lat, lon)。
| sourceOptions 字段 | 必填 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| variables | 否 | object | { u: "U", v: "V", w: "W", lon: "lon", lat: "lat", height: "lev" } | 变量名映射。 |
| bounds | 否 | object | 从坐标变量推断 | 显式数据范围。 |
| minHeight | 否 | number | 0 | 无高度坐标时的兜底最小高度。 |
| maxHeight | 否 | number | max(1, depth - 1) | 无高度坐标时的兜底最大高度。 |
| name | 否 | string | 全局 title 或 "NetCDF v3 UVW" | 数据名称。 |
| unit | 否 | string | U 变量单位或 "m/s" | 数据单位。 |
| spawnThreshold | 否 | number | undefined | 出生点速度阈值。 |
GeoTIFF
GeoTIFF 当前按单高度层读取,即 depth = 1。
多波段:
await layer.load({
source: "/data/uvw.tif",
format: "geotiff",
sourceOptions: {
samples: { u: 0, v: 1, w: 2 },
minHeight: 10000,
maxHeight: 260000,
},
});分量文件:
await layer.load({
source: {
u: "/data/u.tif",
v: "/data/v.tif",
w: "/data/w.tif",
},
format: "geotiff",
sourceOptions: {
minHeight: 10000,
maxHeight: 260000,
},
});规则:
- 多波段模式需要至少包含 U、V 波段。
- 分量文件模式必须提供
source.u和source.v。 - W 可缺省,缺省时按
0处理。 - 如果 GeoTIFF 无法读取地理范围,必须显式传
sourceOptions.bounds。 bounds只接受west / south / east / north,高度通过minHeight / maxHeight传。
| sourceOptions 字段 | 必填 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| samples | 否 | object | 多波段 { u: 0, v: 1, w: 2 };分量文件均为 0 | U/V/W 波段索引。 |
| bounds | 条件必填 | object | 从 GeoTIFF 读取 | 地理范围。GeoTIFF 无地理信息时必填。 |
| minHeight | 否 | number | 0 | 单高度层最小高度。 |
| maxHeight | 否 | number | 1 | 单高度层最大高度。 |
| imageIndex | 否 | number | 0 | TIFF image index。 |
| name | 否 | string | "GeoTIFF UVW" | 数据名称。 |
| unit | 否 | string | "m/s" | 数据单位。 |
| spawnThreshold | 否 | number | GeoTIFF nodata 为 0 时默认 0,否则 undefined | 出生点速度阈值。 |
bounds
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| west | 是 | number | 西边界,经度。 |
| south | 是 | number | 南边界,纬度。 |
| east | 是 | number | 东边界,经度,必须大于 west。 |
| north | 是 | number | 北边界,纬度,必须大于 south。 |
| minHeight | 是 | number | 最小高度,米。 |
| maxHeight | 是 | number | 最大高度,米,必须大于或等于 minHeight。 |
