@anov/gis-skills-cli 0.0.0-stage → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +637 -0
  2. package/INSTALL.md +481 -0
  3. package/LICENSE +15 -0
  4. package/README.md +148 -2
  5. package/RELEASING.md +162 -0
  6. package/bin/anov-gis-skills.mjs +470 -0
  7. package/lib/mcp-config.mjs +273 -0
  8. package/package.json +43 -4
  9. package/skills/anovgis-analysis/SKILL.md +585 -0
  10. package/skills/anovgis-effects/SKILL.md +260 -0
  11. package/skills/anovgis-imagery-terrain/SKILL.md +505 -0
  12. package/skills/anovgis-layers/SKILL.md +627 -0
  13. package/skills/anovgis-materials/SKILL.md +635 -0
  14. package/skills/anovgis-models-3dtiles/SKILL.md +448 -0
  15. package/skills/anovgis-pitfalls/SKILL.md +561 -0
  16. package/skills/anovgis-popup-widget/SKILL.md +474 -0
  17. package/skills/anovgis-primitives/SKILL.md +482 -0
  18. package/skills/anovgis-vector-graphics/SKILL.md +602 -0
  19. package/skills/anovgis-viewer/SKILL.md +618 -0
  20. package/skills/using-anovgis/DEMO-MAP.md +64 -0
  21. package/skills/using-anovgis/DEMO-SKILL-MAP.md +248 -0
  22. package/skills/using-anovgis/DOMAINS.md +183 -0
  23. package/skills/using-anovgis/REFERENCE.md +114 -0
  24. package/skills/using-anovgis/SKILL.md +392 -0
  25. package/skills/using-anovgis/templates/README.md +154 -0
  26. package/skills/using-anovgis/templates/combo1-vue3-vite.md +295 -0
  27. package/skills/using-anovgis/templates/combo2-vue2-cli.md +119 -0
  28. package/skills/using-anovgis/templates/combo3-html-cdn.md +107 -0
  29. package/skills/using-anovgis/templates/combo4-vanilla-webpack.md +91 -0
  30. package/skills/using-anovgis/templates/wizard-profiles.md +105 -0
  31. package/vendor/cesiumjs-skills/LICENSE +201 -0
  32. package/vendor/cesiumjs-skills/NOTICE +18 -0
  33. package/vendor/cesiumjs-skills/skills/cesiumjs-3d-tiles/SKILL.md +465 -0
  34. package/vendor/cesiumjs-skills/skills/cesiumjs-camera/SKILL.md +500 -0
  35. package/vendor/cesiumjs-skills/skills/cesiumjs-core-utilities/SKILL.md +403 -0
  36. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/REFERENCE.md +397 -0
  37. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/SKILL.md +351 -0
  38. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/01-diffuse-tint.js +38 -0
  39. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/02-texture-swap.js +42 -0
  40. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/03-feature-id-tileset.js +29 -0
  41. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/04-translucent-override.js +37 -0
  42. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/05-vertex-displacement.js +49 -0
  43. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/06-metadata-ramp.js +34 -0
  44. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/07-voxel-shader.js +27 -0
  45. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/README.md +19 -0
  46. package/vendor/cesiumjs-skills/skills/cesiumjs-custom-shader/examples/_sandcastle-template.html +9 -0
  47. package/vendor/cesiumjs-skills/skills/cesiumjs-entities/SKILL.md +389 -0
  48. package/vendor/cesiumjs-skills/skills/cesiumjs-imagery/SKILL.md +471 -0
  49. package/vendor/cesiumjs-skills/skills/cesiumjs-interaction/SKILL.md +423 -0
  50. package/vendor/cesiumjs-skills/skills/cesiumjs-materials-shaders/SKILL.md +292 -0
  51. package/vendor/cesiumjs-skills/skills/cesiumjs-models-particles/SKILL.md +423 -0
  52. package/vendor/cesiumjs-skills/skills/cesiumjs-primitives/SKILL.md +537 -0
  53. package/vendor/cesiumjs-skills/skills/cesiumjs-spatial-math/SKILL.md +358 -0
  54. package/vendor/cesiumjs-skills/skills/cesiumjs-terrain-environment/SKILL.md +401 -0
  55. package/vendor/cesiumjs-skills/skills/cesiumjs-time-properties/SKILL.md +353 -0
  56. package/vendor/cesiumjs-skills/skills/cesiumjs-viewer-setup/SKILL.md +434 -0
  57. package/vendor/cesiumjs-skills/skills/using-cesiumjs-skills/SKILL.md +35 -0
@@ -0,0 +1,585 @@
1
+ ---
2
+ name: anovgis-analysis
3
+ description: '@anov/gis 分析与标绘模块。涵盖 Draw*(DrawPoint/DrawPolyLine/DrawPolygon/DrawRectangle/DrawCircle,统一 justDraw 区分测量/标绘)、TerrainClipping 地形开挖与剖切、CesiumWaterAnalysis 水淹分析、CesiumHeatMap + HeatMapLayer 两套热力图、WindLayer 风场粒子、DamWaterRelease 水坝开闸放水、PositonEditor 三轴平移旋转缩放编辑控件(v1.8.6 增强)、Geocoder 地名搜索。触发关键词:标绘、测量、draw、measure、DrawPolyLine、DrawPolygon、地形剖切、TerrainClipping、热力图、HeatMap、风场、WindLayer、水淹、WaterAnalysis、水坝、DamWaterRelease、编辑控件、PositonEditor、positonEditor、damWaterRelease、wfs、WFS、iServerWfs、geocoder、地理编码。Use when 标绘图形 / 测距测面积 / 地形开挖 / 剖切 / 热力图 / 风场粒子 / 水淹分析 / 三轴编辑控件、地名搜索。'
4
+ anov-gis-baseline: 1.8.6
5
+ cesium-baseline: 1.143.0
6
+ ---
7
+ ---
8
+
9
+ # 05 — 分析与标绘速查
10
+
11
+ > ⚠️ **优先级**:本 skill 优先于 SDK 源码 / `node_modules/@anov/gis/`。
12
+ > 遇到 API 行为疑问先查本 skill 与 `anovgis-pitfalls`。**严禁**主动 Glob/Grep `node_modules/@anov/gis/src/...` / `dist/...`;除非用户明确要求并承担风险。
13
+ > 调试流程见 `using-anovgis` § 默认调试流程(Chrome DevTools 仅第 5 级兜底)。
14
+ >
15
+ > **Cesium 入口(铁律)**:`const Cesium = window.Cesium`。`@anov/gis` 启动时已把 Cesium 挂到 `window`,**不存在** `ANOVGIS.Cesium` 写法;本 skill 所有 `Cesium.*` 均从此变量取。底层 Cesium API 细节查 `cesiumjs-skills` 对应 skill(API 名通用,`import` 写法换成 `const Cesium = window.Cesium`)。
16
+
17
+ > SDK 路径:`src/analysis/`,通过 `src/ANOVGIS.js` 的 `export * from './analysis'` 全部挂到 `ANOVGIS` 顶层命名空间(仅作语义锚点)。锁定 `@anov/gis` **v1.8.6**(Cesium **1.143.0**);v1.8.6 新增 `TilesetEditor`(~1034 行)/ `PositonEditor` 增强(~1029 行)。
18
+
19
+ ## Out-of-scope(v0.2.0 短版)
20
+
21
+ - ❌ 不要写 `PositonEditor` 用于编辑 `Tileset` 模型的位姿 → [`anovgis-models-3dtiles`](../anovgis-models-3dtiles/SKILL.md)(`TilesetEditor` 完整用法)
22
+ - ❌ 不要写 WFS / iServer WFS 完整用法 → v0.3.0 `anovgis-offline-deployment`
23
+ - ❌ 不要写 Cesium 原生 `ClippingPlanesCollection`(地形剖切底层) → 见 Cesium 文档
24
+ - ❌ 不要写 Draw* 之外的几何交互(如拾取编辑 Entity 顶点) → Cesium 文档
25
+ - ❌ 不要写 Imagery / Terrain → [`anovgis-imagery-terrain`](../anovgis-imagery-terrain/SKILL.md)
26
+ - ❌ 不要写特效 → [`anovgis-effects`](../anovgis-effects/SKILL.md)
27
+ > **命名警告**:本模块没有 `DrawController` / `DrawType` / `MeasureTool` / `ClippingPlanesEditor` / `TerrainProfile` / `CoordEditor` 这些类。测量与标绘是**同一套 Draw* 类**(`options.justDraw` 区分:`false` 显示长度/面积标签即测量,`true` 仅画图形)。写代码前先核对下表类名。
28
+
29
+ ## 1. 速查表
30
+
31
+ <a id="draw"></a>
32
+ ### 1.1 标绘 / 测量 `src/analysis/draw/`
33
+
34
+ | 类名 | 图形 | 说明 |
35
+ |---|---|---|
36
+ | `DrawBase` | — | 基类,提供 `startDraw()` / `end()` / `clear()` / `clearAll()` |
37
+ | `DrawPoint` | 点 | 标签显示经纬度高程 |
38
+ | `DrawPolyLine` | 折线 | `justDraw:false` 时显示分段长度 + 总长(即距离测量) |
39
+ | `DrawPolygon` | 多边形 | `justDraw:false` 时显示面积(即面积测量) |
40
+ | `DrawRectangle` | 矩形 | 两点拉框 |
41
+ | `DrawCircle` | 圆 | 圆心 + 半径,显示面积 |
42
+ | `NoDepthTestPolylineCollection` | — | 内部用,无深度测试线集合(穿透地形显示) |
43
+
44
+ 构造签名统一为 `new ANOVGIS.DrawXxx(viewer, options)`,`viewer` 可传 ANOVGIS Viewer 或原生(内部 `viewer.nativeObjCesium || viewer`)。
45
+
46
+ ### 1.2 其余分析类
47
+
48
+ | 类名 | 子目录 | 用途 |
49
+ |---|---|---|
50
+ | `TerrainClipping` | `clipping/` | 地形开挖 / 剖切(底面 + 侧墙贴图) |
51
+ | `CesiumWaterAnalysis` | `waterAnalysis/` | 水淹分析(多边形按水位升高拉伸) |
52
+ | `CesiumHeatMap` | `heatmap/` | 热力图(Canvas 引擎 + Entity 贴图,静态工厂 `create`) |
53
+ | `HeatMapLayer` | `heatmap/` | 热力图(WebGL 引擎,继承 `Layer`,走 `viewer.addLayer`) |
54
+ | `WindLayer` | `wind/` | 风场粒子(继承 `Layer`) |
55
+ | `DamWaterRelease` | `damWaterRelease/` | 水坝开闸放水粒子仿真(多闸门) |
56
+ | `PositonEditor` | `transformHelper/` | 模型 / 点位平移旋转缩放编辑控件(三轴 gizmo) |
57
+
58
+ `Clipping`(基类)与 `ClippingDirection`(方向枚举)**未从 index 导出**,只能通过 `TerrainClipping` 继承链间接使用。
59
+
60
+ ## 2. 关键 API
61
+
62
+ ### 2.1 Draw* 公共 options(`DrawBase.js:10-24`)
63
+
64
+ | 参数 | 默认 | 说明 |
65
+ |---|---|---|
66
+ | `justDraw` | `false` | `true` = 纯标绘不显示量算标签 |
67
+ | `showToolTip` | `true` | 鼠标跟随提示 |
68
+ | `clampToGround` | `false` | 贴地 |
69
+ | `pointColor` / `pointSize` | `RED` / `6` | 节点样式 |
70
+ | `outlineColor` / `outlineWidth` | `CHARTREUSE` / `3` | 轮廓 |
71
+ | `lineColor` / `lineWidth` | `CHARTREUSE` / `3` | 线样式 |
72
+ | `tempPoint_size` / `tempPoint_color` / `tempPoint_show` / `tempPoint_showLabel` | `10` / `YELLOW` / `true` / `false` | 浮动跟随点 |
73
+ | `billboard` | `undefined` | 节点图标 |
74
+ | `onCompleted(positions)` | — | 完成回调,返回 `Cartesian3[]` |
75
+
76
+ 方法:`startDraw()` 开始(内部先 `end()` 复位)、`end()` 结束交互、`clear()` 清除本类实体、`clearAll()` 清全部 + 结束。
77
+
78
+ <a id="terrain-clipping"></a>
79
+ ### 2.2 TerrainClipping
80
+
81
+ `new TerrainClipping(viewer, { lerpInterval=50, bottomImage='', sideImage='' })`
82
+
83
+ 属性(均为 setter):`positions`(`Cartesian3[]` 或经纬度数组,赋值即重建裁剪面)、`direction`(单向裁剪,用 `'up'|'down'|'left'|'right'|'front'|'back'`)、`distance`、`angle`、`enable`、`height`(开挖深度,默认 5)。`positions` 与 `direction` 互斥,后设者生效。
84
+
85
+ <a id="water-analysis"></a>
86
+ ### 2.3 CesiumWaterAnalysis
87
+
88
+ `new CesiumWaterAnalysis(viewer, { minHeight=0, maxHeight=2000, speed=10, intervalStep=500 })`
89
+
90
+ `start(cartesians, cb)` 定时抬升水位并回调当前高程 / `pause()` / `stop()`(移除多边形)/ `resetParas({minHeight,maxHeight,setpHeight})` / `show`。注意 `resetParas` 读的是 `setpHeight` 而非 `speed`(`CesiumWaterAnalysis.js:137`)。
91
+
92
+ <a id="heatmap"></a>
93
+ ### 2.4 热力图两套引擎
94
+
95
+ - `CesiumHeatMap.create(viewer, bounds, options)` → 实例;`setWGS84Data(min, max, [{x,y,value}])`、`setData(min,max,data)`、`show(bool)`。`bounds = {west,south,east,north}` 需自行按数据算。options 走 heatmap.js:`radius`、`maxOpacity`、`minOpacity`、`blur`、`backgroundColor`。
96
+ - `new HeatMapLayer({ radius=30, height=0, gradient, useGround=false, classificationType=2 })` → `viewer.addLayer(layer)` 后 `setPoints(points)` / `clear()`。`useGround:true` 走 `GroundPrimitive` 贴地。
97
+
98
+ <a id="wind"></a>
99
+ ### 2.5 WindLayer
100
+
101
+ `new WindLayer({ globalAlpha=0.9, lineWidth=1, colorScale='#fff', velocityScale=1/25, maxAge=90, paths=800, frameRate=20, useCoordsDraw=true, gpet=true })`,`setData(data, options)` / `setOptions(options)` / `show`。数据是标准 grib-json(u/v 两个 component 的 `{header, data}` 数组)。
102
+
103
+ <a id="dam-water"></a>
104
+ ### 2.6 DamWaterRelease
105
+
106
+ `new DamWaterRelease(viewer, options)`,options 见 `DamWaterRelease.js:18-37`(`damCenter`、`gateCount=13`、`gatePositions`、`gateHeight`、`gateSpacing`、`sprayHeading/sprayPitch`、`emitterType`、`coneAngle`、`flowPreset`)。方法:`addToScene()`、`openGate(i)` / `closeGate(i)` / `setGateOpen(i,open)` / `openAllGates()` / `closeAllGates()`、`setFlowLevel('light'|'medium'|'heavy'|'flood')`、`updateSprayDirection(h,p)`、`updateEmitterShape()`、`updateAppearance()`、`removeFromScene()`、`destroy()`。枚举 `DamWaterRelease.EmitterType` / `FLOW_PRESETS`。
107
+
108
+ <a id="positon-editor"></a>
109
+ ### 2.7 PositonEditor
110
+
111
+ `new PositonEditor({ translateEnabled=true, rotateEnabled=false, scaleEnabled=false, xAxisLength, ..., rotatePlaneRadius, sizeInPixel=false, originOffset })`,然后 `addTo(viewer)` + `bind(model)` 或 `bindPosition(position)`。事件:`preTranformEvent` / `postTransformEvent` / `postRoatationEvent` / `postScaleEvent`。旋转与缩放仅对模型有效。
112
+
113
+ ## 3. Snippet
114
+
115
+ ### 3.1 标绘 Polyline(`examples/public/examples/html/analysis/draw.html:157-163, 230-231`)
116
+
117
+ ```js
118
+ // justDraw:true = 纯标绘,不显示长度标签
119
+ const drawLine = new ANOVGIS.DrawPolyLine(viewer, {
120
+ lineColor: Cesium.Color.YELLOW,
121
+ justDraw: true,
122
+ onCompleted(positions) {
123
+ console.log(positions); // Cartesian3[]
124
+ }
125
+ });
126
+ drawLine.startDraw(); // 左键加点,右键/双击结束
127
+ // drawLine.end(); // 中断交互
128
+ // drawLine.clear(); // 清除已绘图形
129
+ ```
130
+
131
+ ### 3.2 距离测量(`examples/public/examples/html/analysis/measure.html:111-115, 167-168`)
132
+
133
+ ```js
134
+ // 同一个类,justDraw 缺省(false) 即自动显示分段长度 + 总长
135
+ const measureLine = new ANOVGIS.DrawPolyLine(viewer, {
136
+ lineColor: Cesium.Color.YELLOW,
137
+ onCompleted(positions) { console.log(positions); }
138
+ });
139
+ measureLine.startDraw();
140
+
141
+ // 面积测量同理,换成 DrawPolygon
142
+ const measureArea = new ANOVGIS.DrawPolygon(viewer, {
143
+ onCompleted(positions) { console.log(positions); }
144
+ });
145
+ ```
146
+
147
+ ### 3.3 地形剖切 / 开挖(`examples/public/examples/html/analysis/terraincliping.html:108-142`)
148
+
149
+ ```js
150
+ const clipping = new ANOVGIS.TerrainClipping(viewer, {
151
+ lerpInterval: 200,
152
+ bottomImage: './images/excavate_bottom.jpeg',
153
+ sideImage: './images/excavate_side.png'
154
+ });
155
+ clipping.enable = true;
156
+ clipping.height = 100; // 开挖深度(米)
157
+
158
+ // 用标绘取范围,回调里直接赋 positions 即完成裁剪
159
+ new ANOVGIS.DrawPolygon(viewer, {
160
+ justDraw: true, clampToGround: true, fill: false,
161
+ onCompleted(positions) { clipping.positions = positions; }
162
+ }).startDraw();
163
+
164
+ // clipping.positions = []; // 还原地形
165
+ // clipping.direction = 'up'; // 单向裁剪(与 positions 互斥)
166
+ ```
167
+
168
+ ### 3.4 热力图(`examples/public/examples/html/analysis/cesiumHeatMap.html:76-97`)
169
+
170
+ ```js
171
+ // GeoJSON / 数组 → 先算 bounds,再建热力图
172
+ const bounds = features.reduce((b, f) => ({
173
+ west: Math.min(b.west, f.X), south: Math.min(b.south, f.Y),
174
+ east: Math.max(b.east, f.X), north: Math.max(b.north, f.Y)
175
+ }), { west: 180, south: 90, east: -180, north: -90 });
176
+
177
+ const heatMap = ANOVGIS.CesiumHeatMap.create(viewer, bounds, {
178
+ backgroundColor: 'rgba(0,0,0,0)',
179
+ radius: 50, maxOpacity: 0.5, minOpacity: 0, blur: 0.7
180
+ });
181
+ // min / max 为值域,data 为 [{x, y, value}]
182
+ heatMap.setWGS84Data(0, 100, features.map(f => ({ x: +f.X, y: +f.Y, value: f.value })));
183
+ // heatMap.show(false);
184
+
185
+ // WebGL 引擎版本(贴地、走图层体系)
186
+ const heatLayer = new ANOVGIS.HeatMapLayer({ radius: 30, useGround: true });
187
+ viewer.addLayer(heatLayer);
188
+ heatLayer.setPoints([{ x: 119.29, y: 32.24, value: 39 }]);
189
+ ```
190
+
191
+ ### 3.5 风场(`examples/public/examples/html/analysis/windlayer.html:65-109`,参数调节 `windlayer2.html:86-136`)
192
+
193
+ ```js
194
+ // data 为 grib-json:u/v 两个 component 的 [{header, data}]
195
+ const data = await fetch('./json/beijing_wind.json').then(r => r.json());
196
+
197
+ const windLayer = new ANOVGIS.WindLayer({
198
+ colorScale: ['rgb(255,255,255)'],
199
+ frameRate: 16,
200
+ maxAge: 60, // 粒子存活时间
201
+ globalAlpha: 0.9, // 拖尾透明度
202
+ velocityScale: 1 / 30,// 移动速度
203
+ paths: 2000 // 粒子数
204
+ });
205
+ windLayer.setData(data);
206
+ viewer.addLayer(windLayer);
207
+
208
+ windLayer.setOptions({ paths: 3000, lineWidth: 2 }); // 运行时改参数
209
+ windLayer.show = false;
210
+ ```
211
+
212
+ ### 3.6 水淹分析(`examples/public/examples/html/analysis/waterAanalysis.html:293-351`,`noAuto` 见 `:244`)
213
+
214
+ ```js
215
+ const water = new ANOVGIS.CesiumWaterAnalysis(viewer, {
216
+ minHeight: 990, // 起始水位
217
+ maxHeight: 1440, // 终止水位
218
+ speed: 10, // 每步抬升高度
219
+ intervalStep: 300 // 定时器间隔 ms
220
+ });
221
+
222
+ // 绘范围(贴地、不填充),拿到 Cartesian3[]
223
+ let positions;
224
+ new ANOVGIS.DrawPolygon(viewer, {
225
+ justDraw: true, fill: false, clampToGround: true,
226
+ onCompleted(ps) { positions = ps; }
227
+ }).startDraw();
228
+
229
+ water.start(positions, h => console.log('当前水位', h));
230
+ // water.pause();
231
+ // water.stop();
232
+ // 注意 resetParas 的速度字段叫 setpHeight,不是 speed
233
+ water.resetParas({ minHeight: 990, maxHeight: 1440, setpHeight: 5 });
234
+ // 固定水位(不动画):water.noAuto(positions, 1200);
235
+ ```
236
+
237
+ ## 各 Draw / 分析工具实战补充
238
+
239
+ ### 3.7 单点标绘(`examples/public/examples/html/analysis/draw.html:146-156, 224-228`)
240
+
241
+ ```js
242
+ // 来源: draw.html L146-156
243
+ // DrawPoint 显示经纬度高程标签;justDraw:false 仍带提示,区别于其他类
244
+ const pointTool = new ANOVGIS.DrawPoint(viewer, {
245
+ justDraw: false,
246
+ pointSize: 12,
247
+ pointColor: Cesium.Color.YELLOW,
248
+ tempPoint_show: true, // 浮动跟随点
249
+ tempPoint_color: Cesium.Color.YELLOW,
250
+ showToolTip: false,
251
+ onCompleted(positions) {
252
+ // positions 是长度为 1 的 Cartesian3[]
253
+ const c = positions[0];
254
+ const carto = Cesium.Cartographic.fromCartesian(c);
255
+ console.log(Cesium.Math.toDegrees(carto.longitude),
256
+ Cesium.Math.toDegrees(carto.latitude),
257
+ carto.height);
258
+ }
259
+ });
260
+ pointTool.startDraw(); // 单击落点,自动结束
261
+ // pointTool.end(); // 中断
262
+ // pointTool.clear(); // 清除已绘点
263
+ ```
264
+
265
+ ### 3.8 矩形标绘(`examples/public/examples/html/analysis/draw.html:172-177, 244-248`)
266
+
267
+ ```js
268
+ // 来源: draw.html L172-177
269
+ // DrawRectangle 两点拉框;justDraw:false 自动显示面积标签
270
+ const rectTool = new ANOVGIS.DrawRectangle(viewer, {
271
+ justDraw: false,
272
+ onCompleted(positions) {
273
+ // positions 为 4 个角点(首尾相同 = 5 个)的 Cartesian3[]
274
+ console.log('rectangle corners:', positions.length);
275
+ }
276
+ });
277
+ rectTool.startDraw(); // 鼠标按下拖动 → 抬起完成
278
+ ```
279
+
280
+ ### 3.9 圆形标绘与测面积(`examples/public/examples/html/analysis/draw.html:178-188, 249-253`)
281
+
282
+ ```js
283
+ // 来源: draw.html L178-188
284
+ // 圆心 + 半径绘制;justDraw:true = 纯标绘,:false = 自动显示面积
285
+ const circleTool = new ANOVGIS.DrawCircle(viewer, {
286
+ justDraw: true, // 纯标绘,不带面积标签
287
+ fill: false, // 不填充
288
+ outline: true, // 显示轮廓
289
+ outlineWidth: 4,
290
+ outlineColor: ANOVGIS.Color.YELLOW,
291
+ clampToGround: true, // 贴地
292
+ onCompleted(positions) {
293
+ console.log('circle done', positions); // 中心 + 圆周点
294
+ }
295
+ });
296
+ circleTool.startDraw();
297
+
298
+ // 测面积:justDraw 留空(默认 false)即显示面积 + 半径
299
+ const measureCircle = new ANOVGIS.DrawCircle(viewer, {
300
+ onCompleted(positions) { console.log(positions); }
301
+ });
302
+ measureCircle.startDraw();
303
+ ```
304
+
305
+ ### 3.10 数据驱动热力图(`examples/public/examples/html/analysis/cesiumHeatMap.html:65-97`)
306
+
307
+ ```js
308
+ // 来源: cesiumHeatMap.html L65-97
309
+ // CesiumHeatMap = Canvas 引擎 + Entity 贴图,依赖外部 bounds
310
+ // HeatMapLayer = WebGL 引擎 + Layer 体系,可贴地
311
+ // 两者并存,按场景选其一,不要混用同一份数据
312
+
313
+ // 1) Canvas 版:自己先 reduce 算 bounds
314
+ const data = [{ X: 119.29, Y: 32.24, value: 39 }, /* ... */];
315
+ const bounds = data.reduce((b, r) => ({
316
+ west: Math.min(b.west, r.X), south: Math.min(b.south, r.Y),
317
+ east: Math.max(b.east, r.X), north: Math.max(b.north, r.Y)
318
+ }), { west: 180, south: 90, east: -180, north: -90 });
319
+
320
+ const canvasHeat = ANOVGIS.CesiumHeatMap.create(viewer, bounds, {
321
+ backgroundColor: 'rgba(0,0,0,0)',
322
+ radius: 50, maxOpacity: 0.5, minOpacity: 0, blur: 0.7
323
+ });
324
+ canvasHeat.setWGS84Data(0, 100, data.map(r => ({ x: +r.X, y: +r.Y, value: r.value })));
325
+
326
+ // 2) WebGL 版:直接喂点,自动贴地
327
+ const webglHeat = new ANOVGIS.HeatMapLayer({ radius: 30, useGround: true });
328
+ viewer.addLayer(webglHeat);
329
+ webglHeat.setPoints([{ x: 119.29, y: 32.24, value: 39 }]);
330
+ // webglHeat.clear();
331
+ ```
332
+
333
+ ### 3.11 地形剖切 / 开挖(`examples/public/examples/html/analysis/terraincliping.html:108-176`)
334
+
335
+ ```js
336
+ // 来源: terraincliping.html L108-176
337
+ // TerrainClipping = 底面 + 侧墙贴图;positions 与 direction 互斥
338
+ const clipping = new ANOVGIS.TerrainClipping(viewer, {
339
+ lerpInterval: 200, // 侧墙贴图过渡间隔
340
+ bottomImage: '../modelData/images/clipping/excavate_bottom.jpeg',
341
+ sideImage: '../modelData/images/clipping/excavate_side.png'
342
+ });
343
+ clipping.enable = true;
344
+ clipping.height = 100; // 开挖深度(米)
345
+
346
+ // 任意 Draw* 工具拿到 Cartesian3[] 后直接赋给 positions
347
+ new ANOVGIS.DrawPolygon(viewer, {
348
+ justDraw: true, clampToGround: true, fill: false,
349
+ onCompleted(positions) { clipping.positions = positions; }
350
+ }).startDraw();
351
+
352
+ // 也支持 DrawPolyLine / DrawRectangle / DrawCircle 任意一种
353
+ // 还原:clipping.positions = [];
354
+ // 单向裁剪(与 positions 互斥,后设者生效):
355
+ // clipping.direction = 'up'; // up|down|left|right|front|back
356
+ ```
357
+
358
+ ### 3.12 风场粒子(`examples/public/examples/html/analysis/windlayer.html:65-109, 118-134`)
359
+
360
+ ```js
361
+ // 来源: windlayer.html L65-109
362
+ // data 为 grib-json:含 u/v 两个 component 的 [{ header, data }]
363
+ const data = await fetch('../modelData/json/beijing_wind.json').then(r => r.json());
364
+
365
+ const windLayer = new ANOVGIS.WindLayer({
366
+ colorScale: ['rgb(255,255,255)'], // 单色;多色可填色阶数组
367
+ frameRate: 16, // 帧率
368
+ maxAge: 60, // 粒子存活帧
369
+ globalAlpha: 0.9, // 拖尾透明度
370
+ velocityScale: 1 / 30, // 速度缩放
371
+ paths: 2000 // 粒子数量
372
+ });
373
+ windLayer.setData(data);
374
+ viewer.addLayer(windLayer);
375
+
376
+ // 运行时调参(按相机高度动态速度示例:windlayer.html:111-134)
377
+ viewer.camera.changed.addEventListener(() => {
378
+ const h = viewer.camera.positionCartographic.height;
379
+ windLayer.setOptions({ velocityScale: h < 5000 ? 0.001 : 0.03 });
380
+ });
381
+ // windLayer.show = false; // 显隐
382
+ // windLayer.setOptions({ paths: 3000, lineWidth: 2 });
383
+ ```
384
+
385
+ ### 3.13 水坝开闸放水 — `examples/public/examples/html/analysis/damWaterRelease.html` L189-L293
386
+
387
+ ```js
388
+ // 来源: damWaterRelease.html L222-L293
389
+ // 关键 API: ANOVGIS.DamWaterRelease
390
+ // 13 个闸门位置 × 流量档次(light/medium/heavy/flood) × 喷射形状(锥/圆/矩形)
391
+ this.damRelease = new ANOVGIS.DamWaterRelease(viewer, {
392
+ damCenter: [115.602, 32.432],
393
+ gatePositions: gatePositions, // [[lng, lat, height], ...] × 13
394
+ gateHeight: 28,
395
+ sprayHeading: this.sprayParams.heading,
396
+ sprayPitch: this.sprayParams.pitch,
397
+ emitterType: this.emitterType, // 'cone' | 'circle' | 'box'
398
+ coneAngle: this.shapeParams.coneAngle,
399
+ flowPreset: this.flowLevel, // 'light' | 'medium' | 'heavy' | 'flood'
400
+ particleImageSize: 24,
401
+ startScale: 0.8,
402
+ });
403
+ this.damRelease.addToScene(); // 加入场景
404
+
405
+ // 单闸控制
406
+ onGateToggle(idx) { this.damRelease.setGateOpen(idx, this.gates[idx].open); }
407
+ openAll() { this.damRelease.openAllGates(); }
408
+ closeAll() { this.damRelease.closeAllGates(); }
409
+ setFlow(level) { this.damRelease.setFlowLevel(level); }
410
+ setEmitterShape(type) {
411
+ this.damRelease.updateEmitterShape({
412
+ emitterType: type, coneAngle: this.shapeParams.coneAngle,
413
+ circleRadius: this.shapeParams.circleRadius,
414
+ boxWidth: this.shapeParams.boxWidth, boxHeight: this.shapeParams.boxHeight,
415
+ });
416
+ }
417
+ onSprayChange() { this.damRelease.updateSprayDirection(this.sprayParams.heading, this.sprayParams.pitch); }
418
+ ```
419
+
420
+ ### 3.14 定位测试(全图元覆盖) — `examples/public/examples/html/analysis/locateTest.html` L116-L399
421
+
422
+ ```js
423
+ // 来源: locateTest.html L116-L360
424
+ // 关键 API: VectorLayer / PrimitiveLayer / TilesetLayer / HtmlLayer
425
+ // 30+ 各类图元 + viewer.flyTo / zoomTo / flyToTileset
426
+ window.viewer = new ANOVGIS.Viewer('cesiumContainer', {
427
+ defaultView: [116.2, 39.7, 116.7, 40.1],
428
+ geocoderType: ANOVGIS.GeocoderType.TIANDITU,
429
+ });
430
+ const vectorLayer = new ANOVGIS.VectorLayer();
431
+ const primitiveLayer = new ANOVGIS.PrimitiveLayer();
432
+ const tilesetLayer = new ANOVGIS.TilesetLayer();
433
+ const htmlLayer = new ANOVGIS.HtmlLayer();
434
+ viewer.addLayer(vectorLayer);
435
+ viewer.addLayer(primitiveLayer);
436
+ viewer.addLayer(tilesetLayer);
437
+ viewer.addLayer(htmlLayer);
438
+
439
+ // Vector 图元(挂到 vectorLayer)
440
+ new ANOVGIS.Point([116.390, 39.900], { color: Cesium.Color.WHITE, pixelSize: 12 });
441
+ new ANOVGIS.Polyline([[116.392,39.902],[116.398,39.908],[116.404,39.902]], { width: 6, material: Cesium.Color.RED });
442
+ new ANOVGIS.Polygon([[116.406,39.900],[116.412,39.900],[116.412,39.906],[116.406,39.906]], { material: 'rgba(255,165,0,0.6)' });
443
+ new ANOVGIS.Circle([116.414, 39.900], 300);
444
+ new ANOVGIS.Ellipse([116.420, 39.900], 400, 200);
445
+ new ANOVGIS.Wall([[116.390,39.910],[116.396,39.914],[116.402,39.910]], { minimumHeight: 0, maximumHeight: 80 });
446
+ new ANOVGIS.Box([116.406, 39.910], 80, 80, 80);
447
+ new ANOVGIS.Cylinder([116.412, 39.910], 120, 30, 30);
448
+ new ANOVGIS.Ellipsoid([116.418, 39.910], { x: 50, y: 50, z: 60 });
449
+ new ANOVGIS.Billboard([116.408, 39.920], { image: '../modelData/images/biaozhu1.png' });
450
+ new ANOVGIS.Label([116.414, 39.920], { text: 'Label 文字', font: '24px sans-serif', color: '#00ffff' });
451
+ new ANOVGIS.Model({ position: [116.360, 39.930, 80], url: '../modelData/gltf/Cesium_Air.glb', scale: 1 });
452
+ new ANOVGIS.Tileset({ url: '../modelData/3dtiles/topchaoyangbuilding3dtiles/tileset.json' });
453
+
454
+ // Primitive 图元(挂到 primitiveLayer)
455
+ new ANOVGIS.BillboardPrimitive([116.440, 39.870], '../modelData/images/biaozhu1.png');
456
+ new ANOVGIS.BounceBillboardPrimitive([116.444, 39.872], '../modelData/images/biaozhu1.png');
457
+ new ANOVGIS.ScanCirclePrimitive([116.462, 39.852], 500);
458
+ new ANOVGIS.TrailLinePrimitive([[116.466,39.856],[116.470,39.860],[116.472,39.856]], 3);
459
+ new ANOVGIS.WaterPrimitive([[116.448,39.842],[116.452,39.842],[116.452,39.846],[116.448,39.846]]);
460
+ layer.addGraphic(g);
461
+
462
+ // 定位 API
463
+ viewer.flyTo(t, 2.2, 0, -45, 0, () => console.log('flyTo 完成'));
464
+ viewer.zoomTo(t);
465
+ viewer.flyToTileset(t, 2, 0.5, -35); // 3D Tiles 专用
466
+ ```
467
+
468
+ ### 3.15 天地图地名搜索 — `examples/public/examples/html/analysis/geocoder.html` L160-L295
469
+
470
+ ```js
471
+ // 来源: geocoder.html L161-L293
472
+ // 关键 API: ANOVGIS.TiandituGeocoderService + Cesium.Geocoder + viewModel._searchCommand
473
+ window.viewer = new ANOVGIS.Viewer("cesiumContainer", { vrButton: false });
474
+ viewer.imageryLayers.addImageryProvider(
475
+ ANOVGIS.ImageryLayerFactory.createImageryLayer(ANOVGIS.ImageryType.TDT, {
476
+ style: "img", key: globalConfig.tdtKey
477
+ })
478
+ );
479
+
480
+ let tinadituService = new ANOVGIS.TiandituGeocoderService(
481
+ 'https://api.tianditu.gov.cn/v2/search',
482
+ globalConfig.tdtKey, // tk 天地图 key
483
+ {}
484
+ );
485
+ let geocoder = new Cesium.Geocoder({
486
+ container: 'geocoder', scene: viewer.scene,
487
+ geocoderServices: [tinadituService]
488
+ });
489
+ let geocoderViewModel = geocoder.viewModel;
490
+ let translateLocal = new ANOVGIS.TranslateLocal(viewer);
491
+ translateLocal && translateLocal.toChinese(); // 控件中文化
492
+
493
+ // 解析纯经纬度输入(lng, lat[, height]) 直接飞过去
494
+ if (splitQuery.length === 2 || splitQuery.length === 3) {
495
+ let longitude = +splitQuery[0], latitude = +splitQuery[1];
496
+ let height = splitQuery.length === 3 ? +splitQuery[2] : 1000;
497
+ ANOVGIS.LocateUtil.flyToPosition(viewer, [longitude, latitude], 0, -70, height, 3, null);
498
+ }
499
+ // 否则走天地图 API 模糊匹配: postStr = { 'keyWord': query, 'level': 11, 'mapBound': '-180,-90,180,90', 'queryType': 4, ... }
500
+ // result.data.suggests[] → viewModel.suggestions.push({displayName, destination, gbCode})
501
+ // 点选条目 → viewModel.destinationFound(viewModel, destination) 触发飞行
502
+ ```
503
+
504
+ ### 3.16 旧版 geocoder — `examples/public/examples/html/analysis/geocoderOld.html` L105-L174
505
+
506
+ ```js
507
+ // 来源: geocoderOld.html L106-L132
508
+ // 关键 API: ANOVGIS.TiandituGeocoderService 实例化 + Viewer.geocoderType=TIANDITU
509
+ let tinadituService = new ANOVGIS.TiandituGeocoderService(
510
+ 'https://api.tianditu.gov.cn/v2/search',
511
+ globalConfig.tdtKey,
512
+ {}
513
+ );
514
+ window.viewer = new ANOVGIS.Viewer("cesiumContainer", {
515
+ navigationHelpButton: true,
516
+ geocoderType: ANOVGIS.GeocoderType.TIANDITU, // 让 viewer 用天地图 geocoder
517
+ copyRight: false
518
+ });
519
+ viewer.imageryLayers.addImageryProvider(
520
+ ANOVGIS.ImageryLayerFactory.createImageryLayer(ANOVGIS.ImageryType.TDT, {
521
+ style: "img", key: globalConfig.tdtKey
522
+ })
523
+ );
524
+ // 注: ANOVGIS.TiandituGeocoder + container:'toolbar' 的写法在本 demo 被全部注释,
525
+ // 生产代码请参考 3.15 (geocoder.html) 用 Cesium.Geocoder + TiandituGeocoderService 的完整接法。
526
+ ```
527
+
528
+ ### 3.17 山西限定 geocoder — `examples/public/examples/html/analysis/geocoder_shanxi.html` L105-L143
529
+
530
+ ```js
531
+ // 来源: geocoder_shanxi.html L105-L125
532
+ // 关键 API: ANOVGIS.TiandituGeocoderService_shanxi + GeocoderType.TIANDITU_SHANXI
533
+ let tinadituService = new ANOVGIS.TiandituGeocoderService_shanxi(
534
+ null,
535
+ '04x-Fu5nGOnU7RY7', // 山西专用 tk
536
+ {}
537
+ );
538
+ window.viewer = new ANOVGIS.Viewer("cesiumContainer", {
539
+ navigationHelpButton: true,
540
+ geocoderType: ANOVGIS.GeocoderType.TIANDITU_SHANXI, // 限定为山西数据源
541
+ });
542
+ // 山西 影像底图 + 山西 注记底图 双层
543
+ viewer.imageryLayers.addImageryProvider(
544
+ ANOVGIS.ImageryLayerFactory.createImageryLayer(ANOVGIS.ImageryType.TDT, { style: "img", key: globalConfig.tdtKey })
545
+ );
546
+ viewer.imageryLayers.addImageryProvider(
547
+ ANOVGIS.ImageryLayerFactory.createImageryLayer(ANOVGIS.ImageryType.TDT, { style: "cva", key: globalConfig.tdtKey })
548
+ );
549
+ ```
550
+
551
+ ### 3.18 自定义 Shader 注入 — `examples/public/examples/html/analysis/test.html` L46-L99
552
+
553
+ ```js
554
+ // 来源: test.html L46-L99
555
+ // 关键 API: Cesium.CustomShader + Cesium.Model.fromGltfAsync + ANOVGIS.LocateUtil.flyToPosition
556
+ // 注意: 此 demo 用了 Cesium.ExperimentalFeatures.enableModelExperimental = true (生产慎用)
557
+ window.viewer = new ANOVGIS.Viewer("cesiumContainer", {
558
+ orderIndependentTranslucency: false,
559
+ geocoderType: ANOVGIS.GeocoderType.TIANDITU,
560
+ });
561
+ viewer.scene.screenSpaceCameraController.enableCollisionDetection = false;
562
+
563
+ let textureUniformShader = this.getCustomShader();
564
+ Cesium.ExperimentalFeatures.enableModelExperimental = true;
565
+ Cesium.Model.fromGltfAsync({
566
+ url: '../modelData/weather/skyDome.glb',
567
+ customShader: textureUniformShader,
568
+ modelMatrix: this.generateModelMatrix([116.40969, 39.951964, 20000], [0, 0, 0], [50000, 50000, 50000])
569
+ }).then(function(model) {
570
+ window.viewer.scene.primitives.add(model);
571
+ });
572
+
573
+ // 每帧推进 u_time
574
+ const startTime = performance.now();
575
+ viewer.scene.postUpdate.addEventListener(function () {
576
+ textureUniformShader.setUniform("u_time", (performance.now() - startTime) / 1000);
577
+ });
578
+ ANOVGIS.LocateUtil.flyToPosition(viewer, '116.40969, 39.951964', 0, -4, 3000, 3, null);
579
+ // 签名: (viewer, "lng,lat", heading, pitch, height, duration, callback)
580
+ ```
581
+
582
+ ### 3.19 windlayer2.html — ⚠️ 开发中版本,不推荐
583
+
584
+ > `windlayer2.html` 引用了未声明的全局 `data` 和 `flow`(ReferenceError),**不适合作为生产推荐用法**。
585
+ > 生产环境请使用 **3.12 windlayer.html**,这是已跑通的稳定版本。