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,526 @@
1
+ import { BaseTool } from './BaseTool.js';
2
+
3
+ /**
4
+ * 选择类型枚举
5
+ */
6
+ export const SelectType = {
7
+ POINT: 'point', // 点选
8
+ RECTANGLE: 'rectangle', // 矩形框选
9
+ CIRCLE: 'circle' // 圆形框选
10
+ };
11
+
12
+ /**
13
+ * 选择工具
14
+ * 支持点选和框选(矩形、圆形)
15
+ */
16
+ export class SelectTool extends BaseTool {
17
+ constructor(editorModule, options = {}) {
18
+ super(editorModule, options);
19
+ this._selectType = options.selectType || SelectType.POINT;
20
+ this._isSelecting = false;
21
+ this._startPos = null;
22
+ this._tempEntities = [];
23
+ this._selectedIds = new Set();
24
+ this._selectionRect = null;
25
+ this._originalStyles = new Map(); // 记录选中前的原始样式
26
+ }
27
+
28
+ /**
29
+ * 设置选择类型
30
+ * @param {string} type SelectType
31
+ */
32
+ setSelectType(type) {
33
+ this._selectType = type;
34
+ return this;
35
+ }
36
+
37
+ getSelectType() {
38
+ return this._selectType;
39
+ }
40
+
41
+ onActivate() {
42
+ this.registerObserver('mouse:click', this._onClick.bind(this));
43
+ this.registerObserver('mouse:move', this._onMove.bind(this));
44
+ this.registerObserver('mouse:down', this._onMouseDown.bind(this));
45
+ this.registerObserver('mouse:up', this._onMouseUp.bind(this));
46
+ }
47
+
48
+ onDeactivate() {
49
+ this._cancelSelection();
50
+ this._clearSelectionRect();
51
+ }
52
+
53
+ _onMouseDown(data) {
54
+ // mouse:down passes movement object from BaseTool
55
+ const screenPos = data.position || data.endPosition;
56
+ if (!screenPos) return;
57
+
58
+ if (this._selectType !== SelectType.POINT) {
59
+ const lonLat = this.screenToLonLat({ x: screenPos.x, y: screenPos.y });
60
+ if (lonLat) {
61
+ this._startPos = lonLat;
62
+ this._isSelecting = true;
63
+ this._createSelectionStartMarker(lonLat);
64
+ }
65
+ }
66
+ }
67
+
68
+ _onMouseUp(data) {
69
+ const screenPos = data.position || data.endPosition;
70
+ if (!screenPos) return;
71
+
72
+ if (this._isSelecting && this._startPos) {
73
+ const lonLat = this.screenToLonLat({ x: screenPos.x, y: screenPos.y });
74
+ if (lonLat) {
75
+ this._finishSelection(lonLat);
76
+ }
77
+ }
78
+ }
79
+
80
+ _onClick(_lngLat, _entity, movement) {
81
+ if (this._selectType !== SelectType.POINT) return;
82
+
83
+ const screenPos = movement.position || (movement && movement.endPosition);
84
+ if (!screenPos) return;
85
+
86
+ const picked = this._viewer.scene.pick({ x: screenPos.x, y: screenPos.y });
87
+
88
+ if (Cesium.defined(picked) && Cesium.defined(picked.id)) {
89
+ const entityId = picked.id.id;
90
+
91
+ // 忽略临时图元
92
+ if (entityId && entityId.startsWith('__temp_')) return;
93
+ if (entityId && entityId.startsWith('__edit_handle_')) return;
94
+
95
+ if (this._isSelected(entityId)) {
96
+ this._deselect(entityId);
97
+ } else {
98
+ this._select(entityId);
99
+ }
100
+ } else {
101
+ // 点击空白处,清除所有选择
102
+ this._clearAllSelections();
103
+ }
104
+ }
105
+
106
+ _onMove(data) {
107
+ // mouse:move passes movement object from BaseTool
108
+ const screenPos = data.position || data.endPosition;
109
+ if (!screenPos) return;
110
+
111
+ if (!this._isSelecting || !this._startPos) return;
112
+
113
+ const lonLat = this.screenToLonLat({ x: screenPos.x, y: screenPos.y });
114
+ if (!lonLat) return;
115
+
116
+ this._updateSelectionRectPreview(lonLat);
117
+
118
+ // 实时框选
119
+ if (this._selectType === SelectType.RECTANGLE) {
120
+ const insideIds = this._getEntitiesInRectangle(this._startPos, lonLat);
121
+ this._highlightEntitiesInSelection(insideIds);
122
+ } else if (this._selectType === SelectType.CIRCLE) {
123
+ const insideIds = this._getEntitiesInCircle(this._startPos, lonLat);
124
+ this._highlightEntitiesInSelection(insideIds);
125
+ }
126
+ }
127
+
128
+ _createSelectionStartMarker(pos) {
129
+ const marker = this.createTempEntity(this.generateId('sel_start'), {
130
+ position: Cesium.Cartesian3.fromDegrees(...pos),
131
+ point: {
132
+ color: Cesium.Color.GREEN,
133
+ pixelSize: 10
134
+ }
135
+ });
136
+ this._tempEntities.push(marker);
137
+ }
138
+
139
+ _updateSelectionRectPreview(currentPos) {
140
+ if (this._selectType === SelectType.RECTANGLE) {
141
+ this._updateRectPreview(currentPos);
142
+ } else if (this._selectType === SelectType.CIRCLE) {
143
+ this._updateCirclePreview(currentPos);
144
+ }
145
+ }
146
+
147
+ _updateRectPreview(currentPos) {
148
+ const corner1 = this._startPos;
149
+ const corner2 = currentPos;
150
+
151
+ if (!corner1 || !corner2) return;
152
+
153
+ if (!this._selectionRect) {
154
+ this._selectionRect = this.createTempEntity(this.generateId('sel_rect'), {
155
+ polyline: {
156
+ positions: new Cesium.CallbackProperty(() => {
157
+ const pos = this._getRectPositions(corner1, corner2);
158
+ return Cesium.Cartesian3.fromDegreesArrayHeights(pos.flatMap(c => [c[0], c[1], 0]));
159
+ }, false),
160
+ material: Cesium.Color.CYAN,
161
+ width: 2
162
+ },
163
+ polygon: {
164
+ hierarchy: new Cesium.CallbackProperty(() => {
165
+ const pos = this._getRectPositions(corner1, corner2);
166
+ return new Cesium.PolygonHierarchy(
167
+ Cesium.Cartesian3.fromDegreesArrayHeights(pos.flatMap(c => [c[0], c[1], 0]))
168
+ );
169
+ }, false),
170
+ material: Cesium.Color.CYAN.withAlpha(0.2),
171
+ outline: false
172
+ }
173
+ });
174
+ this._selectionRect._isPreview = true;
175
+ this._tempEntities.push(this._selectionRect);
176
+ }
177
+ }
178
+
179
+ _updateCirclePreview(currentPos) {
180
+ const center = this._startPos;
181
+
182
+ if (!center || !currentPos) return;
183
+
184
+ if (!this._selectionRect) {
185
+ this._selectionRect = this.createTempEntity(this.generateId('sel_circle'), {
186
+ polygon: {
187
+ hierarchy: new Cesium.CallbackProperty(() => {
188
+ const radius = this._calcDistance(center, currentPos);
189
+ const positions = this._generateCirclePositions(center, radius, 36);
190
+ return new Cesium.PolygonHierarchy(
191
+ Cesium.Cartesian3.fromDegreesArrayHeights(
192
+ positions.flatMap(c => [c[0], c[1], 0])
193
+ )
194
+ );
195
+ }, false),
196
+ material: Cesium.Color.CYAN.withAlpha(0.2),
197
+ outline: true,
198
+ outlineColor: Cesium.Color.CYAN
199
+ }
200
+ });
201
+ this._selectionRect._isPreview = true;
202
+ this._tempEntities.push(this._selectionRect);
203
+ }
204
+ }
205
+
206
+ _getRectPositions(corner1, corner2) {
207
+ return [
208
+ [corner1[0], corner1[1]],
209
+ [corner2[0], corner1[1]],
210
+ [corner2[0], corner2[1]],
211
+ [corner1[0], corner2[1]],
212
+ [corner1[0], corner1[1]]
213
+ ];
214
+ }
215
+
216
+ _clearSelectionRect() {
217
+ this._tempEntities.forEach(entity => {
218
+ if (entity._isPreview) {
219
+ this.removeTempEntity(entity);
220
+ }
221
+ });
222
+ this._tempEntities = this._tempEntities.filter(e => !e._isPreview);
223
+ this._selectionRect = null;
224
+ }
225
+
226
+ _finishSelection(endPos) {
227
+ let selectedIds = [];
228
+
229
+ if (this._selectType === SelectType.RECTANGLE) {
230
+ selectedIds = this._getEntitiesInRectangle(this._startPos, endPos);
231
+ } else if (this._selectType === SelectType.CIRCLE) {
232
+ selectedIds = this._getEntitiesInCircle(this._startPos, endPos);
233
+ }
234
+
235
+ // 框选模式:选中框内所有图元
236
+ selectedIds.forEach(id => {
237
+ this._select(id, false); // 不触发事件
238
+ });
239
+
240
+ this._cancelSelection();
241
+ this._emitSelectionComplete(Array.from(this._selectedIds));
242
+ }
243
+
244
+ _cancelSelection() {
245
+ this._isSelecting = false;
246
+ this._startPos = null;
247
+ this._isSelecting = false;
248
+ this._selectionRect = null;
249
+ this._tempEntities.forEach(entity => {
250
+ this.removeTempEntity(entity);
251
+ });
252
+ this._tempEntities = [];
253
+ }
254
+
255
+ _select(entityId, emitEvent = true) {
256
+ if (this._selectedIds.has(entityId)) return;
257
+
258
+ this._selectedIds.add(entityId);
259
+ this._highlightEntity(entityId, true);
260
+
261
+ if (emitEvent) {
262
+ this._emitSelect(entityId);
263
+ }
264
+ }
265
+
266
+ _deselect(entityId) {
267
+ if (!this._selectedIds.has(entityId)) return;
268
+
269
+ this._selectedIds.delete(entityId);
270
+ this._highlightEntity(entityId, false);
271
+ }
272
+
273
+ _clearAllSelections() {
274
+ this._selectedIds.forEach(id => {
275
+ this._highlightEntity(id, false);
276
+ });
277
+ this._selectedIds.clear();
278
+ this._emitSelectionChange([]);
279
+ }
280
+
281
+ _highlightEntity(entityId, highlight) {
282
+ const entity = this._graphicModule.getGraphic(entityId);
283
+ if (!entity) return;
284
+
285
+ const styleKey = entityId;
286
+
287
+ if (Cesium.defined(entity.point)) {
288
+ if (highlight) {
289
+ if (!this._originalStyles.has(styleKey)) {
290
+ this._originalStyles.set(styleKey, {
291
+ point: {
292
+ outlineColor: entity.point.outlineColor,
293
+ outlineWidth: entity.point.outlineWidth
294
+ }
295
+ });
296
+ }
297
+ entity.point.outlineColor = Cesium.Color.YELLOW;
298
+ entity.point.outlineWidth = 2;
299
+ } else {
300
+ const original = this._originalStyles.get(styleKey)?.point;
301
+ if (original) {
302
+ entity.point.outlineColor = original.outlineColor;
303
+ entity.point.outlineWidth = original.outlineWidth;
304
+ } else {
305
+ entity.point.outlineColor = Cesium.Color.WHITE;
306
+ entity.point.outlineWidth = 1;
307
+ }
308
+ }
309
+ }
310
+
311
+ if (Cesium.defined(entity.polyline)) {
312
+ if (highlight) {
313
+ if (!this._originalStyles.has(styleKey)) {
314
+ this._originalStyles.set(styleKey, {
315
+ polyline: {
316
+ material: entity.polyline.material
317
+ }
318
+ });
319
+ }
320
+ entity.polyline.material = Cesium.Color.CYAN;
321
+ } else {
322
+ const original = this._originalStyles.get(styleKey)?.polyline;
323
+ entity.polyline.material = original?.material || Cesium.Color.BLUE;
324
+ }
325
+ }
326
+
327
+ if (Cesium.defined(entity.polygon)) {
328
+ if (highlight) {
329
+ if (!this._originalStyles.has(styleKey)) {
330
+ this._originalStyles.set(styleKey, {
331
+ polygon: {
332
+ outlineColor: entity.polygon.outlineColor
333
+ }
334
+ });
335
+ }
336
+ entity.polygon.outlineColor = Cesium.Color.CYAN;
337
+ } else {
338
+ const original = this._originalStyles.get(styleKey)?.polygon;
339
+ entity.polygon.outlineColor = original?.outlineColor || Cesium.Color.WHITE;
340
+ }
341
+ }
342
+
343
+ if (!highlight) {
344
+ this._originalStyles.delete(styleKey);
345
+ }
346
+ }
347
+
348
+ _highlightEntitiesInSelection(entityIds) {
349
+ // 先取消所有选择的高亮
350
+ this._selectedIds.forEach(id => {
351
+ if (!entityIds.includes(id)) {
352
+ this._highlightEntity(id, false);
353
+ this._selectedIds.delete(id);
354
+ }
355
+ });
356
+
357
+ // 高亮框内图元
358
+ entityIds.forEach(id => {
359
+ if (!this._selectedIds.has(id)) {
360
+ this._selectedIds.add(id);
361
+ this._highlightEntity(id, true);
362
+ }
363
+ });
364
+ }
365
+
366
+ _getOriginalColor(entity) {
367
+ // 已废弃:原始样式由 _originalStyles 统一维护
368
+ return null;
369
+ }
370
+
371
+ _getEntitiesInRectangle(corner1, corner2) {
372
+ const minLon = Math.min(corner1[0], corner2[0]);
373
+ const maxLon = Math.max(corner1[0], corner2[0]);
374
+ const minLat = Math.min(corner1[1], corner2[1]);
375
+ const maxLat = Math.max(corner1[1], corner2[1]);
376
+
377
+ const allIds = this._getAllGraphicIds();
378
+ return this._filterEntitiesInBounds(allIds, minLon, maxLon, minLat, maxLat);
379
+ }
380
+
381
+ _getEntitiesInCircle(center, edge) {
382
+ const radius = this._calcDistance(center, edge);
383
+ const allIds = this._getAllGraphicIds();
384
+ const result = [];
385
+
386
+ allIds.forEach(id => {
387
+ const entity = this._graphicModule.getGraphic(id);
388
+ if (!entity) return;
389
+
390
+ const entityPos = this._getEntityPosition(entity);
391
+ if (!entityPos) return;
392
+
393
+ const distance = this._calcDistance(center, entityPos);
394
+ if (distance <= radius) {
395
+ result.push(id);
396
+ }
397
+ });
398
+
399
+ return result;
400
+ }
401
+
402
+ _getAllGraphicIds() {
403
+ // 从 GraphicModule 获取所有图元 ID
404
+ const ids = [];
405
+ this._graphicModule.graphicMap.forEach((entity, id) => {
406
+ if (!id.startsWith('__temp_') && !id.startsWith('__edit_handle_')) {
407
+ ids.push(id);
408
+ }
409
+ });
410
+ return ids;
411
+ }
412
+
413
+ _filterEntitiesInBounds(ids, minLon, maxLon, minLat, maxLat) {
414
+ const result = [];
415
+
416
+ ids.forEach(id => {
417
+ const entity = this._graphicModule.getGraphic(id);
418
+ if (!entity) return;
419
+
420
+ const positions = this._getEntityPositions(entity);
421
+ if (!positions || positions.length === 0) return;
422
+
423
+ // 检查是否所有点都在范围内
424
+ let allInBounds = true;
425
+ for (const pos of positions) {
426
+ const c = Cesium.Cartographic.fromCartesian(pos);
427
+ const lon = Cesium.Math.toDegrees(c.longitude);
428
+ const lat = Cesium.Math.toDegrees(c.latitude);
429
+
430
+ if (lon < minLon || lon > maxLon || lat < minLat || lat > maxLat) {
431
+ allInBounds = false;
432
+ break;
433
+ }
434
+ }
435
+
436
+ if (allInBounds) {
437
+ result.push(id);
438
+ }
439
+ });
440
+
441
+ return result;
442
+ }
443
+
444
+ _getEntityPosition(entity) {
445
+ if (Cesium.defined(entity.position)) {
446
+ const pos = entity.position.getValue(Cesium.JulianDate.now());
447
+ if (pos) {
448
+ const c = Cesium.Cartographic.fromCartesian(pos);
449
+ return [
450
+ Cesium.Math.toDegrees(c.longitude),
451
+ Cesium.Math.toDegrees(c.latitude)
452
+ ];
453
+ }
454
+ }
455
+ return null;
456
+ }
457
+
458
+ _getEntityPositions(entity) {
459
+ if (Cesium.defined(entity.polyline) && Cesium.defined(entity.polyline.positions)) {
460
+ return entity.polyline.positions.getValue(Cesium.JulianDate.now());
461
+ }
462
+ if (Cesium.defined(entity.polygon) && Cesium.defined(entity.polygon.hierarchy)) {
463
+ const hierarchy = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now());
464
+ return hierarchy ? hierarchy.positions : [];
465
+ }
466
+ return [];
467
+ }
468
+
469
+ _calcDistance(coord1, coord2) {
470
+ const earthRadius = 6371000;
471
+ const [lon1, lat1] = coord1.map(d => d * Math.PI / 180);
472
+ const [lon2, lat2] = coord2.map(d => d * Math.PI / 180);
473
+
474
+ const dLat = lat2 - lat1;
475
+ const dLon = lon2 - lon1;
476
+
477
+ const a = Math.sin(dLat / 2) ** 2 +
478
+ Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon / 2) ** 2;
479
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
480
+
481
+ return earthRadius * c;
482
+ }
483
+
484
+ _generateCirclePositions(center, radius, segments) {
485
+ const positions = [];
486
+ const [lon, lat] = center;
487
+ const radPerDeg = Math.PI / 180;
488
+
489
+ for (let i = 0; i <= segments; i++) {
490
+ const angle = (i / segments) * Math.PI * 2;
491
+ const dLon = (radius / 111320) * Math.cos(angle) / radPerDeg;
492
+ const dLat = (radius / 110540) / radPerDeg;
493
+ positions.push([lon + dLon, lat + dLat]);
494
+ }
495
+ return positions;
496
+ }
497
+
498
+ _isSelected(entityId) {
499
+ return this._selectedIds.has(entityId);
500
+ }
501
+
502
+ /**
503
+ * 获取当前所有选中的图元 ID
504
+ */
505
+ getSelectedIds() {
506
+ return Array.from(this._selectedIds);
507
+ }
508
+
509
+ _emitSelect(entityId) {
510
+ if (this._options.onSelect) {
511
+ this._options.onSelect({ entityId });
512
+ }
513
+ }
514
+
515
+ _emitSelectionChange(ids) {
516
+ if (this._options.onSelectionChange) {
517
+ this._options.onSelectionChange({ selectedIds: ids });
518
+ }
519
+ }
520
+
521
+ _emitSelectionComplete(ids) {
522
+ if (this._options.onSelectionComplete) {
523
+ this._options.onSelectionComplete({ selectedIds: ids });
524
+ }
525
+ }
526
+ }
package/src/react.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import type { ModuleManager, SceneModule, GraphicModule, EventModule, EditorModule } from './index.js';
2
+
3
+ export interface UseXs3dResult {
4
+ sdk: ModuleManager | null;
5
+ viewer: any;
6
+ sceneModule: SceneModule | null;
7
+ graphicModule: GraphicModule | null;
8
+ eventModule: EventModule | null;
9
+ editorModule: EditorModule | null;
10
+ isReady: boolean;
11
+ }
12
+
13
+ export function useXs3d(
14
+ containerId: string,
15
+ options?: Record<string, any>
16
+ ): UseXs3dResult;
17
+
18
+ export default useXs3d;
package/src/react.js ADDED
@@ -0,0 +1,49 @@
1
+ /**
2
+ * React 适配器
3
+ * 提供 useXs3d Hook,管理 SDK 初始化与销毁生命周期
4
+ */
5
+ import { useEffect, useRef, useState } from 'react';
6
+ import xs3d from './index.js';
7
+
8
+ /**
9
+ * 在 React 组件中使用 XS 3D SDK
10
+ * @param {string} containerId 容器元素 ID
11
+ * @param {Object} options 初始化配置(同 xs3d.init)
12
+ * @returns {Object}
13
+ * - sdk: SDK 根实例
14
+ * - viewer: Cesium Viewer
15
+ * - sceneModule, graphicModule, eventModule, editorModule: 各模块
16
+ * - isReady: 是否初始化完成
17
+ */
18
+ export function useXs3d(containerId, options = {}) {
19
+ const sdkRef = useRef(null);
20
+ const [isReady, setIsReady] = useState(false);
21
+
22
+ useEffect(() => {
23
+ if (!containerId || typeof window === 'undefined') {
24
+ return;
25
+ }
26
+
27
+ const instance = xs3d.init(containerId, options);
28
+ sdkRef.current = instance;
29
+ setIsReady(true);
30
+
31
+ return () => {
32
+ xs3d.destroy();
33
+ sdkRef.current = null;
34
+ setIsReady(false);
35
+ };
36
+ }, [containerId, JSON.stringify(options)]);
37
+
38
+ return {
39
+ sdk: sdkRef.current,
40
+ viewer: sdkRef.current?.viewer ?? null,
41
+ sceneModule: sdkRef.current?.sceneModule ?? null,
42
+ graphicModule: sdkRef.current?.graphicModule ?? null,
43
+ eventModule: sdkRef.current?.eventModule ?? null,
44
+ editorModule: sdkRef.current?.editorModule ?? null,
45
+ isReady
46
+ };
47
+ }
48
+
49
+ export default useXs3d;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * 坐标转换工具(对齐平台 屏幕/世界/地理坐标转换)
3
+ */
4
+ export class CoordinateUtil {
5
+ /**
6
+ * 坐标转换核心方法
7
+ * @param {Cesium.Viewer} viewer Cesium 实例
8
+ * @param {Cesium.Cartesian3|Array<number>} coord 源坐标
9
+ * @param {string} from 源类型(screen/world/scene)
10
+ * @param {string} to 目标类型(screen/world/scene)
11
+ * @returns {Cesium.Cartesian3|Cesium.Cartographic} 转换后坐标
12
+ */
13
+ static transform(viewer, coord, from, to) {
14
+ // 统一坐标格式
15
+ let sourceCoord = coord;
16
+ if (Array.isArray(coord)) {
17
+ if (from === 'scene') {
18
+ // 地理坐标转世界坐标
19
+ sourceCoord = Cesium.Cartesian3.fromDegrees(...coord);
20
+ } else if (from === 'world') {
21
+ sourceCoord = new Cesium.Cartesian3(coord[0], coord[1], coord[2]);
22
+ } else if (from === 'screen') {
23
+ // 屏幕坐标数组需先转为 Cartesian2
24
+ sourceCoord = new Cesium.Cartesian2(coord[0], coord[1]);
25
+ }
26
+ }
27
+
28
+ // 转换逻辑
29
+ switch (`${from}_${to}`) {
30
+ // 屏幕坐标 -> 世界坐标
31
+ case 'screen_world':
32
+ return viewer.camera.pickEllipsoid(sourceCoord);
33
+ // 屏幕坐标 -> 地理坐标
34
+ case 'screen_scene':
35
+ const worldCoord = viewer.camera.pickEllipsoid(sourceCoord);
36
+ const cartographic = Cesium.Cartographic.fromCartesian(worldCoord);
37
+ return [
38
+ Cesium.Math.toDegrees(cartographic.longitude),
39
+ Cesium.Math.toDegrees(cartographic.latitude),
40
+ cartographic.height
41
+ ];
42
+ // 世界坐标 -> 屏幕坐标
43
+ case 'world_screen':
44
+ return Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, sourceCoord);
45
+ // 世界坐标 -> 地理坐标
46
+ case 'world_scene':
47
+ const carto = Cesium.Cartographic.fromCartesian(sourceCoord);
48
+ return [
49
+ Cesium.Math.toDegrees(carto.longitude),
50
+ Cesium.Math.toDegrees(carto.latitude),
51
+ carto.height
52
+ ];
53
+ // 地理坐标 -> 世界坐标(已在入参处理)
54
+ case 'scene_world':
55
+ return sourceCoord;
56
+ // 地理坐标 -> 屏幕坐标
57
+ case 'scene_screen':
58
+ return Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, sourceCoord);
59
+ default:
60
+ return sourceCoord;
61
+ }
62
+ }
63
+ }