cesium-xs-sdk 1.0.0

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.
@@ -0,0 +1,43 @@
1
+ /**
2
+ * 标绘图元类型枚举
3
+ * 对应 cesium-plot-js 支持的军事标绘类型
4
+ */
5
+ export const PlotGraphicType = {
6
+ // 面型标绘
7
+ TRIANGLE: 'triangle',
8
+ SECTOR: 'sector',
9
+ ELLIPSE: 'ellipse',
10
+ FINE_ARROW: 'fineArrow',
11
+ ASSAULT_DIRECTION: 'assaultDirection',
12
+ ATTACK_ARROW: 'attackArrow',
13
+ SWALLOWTAIL_ATTACK_ARROW: 'swallowtailAttackArrow',
14
+ SQUAD_COMBAT: 'squadCombat',
15
+ SWALLOWTAIL_SQUAD_COMBAT: 'swallowtailSquadCombat',
16
+ DOUBLE_ARROW: 'doubleArrow',
17
+
18
+ // 线型标绘
19
+ STRAIGHT_ARROW: 'straightArrow',
20
+ CURVED_ARROW: 'curvedArrow',
21
+ CURVE: 'curve'
22
+ };
23
+
24
+ /**
25
+ * 标绘图元分类
26
+ */
27
+ export const PlotGraphicCategory = {
28
+ POLYGON: 'polygon',
29
+ LINE: 'line'
30
+ };
31
+
32
+ /**
33
+ * 判断标绘类型是否为线型
34
+ * @param {string} plotType PlotGraphicType
35
+ * @returns {boolean}
36
+ */
37
+ export function isLinePlotType(plotType) {
38
+ return [
39
+ PlotGraphicType.STRAIGHT_ARROW,
40
+ PlotGraphicType.CURVED_ARROW,
41
+ PlotGraphicType.CURVE
42
+ ].includes(plotType);
43
+ }
@@ -0,0 +1,600 @@
1
+ import { Config } from '../core/Config.js';
2
+
3
+ /**
4
+ * 图层类型枚举
5
+ * @readonly
6
+ * @enum {string}
7
+ */
8
+ export const LayerType = Object.freeze({
9
+ /** XYZ 瓦片服务 */
10
+ XYZ: 'xyz',
11
+ /** WMTS 瓦片服务 */
12
+ WMTS: 'wmts',
13
+ /** WMS 动态地图服务 */
14
+ WMS: 'wms',
15
+ /** TMS 瓦片服务 */
16
+ TMS: 'tms',
17
+ /** 单张图片 */
18
+ SINGLE_IMAGE: 'single_image',
19
+ /** 地形数据 */
20
+ TERRAIN: 'terrain',
21
+ /** 3D Tiles 模型数据集 */
22
+ '3DTILES': '3dtiles'
23
+ });
24
+
25
+
26
+ // ========== 私有工厂函数(文件内部) ==========
27
+
28
+ /**
29
+ * 根据 URL 自动推断图层类型
30
+ * @param {string} url 服务地址
31
+ * @returns {string} LayerType 值
32
+ */
33
+ function autoDetectType(url) {
34
+ const u = url.toLowerCase();
35
+
36
+ // 1. 3DTiles — 以 .json 结尾或包含 3dtiles/3d_tiles
37
+ if (/\.json(?:[?#]|$)/.test(u) || u.includes('3dtiles') || u.includes('3d_tiles')) {
38
+ return LayerType['3DTILES'];
39
+ }
40
+
41
+ // 2. 地形 — 包含 terrain / dem / gdem / 水深 / elevation 关键词
42
+ if (/\/(?:terrain|dem|gdem|水深|elevation|ele)(\/|$)/.test(u) || /[?&#]terrain=/.test(u)) {
43
+ return LayerType.TERRAIN;
44
+ }
45
+
46
+ // 3. WMTS — 包含 wmts 关键词 或 TileMatrixSet 参数
47
+ if (u.includes('wmts') || u.includes('tilematrixset')) {
48
+ return LayerType.WMTS;
49
+ }
50
+
51
+ // 4. WMS — 包含 wms 关键词 或 GetMap 请求参数
52
+ if (u.includes('wms') || u.includes('getmap') || u.includes('request=getmap')) {
53
+ return LayerType.WMS;
54
+ }
55
+
56
+ // 5. TMS — 包含 tms 关键词 或 {-y} 反转瓦片
57
+ if (u.includes('tms') || u.includes('{-y}')) {
58
+ return LayerType.TMS;
59
+ }
60
+
61
+ // 6. XYZ — URL 模板包含 {z} {x} {y}
62
+ if (/\{[xyz]\}/.test(u)) {
63
+ return LayerType.XYZ;
64
+ }
65
+
66
+ // 7. 单张影像 — 有常见图片后缀且无瓦片模板
67
+ if (/\.(?:png|jpe?g|tiff?|gif|bmp|img)(?:[?#]|$)/.test(u)) {
68
+ return LayerType.SINGLE_IMAGE;
69
+ }
70
+
71
+ // 默认按 XYZ 处理(最常见的瓦片格式)
72
+ return LayerType.XYZ;
73
+ }
74
+
75
+ /**
76
+ * 根据类型创建对应的 Cesium Provider
77
+ * @param {string} type LayerType 值
78
+ * @param {string} url 服务地址
79
+ * @param {Object} opts 用户传入的配置
80
+ * @returns {Object} Cesium Provider 实例
81
+ */
82
+ function createProviderByType(type, url, opts) {
83
+ switch (type) {
84
+ case LayerType.XYZ:
85
+ case LayerType.TMS:
86
+ // XYZ / TMS 均使用 UrlTemplateImageryProvider
87
+ return new Cesium.UrlTemplateImageryProvider({ url, ...opts });
88
+
89
+ case LayerType.WMTS:
90
+ return new Cesium.WebMapTileServiceImageryProvider({
91
+ url,
92
+ layer: opts.layer,
93
+ style: opts.style || 'default',
94
+ format: opts.format || 'image/jpeg',
95
+ tileMatrixSetID: opts.tileMatrixSetID || 'EPSG:4326',
96
+ ...opts
97
+ });
98
+
99
+ case LayerType.WMS:
100
+ return new Cesium.WebMapServiceImageryProvider({
101
+ url,
102
+ layers: opts.layers || '',
103
+ parameters: { transparent: true, format: 'image/png', ...opts.parameters },
104
+ ...opts
105
+ });
106
+
107
+ case LayerType.SINGLE_IMAGE:
108
+ return new Cesium.SingleTileImageryProvider({
109
+ url,
110
+ rectangle: opts.extent ? Cesium.Rectangle.fromDegrees(...opts.extent) : undefined,
111
+ credit: opts.credit || '',
112
+ ...opts
113
+ });
114
+
115
+ case LayerType.TERRAIN:
116
+ // fromUrl 返回 Promise,由 addProviderToViewer 统一 await
117
+ return Cesium.CesiumTerrainProvider.fromUrl(url, {
118
+ requestWaterMask: opts.requestWaterMask ?? false,
119
+ requestVertexNormals: opts.requestVertexNormals ?? false,
120
+ ...opts
121
+ });
122
+
123
+ case LayerType['3DTILES']:
124
+ return new Cesium.Cesium3DTileset({
125
+ url,
126
+ maximumScreenSpaceError: opts.maximumScreenSpaceError ?? 16,
127
+ maximumMemoryUsage: opts.maximumMemoryUsage ?? 512,
128
+ ...opts
129
+ });
130
+
131
+ default:
132
+ throw new Error(`SceneModule: 不支持的图层类型 "${type}",可用值: ${Object.values(LayerType).join(', ')}`);
133
+ }
134
+ }
135
+
136
+ /**
137
+ * 将 Provider 添加到 Viewer 并返回句柄
138
+ * terrain 类型返回 provider 自身(不是 layer)
139
+ * 3dtiles 类型返回 tileset
140
+ * 其余返回 ImageryLayer
141
+ * @param {string} type LayerType
142
+ * @param {Object} viewer Cesium.Viewer
143
+ * @param {Object} providerType Cesium Provider
144
+ * @param {boolean} visible 是否可见
145
+ * @returns {Object} layer/tileset/provider
146
+ */
147
+ async function addProviderToViewer(type, viewer, providerType, visible) {
148
+ if (type === LayerType.TERRAIN) {
149
+ const provider = await providerType
150
+ viewer.terrainProvider = provider;
151
+ return provider;
152
+ }
153
+ if (type === LayerType['3DTILES']) {
154
+ const tileset = viewer.scene.primitives.add(providerType);
155
+ tileset.show = visible ?? true;
156
+ return tileset;
157
+ }
158
+ const layer = viewer.imageryLayers.addImageryProvider(providerType);
159
+ layer.show = visible ?? true;
160
+ return layer;
161
+ }
162
+
163
+
164
+ // ========== 图层包装器 ==========
165
+
166
+ /**
167
+ * 影像图层包装器
168
+ */
169
+ class ImageryLayerWrapper {
170
+ constructor(sceneModule, layer, layerId) {
171
+ this._layer = layer;
172
+ this._sceneModule = sceneModule;
173
+ this._layerId = layerId;
174
+ this._pickable = true;
175
+ this._eventEnabled = true;
176
+ }
177
+
178
+ setVisible(visible) {
179
+ this._layer.show = visible;
180
+ return this;
181
+ }
182
+
183
+ setAlpha(alpha) {
184
+ this._layer.alpha = alpha;
185
+ return this;
186
+ }
187
+
188
+ setBrightness(brightness) {
189
+ this._layer.brightness = brightness;
190
+ return this;
191
+ }
192
+
193
+ setContrast(contrast) {
194
+ this._layer.contrast = contrast;
195
+ return this;
196
+ }
197
+
198
+ setHue(hue) {
199
+ this._layer.hue = hue;
200
+ return this;
201
+ }
202
+
203
+ setSaturation(saturation) {
204
+ this._layer.saturation = saturation;
205
+ return this;
206
+ }
207
+
208
+ setGamma(gamma) {
209
+ this._layer.gamma = gamma;
210
+ return this;
211
+ }
212
+
213
+ enableEdit(enabled) {
214
+ this._pickable = enabled;
215
+ return this;
216
+ }
217
+
218
+ enableEvent(enabled) {
219
+ this._eventEnabled = enabled;
220
+ if (this._layer.imageryProvider && this._layer.imageryProvider.enablePickFeatures) {
221
+ this._layer.imageryProvider.enablePickFeatures = enabled;
222
+ }
223
+ return this;
224
+ }
225
+
226
+ getExtent() {
227
+ const provider = this._layer.imageryProvider;
228
+ if (provider && provider.rectangle) {
229
+ const rect = provider.rectangle;
230
+ return {
231
+ west: Cesium.Math.toDegrees(rect.west),
232
+ south: Cesium.Math.toDegrees(rect.south),
233
+ east: Cesium.Math.toDegrees(rect.east),
234
+ north: Cesium.Math.toDegrees(rect.north)
235
+ };
236
+ }
237
+ return null;
238
+ }
239
+
240
+ getRange() {
241
+ const provider = this._layer.imageryProvider;
242
+ return {
243
+ minLevel: provider.minimumLevel || 0,
244
+ maxLevel: provider.maximumLevel || 18
245
+ };
246
+ }
247
+
248
+ getLayer() {
249
+ return this._layer;
250
+ }
251
+
252
+ remove() {
253
+ this._sceneModule.removeLayer(this._layerId);
254
+ return this;
255
+ }
256
+ }
257
+
258
+ /**
259
+ * 地形图层包装器
260
+ */
261
+ class TerrainLayerWrapper {
262
+ constructor(sceneModule, provider, layerId) {
263
+ this._provider = provider;
264
+ this._sceneModule = sceneModule;
265
+ this._layerId = layerId;
266
+ this._visible = true;
267
+ }
268
+
269
+ setVisible(visible) {
270
+ this._visible = visible;
271
+ return this;
272
+ }
273
+
274
+ getExtent() {
275
+ if (this._provider.rectangle) {
276
+ const rect = this._provider.rectangle;
277
+ return {
278
+ west: Cesium.Math.toDegrees(rect.west),
279
+ south: Cesium.Math.toDegrees(rect.south),
280
+ east: Cesium.Math.toDegrees(rect.east),
281
+ north: Cesium.Math.toDegrees(rect.north)
282
+ };
283
+ }
284
+ return { west: -180, south: -85, east: 180, north: 85 };
285
+ }
286
+
287
+ getProvider() {
288
+ return this._provider;
289
+ }
290
+
291
+ remove() {
292
+ this._sceneModule.removeLayer(this._layerId);
293
+ return this;
294
+ }
295
+ }
296
+
297
+ /**
298
+ * 3DTiles 图层包装器
299
+ */
300
+ class TilesetLayerWrapper {
301
+ constructor(sceneModule, tileset, layerId) {
302
+ this._tileset = tileset;
303
+ this._sceneModule = sceneModule;
304
+ this._layerId = layerId;
305
+ }
306
+
307
+ setVisible(visible) {
308
+ this._tileset.show = visible;
309
+ return this;
310
+ }
311
+
312
+ setStyle(style) {
313
+ this._tileset.style = style;
314
+ return this;
315
+ }
316
+
317
+ getExtent() {
318
+ if (this._tileset.boundingSphere) {
319
+ const bs = this._tileset.boundingSphere;
320
+ const cartographic = Cesium.Cartographic.fromCartesian(bs.center);
321
+ const rect = this._tileset.rectangle;
322
+ if (rect) {
323
+ return {
324
+ west: Cesium.Math.toDegrees(rect.west),
325
+ south: Cesium.Math.toDegrees(rect.south),
326
+ east: Cesium.Math.toDegrees(rect.east),
327
+ north: Cesium.Math.toDegrees(rect.north),
328
+ center: [
329
+ Cesium.Math.toDegrees(cartographic.longitude),
330
+ Cesium.Math.toDegrees(cartographic.latitude)
331
+ ]
332
+ };
333
+ }
334
+ }
335
+ return null;
336
+ }
337
+
338
+ locateTo() {
339
+ return this._sceneModule.viewer.zoomTo(this._tileset);
340
+ }
341
+
342
+ getTileset() {
343
+ return this._tileset;
344
+ }
345
+
346
+ remove() {
347
+ this._sceneModule.removeLayer(this._layerId);
348
+ return this;
349
+ }
350
+ }
351
+
352
+
353
+ // ========== SceneModule ==========
354
+
355
+ /**
356
+ * 场景+图层管理模块
357
+ */
358
+ export class SceneModule {
359
+ constructor(viewer) {
360
+ this.viewer = viewer;
361
+ this.config = Config.getInstance().getConfig();
362
+ this.layerMap = new Map(); // 图层缓存(ID -> Wrapper 实例)
363
+ }
364
+
365
+ // ========== 坐标转换 ==========
366
+
367
+ lonLatToWorld(lon, lat, height = 0) {
368
+ return Cesium.Cartesian3.fromDegrees(lon, lat, height);
369
+ }
370
+
371
+ worldToLonLat(cartesian) {
372
+ const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
373
+ return [
374
+ Cesium.Math.toDegrees(cartographic.longitude),
375
+ Cesium.Math.toDegrees(cartographic.latitude),
376
+ cartographic.height
377
+ ];
378
+ }
379
+
380
+ screenToWorld(x, y) {
381
+ const screenPosition = new Cesium.Cartesian2(x, y);
382
+ if (this.viewer.scene.pickPositionSupported) {
383
+ const precisePosition = this.viewer.scene.pickPosition(screenPosition);
384
+ if (precisePosition) return precisePosition;
385
+ }
386
+ const ray = this.viewer.camera.getPickRay(screenPosition);
387
+ const globePosition = this.viewer.scene.globe.pick(ray, this.viewer.scene);
388
+ if (globePosition) return globePosition;
389
+ return this.viewer.camera.pickEllipsoid(screenPosition, Cesium.Ellipsoid.WGS84);
390
+ }
391
+
392
+ worldToScreen(cartesian) {
393
+ return this.viewer.scene.cartesianToCanvasCoordinates(cartesian);
394
+ }
395
+
396
+ screenToLonLat(x, y) {
397
+ const worldCoord = this.screenToWorld(x, y);
398
+ return worldCoord ? this.worldToLonLat(worldCoord) : null;
399
+ }
400
+
401
+ lonLatToScreen(lon, lat, height = 0) {
402
+ const worldCoord = this.lonLatToWorld(lon, lat, height);
403
+ return this.worldToScreen(worldCoord);
404
+ }
405
+
406
+ lonLatToCartographic(lon, lat, height = 0) {
407
+ return new Cesium.Cartographic(Cesium.Math.toRadians(lon), Cesium.Math.toRadians(lat), height);
408
+ }
409
+
410
+ cartographicToLonLat(cartographic) {
411
+ return [
412
+ Cesium.Math.toDegrees(cartographic.longitude),
413
+ Cesium.Math.toDegrees(cartographic.latitude),
414
+ cartographic.height
415
+ ];
416
+ }
417
+
418
+ // ========== 统一图层工厂 ==========
419
+
420
+ /**
421
+ * 通用图层创建工厂(自动从 URL 推断类型)
422
+ * @param {string} url 服务地址
423
+ * @param {Object} [options={}] 配置选项
424
+ * @param {string} [options.type] 强制指定图层类型,见 {@link LayerType},不提供则自动推断
425
+ * @param {string} [options.layerId] 图层唯一 ID,不提供则自动生成
426
+ * @param {boolean} [options.visible=true] 是否可见
427
+ * @param {number} [options.minimumLevel=0] 最小层级
428
+ * @param {number} [options.maximumLevel=18] 最大层级
429
+ * @param {string} [options.credit=''] 版权信息
430
+ * @param {Array<number>} [options.extent] 范围 [west, south, east, north](单张影像用)
431
+ * @param {string} [options.layer] WMTS 层名
432
+ * @param {string} [options.style] WMTS 样式
433
+ * @param {string} [options.format] WMTS 格式
434
+ * @param {string} [options.tileMatrixSetID] WMTS 瓦片矩阵集
435
+ * @param {string} [options.layers] WMS 图层名
436
+ * @param {Object} [options.parameters] WMS 额外参数
437
+ * @param {boolean} [options.requestWaterMask] 地形请求水面遮罩
438
+ * @param {boolean} [options.requestVertexNormals] 地形请求顶点法线
439
+ * @param {number} [options.maximumScreenSpaceError] 3DTiles 最大屏幕空间误差
440
+ * @param {number} [options.maximumMemoryUsage] 3DTiles 最大内存占用(MB)
441
+ * @param {boolean} [options.autoLocate=true] 3DTiles 创建后自动定位
442
+ * @returns {ImageryLayerWrapper|TerrainLayerWrapper|TilesetLayerWrapper} 图层包装器
443
+ * @example
444
+ * // 自动推断类型(推荐)
445
+ * sceneModule.createLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { layerId: 'osm' });
446
+ * sceneModule.createLayer('https://example.com/tileset.json');
447
+ * sceneModule.createLayer('https://example.com/terrain');
448
+ *
449
+ * // 显式指定类型(覆盖自动推断)
450
+ * sceneModule.createLayer('https://example.com/wmts', { type: LayerType.WMTS, layer: 'vec' });
451
+ */
452
+ async createLayer(url, options = {}) {
453
+ const type = options.type ?? autoDetectType(url);
454
+ const layerId = options.layerId || `${type}_${Date.now()}`;
455
+
456
+ if (this.layerMap.has(layerId)) {
457
+ console.warn(`图层 ${layerId} 已存在`);
458
+ return this.layerMap.get(layerId);
459
+ }
460
+
461
+ const visible = options.visible !== false;
462
+ const provider = createProviderByType(type, url, options);
463
+ const layerOrEntity = await addProviderToViewer(type, this.viewer, provider, visible);
464
+ const wrapper = this.#wrapLayer(type, layerOrEntity, layerId);
465
+
466
+ // 3DTiles 自动定位(readyPromise 已移除,改用 initialTilesLoaded 一次性事件)
467
+ if (type === LayerType['3DTILES'] && options.autoLocate !== false) {
468
+ const removeListener = layerOrEntity.initialTilesLoaded.addEventListener(() => {
469
+ removeListener();
470
+ this.viewer.zoomTo(layerOrEntity);
471
+ });
472
+ }
473
+
474
+ this.layerMap.set(layerId, wrapper);
475
+ console.log(`${type} 图层 ${layerId} 创建成功`);
476
+ return wrapper;
477
+ }
478
+
479
+ /** 根据类型实例化对应包装器 */
480
+ #wrapLayer(type, layerOrEntity, layerId) {
481
+ if (type === LayerType.TERRAIN) {
482
+ return new TerrainLayerWrapper(this, layerOrEntity, layerId);
483
+ }
484
+ if (type === LayerType['3DTILES']) {
485
+ return new TilesetLayerWrapper(this, layerOrEntity, layerId);
486
+ }
487
+ return new ImageryLayerWrapper(this, layerOrEntity, layerId);
488
+ }
489
+
490
+ // ========== 图层管理 ==========
491
+
492
+ /**
493
+ * 删除图层
494
+ * @param {string} layerId 图层 ID
495
+ * @returns {boolean} 是否删除成功
496
+ */
497
+ removeLayer(layerId) {
498
+ if (!this.layerMap.has(layerId)) {
499
+ console.warn(`图层 ${layerId} 不存在`);
500
+ return false;
501
+ }
502
+
503
+ const layer = this.layerMap.get(layerId);
504
+
505
+ if (layer instanceof ImageryLayerWrapper) {
506
+ this.viewer.imageryLayers.remove(layer.getLayer());
507
+ } else if (layer instanceof TerrainLayerWrapper) {
508
+ // 地形无法直接删除,重置为默认椭球地形
509
+ this.viewer.terrainProvider = new Cesium.EllipsoidTerrainProvider();
510
+ } else if (layer instanceof TilesetLayerWrapper) {
511
+ this.viewer.scene.primitives.remove(layer.getTileset());
512
+ }
513
+
514
+ this.layerMap.delete(layerId);
515
+ return true;
516
+ }
517
+
518
+ /**
519
+ * 获取图层
520
+ * @param {string} layerId 图层 ID
521
+ * @returns {ImageryLayerWrapper|TerrainLayerWrapper|TilesetLayerWrapper|undefined}
522
+ */
523
+ getLayer(layerId) {
524
+ return this.layerMap.get(layerId);
525
+ }
526
+
527
+ // ========== 场景定位 ==========
528
+
529
+ /**
530
+ * 相机飞到指定经纬度
531
+ * @param {Object} params 飞行参数
532
+ * @param {number} params.lon 经度
533
+ * @param {number} params.lat 纬度
534
+ * @param {number} [params.height=2000] 相机高度
535
+ * @param {number} [params.heading=0] 偏航角
536
+ * @param {number} [params.pitch=-90] 俯仰角
537
+ * @param {number} [params.roll=0] 翻滚角
538
+ * @param {number} [params.duration=3.0] 飞行时长(秒)
539
+ * @returns {Promise<boolean>}
540
+ */
541
+ flyToLonLat(params = {}) {
542
+ const {
543
+ lon, lat,
544
+ height = 2000,
545
+ heading = 0,
546
+ pitch = -90,
547
+ roll = 0,
548
+ duration = 3.0
549
+ } = params;
550
+
551
+ if (!Cesium.defined(lon) || !Cesium.defined(lat)) {
552
+ console.warn('flyToLonLat: 必须提供 lon、lat');
553
+ return Promise.resolve(false);
554
+ }
555
+
556
+ return this.viewer.camera.flyTo({
557
+ destination: Cesium.Cartesian3.fromDegrees(lon, lat, height),
558
+ orientation: {
559
+ heading: Cesium.Math.toRadians(heading),
560
+ pitch: Cesium.Math.toRadians(pitch),
561
+ roll: Cesium.Math.toRadians(roll)
562
+ },
563
+ duration
564
+ });
565
+ }
566
+
567
+ /**
568
+ * 设置相机视角(立即跳转,无飞行动画)
569
+ * @param {Object} params
570
+ * @param {number} params.lon 经度
571
+ * @param {number} params.lat 纬度
572
+ * @param {number} [params.height=500] 相机高度
573
+ * @param {number} [params.heading=0] 偏航角(默认北向)
574
+ * @param {number} [params.pitch=-90] 俯仰角(默认俯视)
575
+ * @param {number} [params.roll=0] 翻滚角
576
+ */
577
+ setView(params = {}) {
578
+ const {
579
+ lon, lat,
580
+ height = 500,
581
+ heading = 0,
582
+ pitch = -90,
583
+ roll = 0
584
+ } = params;
585
+
586
+ if (!Cesium.defined(lon) || !Cesium.defined(lat)) {
587
+ console.warn('setView: 必须提供 lon、lat');
588
+ return;
589
+ }
590
+
591
+ this.viewer.camera.setView({
592
+ destination: Cesium.Cartesian3.fromDegrees(lon, lat, height),
593
+ orientation: {
594
+ heading: Cesium.Math.toRadians(heading),
595
+ pitch: Cesium.Math.toRadians(pitch),
596
+ roll: Cesium.Math.toRadians(roll)
597
+ }
598
+ });
599
+ }
600
+ }