@jorgmoritz/gis-manager 0.1.31 → 0.1.33
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.
- package/README.md +76 -76
- package/dist/index.cjs +545 -659
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +120 -173
- package/dist/index.d.ts +120 -173
- package/dist/index.js +545 -659
- package/dist/index.js.map +1 -1
- package/dist/vue/index.cjs +181 -657
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.js +181 -657
- package/dist/vue/index.js.map +1 -1
- package/package.json +1 -1
package/dist/vue/index.js
CHANGED
|
@@ -1284,12 +1284,10 @@ var StateManager = class {
|
|
|
1284
1284
|
__publicField(this, "editing", false);
|
|
1285
1285
|
__publicField(this, "editingTarget");
|
|
1286
1286
|
__publicField(this, "previousView");
|
|
1287
|
-
__publicField(this, "flightPreviewing", false);
|
|
1288
1287
|
// Emitters
|
|
1289
1288
|
__publicField(this, "onSelectionChange", new Emitter());
|
|
1290
1289
|
__publicField(this, "onEditingChange", new Emitter());
|
|
1291
1290
|
__publicField(this, "onPreviousViewChange", new Emitter());
|
|
1292
|
-
__publicField(this, "onFlightPreviewChange", new Emitter());
|
|
1293
1291
|
}
|
|
1294
1292
|
// Selection
|
|
1295
1293
|
setSelected(next) {
|
|
@@ -1336,35 +1334,6 @@ var StateManager = class {
|
|
|
1336
1334
|
getPreviousCameraView() {
|
|
1337
1335
|
return this.previousView;
|
|
1338
1336
|
}
|
|
1339
|
-
// Flight preview mode
|
|
1340
|
-
/**
|
|
1341
|
-
* 开始飞行预览模式(锁定交互)
|
|
1342
|
-
*/
|
|
1343
|
-
startFlightPreview() {
|
|
1344
|
-
if (this.flightPreviewing) return;
|
|
1345
|
-
this.flightPreviewing = true;
|
|
1346
|
-
this.onFlightPreviewChange.emit({ previewing: true });
|
|
1347
|
-
}
|
|
1348
|
-
/**
|
|
1349
|
-
* 停止飞行预览模式(恢复交互)
|
|
1350
|
-
*/
|
|
1351
|
-
stopFlightPreview() {
|
|
1352
|
-
if (!this.flightPreviewing) return;
|
|
1353
|
-
this.flightPreviewing = false;
|
|
1354
|
-
this.onFlightPreviewChange.emit({ previewing: false });
|
|
1355
|
-
}
|
|
1356
|
-
/**
|
|
1357
|
-
* 检查是否处于飞行预览模式
|
|
1358
|
-
*/
|
|
1359
|
-
isFlightPreviewing() {
|
|
1360
|
-
return this.flightPreviewing;
|
|
1361
|
-
}
|
|
1362
|
-
/**
|
|
1363
|
-
* 检查当前是否允许交互(非编辑模式且非飞行预览模式)
|
|
1364
|
-
*/
|
|
1365
|
-
isInteractionAllowed() {
|
|
1366
|
-
return !this.editing && !this.flightPreviewing;
|
|
1367
|
-
}
|
|
1368
1337
|
};
|
|
1369
1338
|
var globalState = new StateManager();
|
|
1370
1339
|
|
|
@@ -2818,6 +2787,10 @@ var AirplaneCursor = class {
|
|
|
2818
2787
|
__publicField(this, "pyramidEntities", []);
|
|
2819
2788
|
// 临时数据源,用于存储金字塔实体(避免污染宿主图层)
|
|
2820
2789
|
__publicField(this, "pyramidLayer");
|
|
2790
|
+
// 缓存的缩放因子,仅在相机变化时更新
|
|
2791
|
+
__publicField(this, "cachedScaleFactor", 1);
|
|
2792
|
+
// 相机变化事件监听器
|
|
2793
|
+
__publicField(this, "cameraChangedListener");
|
|
2821
2794
|
const C = this.CesiumNS;
|
|
2822
2795
|
this.opts = opts;
|
|
2823
2796
|
this.pose = { position: startPosition, heading: 0, pitch: -10, roll: 0 };
|
|
@@ -2837,14 +2810,39 @@ var AirplaneCursor = class {
|
|
|
2837
2810
|
this.viewer.dataSources.add(this.pyramidLayer);
|
|
2838
2811
|
}
|
|
2839
2812
|
const modelHeadingOffset = 270;
|
|
2840
|
-
const
|
|
2841
|
-
const
|
|
2842
|
-
const
|
|
2813
|
+
const baseVerticalOffset = 10;
|
|
2814
|
+
const baseForwardOffset = 5;
|
|
2815
|
+
const baseRightOffset = -9;
|
|
2816
|
+
const baseScale = 0.15;
|
|
2817
|
+
const minScale = 0.025;
|
|
2818
|
+
const maxScale = 1.5;
|
|
2819
|
+
const referenceDistance = 800;
|
|
2820
|
+
const computeScaleFactor = () => {
|
|
2821
|
+
try {
|
|
2822
|
+
const cameraPos = this.viewer.camera.positionWC;
|
|
2823
|
+
const modelPos = this.pose.position;
|
|
2824
|
+
const distance = C.Cartesian3.distance(cameraPos, modelPos);
|
|
2825
|
+
const rawScale = baseScale * (distance / referenceDistance);
|
|
2826
|
+
const clampedScale = Math.max(minScale, Math.min(maxScale, rawScale));
|
|
2827
|
+
return clampedScale / baseScale;
|
|
2828
|
+
} catch {
|
|
2829
|
+
return 1;
|
|
2830
|
+
}
|
|
2831
|
+
};
|
|
2832
|
+
this.cachedScaleFactor = computeScaleFactor();
|
|
2833
|
+
this.cameraChangedListener = this.viewer.camera.changed.addEventListener(() => {
|
|
2834
|
+
this.cachedScaleFactor = computeScaleFactor();
|
|
2835
|
+
this.viewer.scene?.requestRender?.();
|
|
2836
|
+
});
|
|
2843
2837
|
this.modelEntity = this.pyramidLayer.entities.add({
|
|
2844
2838
|
position: new C.CallbackProperty(() => {
|
|
2845
2839
|
const pos = this.pose.position;
|
|
2846
2840
|
const headingRad = C.Math.toRadians(this.pose.heading);
|
|
2847
2841
|
const pitchRad = C.Math.toRadians(this.pose.pitch);
|
|
2842
|
+
const scaleFactor = this.cachedScaleFactor;
|
|
2843
|
+
const modelVerticalOffset = baseVerticalOffset * scaleFactor;
|
|
2844
|
+
const modelForwardOffset = baseForwardOffset * scaleFactor;
|
|
2845
|
+
const modelRightOffset = baseRightOffset * scaleFactor;
|
|
2848
2846
|
const enu = C.Transforms.eastNorthUpToFixedFrame(pos);
|
|
2849
2847
|
const east = C.Cartesian3.fromCartesian4(C.Matrix4.getColumn(enu, 0, new C.Cartesian4()));
|
|
2850
2848
|
const north = C.Cartesian3.fromCartesian4(C.Matrix4.getColumn(enu, 1, new C.Cartesian4()));
|
|
@@ -2885,9 +2883,10 @@ var AirplaneCursor = class {
|
|
|
2885
2883
|
}, false),
|
|
2886
2884
|
model: {
|
|
2887
2885
|
uri: wurenji_default,
|
|
2888
|
-
scale:
|
|
2889
|
-
|
|
2890
|
-
|
|
2886
|
+
scale: new C.CallbackProperty(() => {
|
|
2887
|
+
return baseScale * this.cachedScaleFactor;
|
|
2888
|
+
}, false),
|
|
2889
|
+
minimumPixelSize: 24,
|
|
2891
2890
|
silhouetteColor: C.Color.CYAN,
|
|
2892
2891
|
silhouetteSize: 1
|
|
2893
2892
|
},
|
|
@@ -3021,20 +3020,7 @@ var AirplaneCursor = class {
|
|
|
3021
3020
|
moved = true;
|
|
3022
3021
|
}
|
|
3023
3022
|
if (this.keysPressed.has("z")) {
|
|
3024
|
-
|
|
3025
|
-
const cartographic = C.Cartographic.fromCartesian(newPos);
|
|
3026
|
-
if (cartographic) {
|
|
3027
|
-
const terrainHeight = this.viewer.scene.globe.getHeight(cartographic) ?? 0;
|
|
3028
|
-
const minAltitude = terrainHeight + 1;
|
|
3029
|
-
if (cartographic.height < minAltitude) {
|
|
3030
|
-
cartographic.height = minAltitude;
|
|
3031
|
-
setPos(C.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height));
|
|
3032
|
-
} else {
|
|
3033
|
-
setPos(newPos);
|
|
3034
|
-
}
|
|
3035
|
-
} else {
|
|
3036
|
-
setPos(newPos);
|
|
3037
|
-
}
|
|
3023
|
+
setPos(addVec(pose.position, C.Cartesian3.multiplyByScalar(u3, -step, new C.Cartesian3())));
|
|
3038
3024
|
moved = true;
|
|
3039
3025
|
}
|
|
3040
3026
|
if (this.keysPressed.has("q")) {
|
|
@@ -3262,6 +3248,11 @@ var AirplaneCursor = class {
|
|
|
3262
3248
|
} catch {
|
|
3263
3249
|
}
|
|
3264
3250
|
this.pyramidLayer = void 0;
|
|
3251
|
+
try {
|
|
3252
|
+
this.cameraChangedListener?.();
|
|
3253
|
+
} catch {
|
|
3254
|
+
}
|
|
3255
|
+
this.cameraChangedListener = void 0;
|
|
3265
3256
|
try {
|
|
3266
3257
|
this.frustum?.destroy();
|
|
3267
3258
|
} catch {
|
|
@@ -4580,34 +4571,6 @@ var PathEditingEventHandler = class {
|
|
|
4580
4571
|
* 🆕 处理快速编辑模式的点击
|
|
4581
4572
|
*/
|
|
4582
4573
|
handleQuickEditClick(movement) {
|
|
4583
|
-
const C = this.CesiumNS;
|
|
4584
|
-
try {
|
|
4585
|
-
const picked = this.viewer.scene.pick?.(movement.position);
|
|
4586
|
-
const entity = picked?.id;
|
|
4587
|
-
if (entity?.properties) {
|
|
4588
|
-
const props = entity.properties;
|
|
4589
|
-
const vertexIndex = props._vertexIndex?.getValue?.() ?? props._vertexIndex;
|
|
4590
|
-
const type = props._type?.getValue?.() ?? props._type;
|
|
4591
|
-
if (typeof vertexIndex === "number" && (type === "path-vertex" || type === "vertex-label")) {
|
|
4592
|
-
if (vertexIndex !== this.hiddenClimbIndex && vertexIndex !== 0) {
|
|
4593
|
-
console.log("[QuickEdit] \u70B9\u51FB\u5230\u5DF2\u5B58\u5728\u822A\u70B9\uFF0C\u9009\u4E2D\u800C\u975E\u65B0\u589E:", vertexIndex);
|
|
4594
|
-
if (this.callbacks.onVertexSelect) {
|
|
4595
|
-
this.callbacks.onVertexSelect(vertexIndex);
|
|
4596
|
-
}
|
|
4597
|
-
if (this.callbacks.onVertexSelectDetail) {
|
|
4598
|
-
try {
|
|
4599
|
-
const detailInfo = this.buildVertexDetailInfo(vertexIndex);
|
|
4600
|
-
this.callbacks.onVertexSelectDetail(detailInfo);
|
|
4601
|
-
} catch (error) {
|
|
4602
|
-
console.error("Error building vertex detail info:", error);
|
|
4603
|
-
}
|
|
4604
|
-
}
|
|
4605
|
-
return;
|
|
4606
|
-
}
|
|
4607
|
-
}
|
|
4608
|
-
}
|
|
4609
|
-
} catch (error) {
|
|
4610
|
-
}
|
|
4611
4574
|
const position = this.getPositionFromMouse(movement);
|
|
4612
4575
|
if (!position) {
|
|
4613
4576
|
console.warn("[QuickEdit] \u65E0\u6CD5\u83B7\u53D6\u70B9\u51FB\u4F4D\u7F6E");
|
|
@@ -4616,6 +4579,7 @@ var PathEditingEventHandler = class {
|
|
|
4616
4579
|
const quickEditOptions = this.callbacks.getQuickEditOptions?.();
|
|
4617
4580
|
if (!quickEditOptions) return;
|
|
4618
4581
|
const { climbHeight, altitudeMode } = quickEditOptions;
|
|
4582
|
+
const C = this.CesiumNS;
|
|
4619
4583
|
const originalCarto = C.Cartographic.fromCartesian(position);
|
|
4620
4584
|
const originalHeight = originalCarto.height;
|
|
4621
4585
|
const newPosition = this.applyClimbHeight(position, climbHeight, altitudeMode);
|
|
@@ -5470,10 +5434,6 @@ function startPathEditing(CesiumNS, viewer, entityOrId, options) {
|
|
|
5470
5434
|
);
|
|
5471
5435
|
const cleanupSession = () => {
|
|
5472
5436
|
setActiveIndex(void 0);
|
|
5473
|
-
try {
|
|
5474
|
-
preview?.destroy();
|
|
5475
|
-
} catch {
|
|
5476
|
-
}
|
|
5477
5437
|
try {
|
|
5478
5438
|
handles.forEach((handle) => {
|
|
5479
5439
|
if (handle) {
|
|
@@ -5883,6 +5843,13 @@ var ArrowShape = class {
|
|
|
5883
5843
|
__publicField(this, "baseAlpha");
|
|
5884
5844
|
__publicField(this, "outline");
|
|
5885
5845
|
__publicField(this, "outlineColor");
|
|
5846
|
+
// 动态缩放相关
|
|
5847
|
+
__publicField(this, "dynamicScale");
|
|
5848
|
+
__publicField(this, "viewer");
|
|
5849
|
+
__publicField(this, "referenceDistance");
|
|
5850
|
+
__publicField(this, "minScale");
|
|
5851
|
+
__publicField(this, "maxScale");
|
|
5852
|
+
__publicField(this, "cachedScaleFactor", 1);
|
|
5886
5853
|
const C = this.CesiumNS;
|
|
5887
5854
|
this.shaftHeight = opts.shaftHeight ?? 17;
|
|
5888
5855
|
this.headHeight = opts.headHeight ?? 8;
|
|
@@ -5890,12 +5857,17 @@ var ArrowShape = class {
|
|
|
5890
5857
|
this.shaftRadius = opts.shaftRadius ?? 3;
|
|
5891
5858
|
this.headRadius = opts.headRadius ?? 6;
|
|
5892
5859
|
this.baseRadius = opts.baseRadius ?? 8;
|
|
5893
|
-
this.color = opts.color ? C.Color.fromCssColorString(opts.color) : C.Color.fromCssColorString("#
|
|
5860
|
+
this.color = opts.color ? C.Color.fromCssColorString(opts.color) : C.Color.fromCssColorString("#FFD700");
|
|
5894
5861
|
this.shaftAlpha = opts.shaftAlpha ?? 1;
|
|
5895
5862
|
this.headAlpha = opts.headAlpha ?? 1;
|
|
5896
|
-
this.baseAlpha = opts.baseAlpha ??
|
|
5863
|
+
this.baseAlpha = opts.baseAlpha ?? 0.65;
|
|
5897
5864
|
this.outline = opts.outline ?? false;
|
|
5898
5865
|
this.outlineColor = opts.outlineColor ? C.Color.fromCssColorString(opts.outlineColor) : this.color.darken(0.3, new C.Color());
|
|
5866
|
+
this.dynamicScale = opts.dynamicScale ?? false;
|
|
5867
|
+
this.viewer = opts.viewer;
|
|
5868
|
+
this.referenceDistance = opts.referenceDistance ?? 500;
|
|
5869
|
+
this.minScale = opts.minScale ?? 0.3;
|
|
5870
|
+
this.maxScale = opts.maxScale ?? 3;
|
|
5899
5871
|
}
|
|
5900
5872
|
/**
|
|
5901
5873
|
* Create arrow entities at given position
|
|
@@ -5913,22 +5885,40 @@ var ArrowShape = class {
|
|
|
5913
5885
|
const carto = C.Cartographic.fromCartesian(position);
|
|
5914
5886
|
const lon = C.Math.toDegrees(carto.longitude);
|
|
5915
5887
|
const lat = C.Math.toDegrees(carto.latitude);
|
|
5916
|
-
const
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
5921
|
-
|
|
5888
|
+
const computeScaleFactor = () => {
|
|
5889
|
+
if (!this.dynamicScale || !this.viewer) return 1;
|
|
5890
|
+
try {
|
|
5891
|
+
const cameraPos = this.viewer.camera.positionWC;
|
|
5892
|
+
const distance = C.Cartesian3.distance(cameraPos, position);
|
|
5893
|
+
const rawScale = distance / this.referenceDistance;
|
|
5894
|
+
return Math.max(this.minScale, Math.min(this.maxScale, rawScale));
|
|
5895
|
+
} catch {
|
|
5896
|
+
return 1;
|
|
5897
|
+
}
|
|
5898
|
+
};
|
|
5899
|
+
if (this.dynamicScale && this.viewer) {
|
|
5900
|
+
this.viewer.scene.preRender.addEventListener(() => {
|
|
5901
|
+
this.cachedScaleFactor = computeScaleFactor();
|
|
5902
|
+
});
|
|
5903
|
+
}
|
|
5922
5904
|
const hpr = new C.HeadingPitchRoll(0, 0, 0);
|
|
5923
5905
|
const baseOrientation = C.Transforms.headingPitchRollQuaternion(position, hpr);
|
|
5924
5906
|
const fixedOrientation = new C.ConstantProperty(baseOrientation);
|
|
5907
|
+
const getShaftPosition = () => {
|
|
5908
|
+
const scale = this.cachedScaleFactor;
|
|
5909
|
+
return C.Cartesian3.fromDegrees(lon, lat, baseHeight + this.shaftHeight * scale / 2);
|
|
5910
|
+
};
|
|
5911
|
+
const getHeadPosition = () => {
|
|
5912
|
+
const scale = this.cachedScaleFactor;
|
|
5913
|
+
return C.Cartesian3.fromDegrees(lon, lat, baseHeight + this.shaftHeight * scale + this.headHeight * scale / 2);
|
|
5914
|
+
};
|
|
5925
5915
|
const shaftEntity = layer.entities.add({
|
|
5926
|
-
position: new C.ConstantPositionProperty(
|
|
5916
|
+
position: this.dynamicScale ? new C.CallbackProperty(getShaftPosition, false) : new C.ConstantPositionProperty(C.Cartesian3.fromDegrees(lon, lat, baseHeight + this.shaftHeight / 2)),
|
|
5927
5917
|
orientation: fixedOrientation,
|
|
5928
5918
|
cylinder: {
|
|
5929
|
-
length: this.shaftHeight,
|
|
5930
|
-
topRadius: this.shaftRadius,
|
|
5931
|
-
bottomRadius: this.shaftRadius,
|
|
5919
|
+
length: this.dynamicScale ? new C.CallbackProperty(() => this.shaftHeight * this.cachedScaleFactor, false) : this.shaftHeight,
|
|
5920
|
+
topRadius: this.dynamicScale ? new C.CallbackProperty(() => this.shaftRadius * this.cachedScaleFactor, false) : this.shaftRadius,
|
|
5921
|
+
bottomRadius: this.dynamicScale ? new C.CallbackProperty(() => this.shaftRadius * this.cachedScaleFactor, false) : this.shaftRadius,
|
|
5932
5922
|
material: this.color.withAlpha(this.shaftAlpha),
|
|
5933
5923
|
outline: this.outline,
|
|
5934
5924
|
outlineColor: this.outlineColor,
|
|
@@ -5941,13 +5931,13 @@ var ArrowShape = class {
|
|
|
5941
5931
|
});
|
|
5942
5932
|
entities.push(shaftEntity);
|
|
5943
5933
|
const headEntity = layer.entities.add({
|
|
5944
|
-
position: new C.ConstantPositionProperty(
|
|
5934
|
+
position: this.dynamicScale ? new C.CallbackProperty(getHeadPosition, false) : new C.ConstantPositionProperty(C.Cartesian3.fromDegrees(lon, lat, baseHeight + this.shaftHeight + this.headHeight / 2)),
|
|
5945
5935
|
orientation: fixedOrientation,
|
|
5946
5936
|
cylinder: {
|
|
5947
|
-
length: this.headHeight,
|
|
5937
|
+
length: this.dynamicScale ? new C.CallbackProperty(() => this.headHeight * this.cachedScaleFactor, false) : this.headHeight,
|
|
5948
5938
|
topRadius: 0,
|
|
5949
5939
|
// Creates cone shape
|
|
5950
|
-
bottomRadius: this.headRadius,
|
|
5940
|
+
bottomRadius: this.dynamicScale ? new C.CallbackProperty(() => this.headRadius * this.cachedScaleFactor, false) : this.headRadius,
|
|
5951
5941
|
material: this.color.withAlpha(this.headAlpha),
|
|
5952
5942
|
outline: this.outline,
|
|
5953
5943
|
outlineColor: this.outlineColor,
|
|
@@ -5962,8 +5952,8 @@ var ArrowShape = class {
|
|
|
5962
5952
|
const baseEntity = layer.entities.add({
|
|
5963
5953
|
position,
|
|
5964
5954
|
ellipse: {
|
|
5965
|
-
semiMajorAxis: this.baseRadius,
|
|
5966
|
-
semiMinorAxis: this.baseRadius,
|
|
5955
|
+
semiMajorAxis: this.dynamicScale ? new C.CallbackProperty(() => this.baseRadius * this.cachedScaleFactor, false) : this.baseRadius,
|
|
5956
|
+
semiMinorAxis: this.dynamicScale ? new C.CallbackProperty(() => this.baseRadius * this.cachedScaleFactor, false) : this.baseRadius,
|
|
5967
5957
|
height: baseHeight,
|
|
5968
5958
|
material: this.color.withAlpha(this.baseAlpha),
|
|
5969
5959
|
outline: this.outline,
|
|
@@ -6102,7 +6092,13 @@ function startPathDrawing(CesiumNS, viewer, options, onComplete) {
|
|
|
6102
6092
|
color: "#FFD700",
|
|
6103
6093
|
shaftAlpha: 1,
|
|
6104
6094
|
headAlpha: 1,
|
|
6105
|
-
baseAlpha: 0.5
|
|
6095
|
+
baseAlpha: 0.5,
|
|
6096
|
+
// 启用动态缩放,和无人机模型一样根据相机距离调整大小
|
|
6097
|
+
dynamicScale: true,
|
|
6098
|
+
viewer,
|
|
6099
|
+
referenceDistance: 300,
|
|
6100
|
+
minScale: 0.3,
|
|
6101
|
+
maxScale: 2
|
|
6106
6102
|
});
|
|
6107
6103
|
const arrowEntities = arrowShape.createEntities(
|
|
6108
6104
|
layer,
|
|
@@ -6601,7 +6597,13 @@ function renderFlightPath(CesiumNS, viewer, options) {
|
|
|
6601
6597
|
color: "#FFD700",
|
|
6602
6598
|
shaftAlpha: 0.98,
|
|
6603
6599
|
headAlpha: 0.98,
|
|
6604
|
-
baseAlpha: 0.65
|
|
6600
|
+
baseAlpha: 0.65,
|
|
6601
|
+
// 启用动态缩放
|
|
6602
|
+
dynamicScale: true,
|
|
6603
|
+
viewer,
|
|
6604
|
+
referenceDistance: 300,
|
|
6605
|
+
minScale: 0.3,
|
|
6606
|
+
maxScale: 2
|
|
6605
6607
|
});
|
|
6606
6608
|
arrowShape.createEntities(
|
|
6607
6609
|
layer,
|
|
@@ -6725,515 +6727,6 @@ function renderFlightPathPreview(CesiumNS, viewer, options) {
|
|
|
6725
6727
|
return { entity, controller };
|
|
6726
6728
|
}
|
|
6727
6729
|
|
|
6728
|
-
// src/core/path-manager/FlightPreviewController.ts
|
|
6729
|
-
var FlightPreviewController = class {
|
|
6730
|
-
constructor(CesiumNS, viewer, options) {
|
|
6731
|
-
this.CesiumNS = CesiumNS;
|
|
6732
|
-
this.viewer = viewer;
|
|
6733
|
-
this.options = options;
|
|
6734
|
-
// ========== 状态 ==========
|
|
6735
|
-
__publicField(this, "state", "stopped");
|
|
6736
|
-
__publicField(this, "destroyed", false);
|
|
6737
|
-
// ========== 配置 ==========
|
|
6738
|
-
__publicField(this, "speed");
|
|
6739
|
-
__publicField(this, "loop");
|
|
6740
|
-
__publicField(this, "showFrustum");
|
|
6741
|
-
__publicField(this, "trackHighlightOptions");
|
|
6742
|
-
// ========== 路径数据 ==========
|
|
6743
|
-
__publicField(this, "waypoints", []);
|
|
6744
|
-
__publicField(this, "totalDistance", 0);
|
|
6745
|
-
// ========== 动画状态 ==========
|
|
6746
|
-
__publicField(this, "currentDistance", 0);
|
|
6747
|
-
// 当前已飞行距离
|
|
6748
|
-
__publicField(this, "animationFrameId");
|
|
6749
|
-
__publicField(this, "lastFrameTime");
|
|
6750
|
-
// ========== 可视化组件 ==========
|
|
6751
|
-
__publicField(this, "layer");
|
|
6752
|
-
__publicField(this, "droneEntity");
|
|
6753
|
-
__publicField(this, "frustum");
|
|
6754
|
-
__publicField(this, "pathPreview");
|
|
6755
|
-
// ========== 轨迹高亮 ==========
|
|
6756
|
-
__publicField(this, "traveledPathEntity");
|
|
6757
|
-
__publicField(this, "remainingPathEntity");
|
|
6758
|
-
// ========== 事件 ==========
|
|
6759
|
-
__publicField(this, "onStateChange", new Emitter());
|
|
6760
|
-
__publicField(this, "onProgressChange", new Emitter());
|
|
6761
|
-
this.speed = options.speed ?? 10;
|
|
6762
|
-
this.loop = options.loop ?? true;
|
|
6763
|
-
this.showFrustum = options.showFrustum ?? true;
|
|
6764
|
-
this.trackHighlightOptions = {
|
|
6765
|
-
enabled: true,
|
|
6766
|
-
traveledWidth: 6,
|
|
6767
|
-
remainingWidth: 4,
|
|
6768
|
-
...options.trackHighlight
|
|
6769
|
-
};
|
|
6770
|
-
this.initLayer();
|
|
6771
|
-
this.parseWaylineData();
|
|
6772
|
-
this.initVisualization();
|
|
6773
|
-
console.log("[FlightPreviewController] \u521D\u59CB\u5316\u5B8C\u6210", {
|
|
6774
|
-
waypointCount: this.waypoints.length,
|
|
6775
|
-
totalDistance: this.totalDistance,
|
|
6776
|
-
speed: this.speed
|
|
6777
|
-
});
|
|
6778
|
-
}
|
|
6779
|
-
// ==================== 公共方法 ====================
|
|
6780
|
-
/** 开始预览 */
|
|
6781
|
-
start() {
|
|
6782
|
-
if (this.destroyed) return;
|
|
6783
|
-
if (this.state === "playing") return;
|
|
6784
|
-
if (this.state === "stopped") {
|
|
6785
|
-
this.currentDistance = 0;
|
|
6786
|
-
}
|
|
6787
|
-
this.setState("playing");
|
|
6788
|
-
this.lastFrameTime = performance.now();
|
|
6789
|
-
this.startAnimationLoop();
|
|
6790
|
-
globalState.startFlightPreview();
|
|
6791
|
-
this.pathPreview?.show();
|
|
6792
|
-
console.log("[FlightPreviewController] \u5F00\u59CB\u64AD\u653E");
|
|
6793
|
-
}
|
|
6794
|
-
/** 暂停 */
|
|
6795
|
-
pause() {
|
|
6796
|
-
if (this.destroyed) return;
|
|
6797
|
-
if (this.state !== "playing") return;
|
|
6798
|
-
this.setState("paused");
|
|
6799
|
-
this.stopAnimationLoop();
|
|
6800
|
-
console.log("[FlightPreviewController] \u6682\u505C");
|
|
6801
|
-
}
|
|
6802
|
-
/** 继续 */
|
|
6803
|
-
resume() {
|
|
6804
|
-
if (this.destroyed) return;
|
|
6805
|
-
if (this.state !== "paused") return;
|
|
6806
|
-
this.setState("playing");
|
|
6807
|
-
this.lastFrameTime = performance.now();
|
|
6808
|
-
this.startAnimationLoop();
|
|
6809
|
-
console.log("[FlightPreviewController] \u7EE7\u7EED\u64AD\u653E");
|
|
6810
|
-
}
|
|
6811
|
-
/** 停止并重置 */
|
|
6812
|
-
stop() {
|
|
6813
|
-
if (this.destroyed) return;
|
|
6814
|
-
this.setState("stopped");
|
|
6815
|
-
this.stopAnimationLoop();
|
|
6816
|
-
this.currentDistance = 0;
|
|
6817
|
-
globalState.stopFlightPreview();
|
|
6818
|
-
this.updateVisualization();
|
|
6819
|
-
this.pathPreview?.hide();
|
|
6820
|
-
console.log("[FlightPreviewController] \u505C\u6B62");
|
|
6821
|
-
}
|
|
6822
|
-
/** 跳转到指定进度 (0-1) */
|
|
6823
|
-
seek(progress) {
|
|
6824
|
-
if (this.destroyed) return;
|
|
6825
|
-
const clampedProgress = Math.max(0, Math.min(1, progress));
|
|
6826
|
-
this.currentDistance = clampedProgress * this.totalDistance;
|
|
6827
|
-
this.updateVisualization();
|
|
6828
|
-
console.log("[FlightPreviewController] \u8DF3\u8F6C\u5230", (clampedProgress * 100).toFixed(1) + "%");
|
|
6829
|
-
}
|
|
6830
|
-
/** 设置速度 */
|
|
6831
|
-
setSpeed(speed) {
|
|
6832
|
-
this.speed = Math.max(1, speed);
|
|
6833
|
-
console.log("[FlightPreviewController] \u8BBE\u7F6E\u901F\u5EA6:", this.speed, "m/s");
|
|
6834
|
-
}
|
|
6835
|
-
/** 获取当前状态 */
|
|
6836
|
-
getState() {
|
|
6837
|
-
return this.state;
|
|
6838
|
-
}
|
|
6839
|
-
/** 获取当前进度 (0-1) */
|
|
6840
|
-
getProgress() {
|
|
6841
|
-
if (this.totalDistance === 0) return 0;
|
|
6842
|
-
return this.currentDistance / this.totalDistance;
|
|
6843
|
-
}
|
|
6844
|
-
/** 获取当前航点索引 */
|
|
6845
|
-
getCurrentWaypointIndex() {
|
|
6846
|
-
return this.findCurrentSegment().segmentIndex;
|
|
6847
|
-
}
|
|
6848
|
-
/** 销毁 */
|
|
6849
|
-
destroy() {
|
|
6850
|
-
if (this.destroyed) return;
|
|
6851
|
-
this.destroyed = true;
|
|
6852
|
-
this.stopAnimationLoop();
|
|
6853
|
-
globalState.stopFlightPreview();
|
|
6854
|
-
this.destroyVisualization();
|
|
6855
|
-
this.onStateChange.clear();
|
|
6856
|
-
this.onProgressChange.clear();
|
|
6857
|
-
console.log("[FlightPreviewController] \u5DF2\u9500\u6BC1");
|
|
6858
|
-
}
|
|
6859
|
-
// ==================== 私有方法 - 初始化 ====================
|
|
6860
|
-
/** 初始化图层 */
|
|
6861
|
-
initLayer() {
|
|
6862
|
-
const C = this.CesiumNS;
|
|
6863
|
-
if (this.options.layer) {
|
|
6864
|
-
this.layer = this.options.layer;
|
|
6865
|
-
} else {
|
|
6866
|
-
const newLayer = new C.CustomDataSource("FlightPreviewLayer");
|
|
6867
|
-
this.layer = newLayer;
|
|
6868
|
-
this.viewer.dataSources.add(newLayer);
|
|
6869
|
-
}
|
|
6870
|
-
}
|
|
6871
|
-
/** 解析航线数据 */
|
|
6872
|
-
parseWaylineData() {
|
|
6873
|
-
const C = this.CesiumNS;
|
|
6874
|
-
const { waylineData } = this.options;
|
|
6875
|
-
const converted = convertSinoflyWayline(waylineData, { CesiumNS: this.CesiumNS });
|
|
6876
|
-
const waypointData = converted.waypointData;
|
|
6877
|
-
if (!waypointData || waypointData.length < 2) {
|
|
6878
|
-
console.warn("[FlightPreviewController] \u822A\u70B9\u6570\u91CF\u4E0D\u8DB3");
|
|
6879
|
-
return;
|
|
6880
|
-
}
|
|
6881
|
-
let cumulativeDistance = 0;
|
|
6882
|
-
for (let i = 0; i < waypointData.length; i++) {
|
|
6883
|
-
const wp = waypointData[i];
|
|
6884
|
-
let distanceToNext = 0;
|
|
6885
|
-
if (i < waypointData.length - 1) {
|
|
6886
|
-
const nextWp = waypointData[i + 1];
|
|
6887
|
-
distanceToNext = C.Cartesian3.distance(wp.position, nextWp.position);
|
|
6888
|
-
}
|
|
6889
|
-
this.waypoints.push({
|
|
6890
|
-
position: wp.position,
|
|
6891
|
-
heading: wp.heading ?? 0,
|
|
6892
|
-
pitch: wp.pitch ?? -10,
|
|
6893
|
-
roll: wp.roll ?? 0,
|
|
6894
|
-
distanceToNext,
|
|
6895
|
-
cumulativeDistance
|
|
6896
|
-
});
|
|
6897
|
-
cumulativeDistance += distanceToNext;
|
|
6898
|
-
}
|
|
6899
|
-
this.totalDistance = cumulativeDistance;
|
|
6900
|
-
}
|
|
6901
|
-
/** 初始化可视化组件 */
|
|
6902
|
-
initVisualization() {
|
|
6903
|
-
this.initDroneModel();
|
|
6904
|
-
this.initFrustum();
|
|
6905
|
-
this.initTrackHighlight();
|
|
6906
|
-
this.initPathPreview();
|
|
6907
|
-
this.updateVisualization();
|
|
6908
|
-
}
|
|
6909
|
-
/** 初始化无人机模型 */
|
|
6910
|
-
initDroneModel() {
|
|
6911
|
-
if (!this.layer || this.waypoints.length === 0) return;
|
|
6912
|
-
const C = this.CesiumNS;
|
|
6913
|
-
const layer = this.layer;
|
|
6914
|
-
const modelHeadingOffset = 270;
|
|
6915
|
-
const modelVerticalOffset = 35;
|
|
6916
|
-
const modelForwardOffset = 5;
|
|
6917
|
-
const modelRightOffset = -30;
|
|
6918
|
-
this.droneEntity = layer.entities.add({
|
|
6919
|
-
position: new C.CallbackProperty(() => {
|
|
6920
|
-
const { position, heading, pitch } = this.getCurrentPose();
|
|
6921
|
-
return this.applyModelOffset(position, heading, pitch, {
|
|
6922
|
-
forward: modelForwardOffset,
|
|
6923
|
-
right: modelRightOffset,
|
|
6924
|
-
up: modelVerticalOffset
|
|
6925
|
-
});
|
|
6926
|
-
}, false),
|
|
6927
|
-
orientation: new C.CallbackProperty(() => {
|
|
6928
|
-
const { position, heading, pitch, roll } = this.getCurrentPose();
|
|
6929
|
-
const hpr = new C.HeadingPitchRoll(
|
|
6930
|
-
C.Math.toRadians(heading + modelHeadingOffset),
|
|
6931
|
-
C.Math.toRadians(pitch),
|
|
6932
|
-
C.Math.toRadians(roll)
|
|
6933
|
-
);
|
|
6934
|
-
return C.Transforms.headingPitchRollQuaternion(position, hpr);
|
|
6935
|
-
}, false),
|
|
6936
|
-
model: {
|
|
6937
|
-
uri: wurenji_default,
|
|
6938
|
-
scale: 0.5,
|
|
6939
|
-
minimumPixelSize: 32,
|
|
6940
|
-
maximumScale: 100,
|
|
6941
|
-
silhouetteColor: C.Color.CYAN,
|
|
6942
|
-
silhouetteSize: 1
|
|
6943
|
-
},
|
|
6944
|
-
properties: { _type: "flight-preview-drone" }
|
|
6945
|
-
});
|
|
6946
|
-
}
|
|
6947
|
-
/** 应用模型偏移 */
|
|
6948
|
-
applyModelOffset(position, heading, pitch, offset) {
|
|
6949
|
-
const C = this.CesiumNS;
|
|
6950
|
-
const headingRad = C.Math.toRadians(heading);
|
|
6951
|
-
const pitchRad = C.Math.toRadians(pitch);
|
|
6952
|
-
const enu = C.Transforms.eastNorthUpToFixedFrame(position);
|
|
6953
|
-
const east = C.Cartesian3.fromCartesian4(C.Matrix4.getColumn(enu, 0, new C.Cartesian4()));
|
|
6954
|
-
const north = C.Cartesian3.fromCartesian4(C.Matrix4.getColumn(enu, 1, new C.Cartesian4()));
|
|
6955
|
-
const up = C.Cartesian3.fromCartesian4(C.Matrix4.getColumn(enu, 2, new C.Cartesian4()));
|
|
6956
|
-
const horizForward = C.Cartesian3.add(
|
|
6957
|
-
C.Cartesian3.multiplyByScalar(east, Math.sin(headingRad), new C.Cartesian3()),
|
|
6958
|
-
C.Cartesian3.multiplyByScalar(north, Math.cos(headingRad), new C.Cartesian3()),
|
|
6959
|
-
new C.Cartesian3()
|
|
6960
|
-
);
|
|
6961
|
-
const right = C.Cartesian3.add(
|
|
6962
|
-
C.Cartesian3.multiplyByScalar(east, Math.cos(headingRad), new C.Cartesian3()),
|
|
6963
|
-
C.Cartesian3.multiplyByScalar(north, -Math.sin(headingRad), new C.Cartesian3()),
|
|
6964
|
-
new C.Cartesian3()
|
|
6965
|
-
);
|
|
6966
|
-
const forward = C.Cartesian3.add(
|
|
6967
|
-
C.Cartesian3.multiplyByScalar(horizForward, Math.cos(pitchRad), new C.Cartesian3()),
|
|
6968
|
-
C.Cartesian3.multiplyByScalar(up, Math.sin(pitchRad), new C.Cartesian3()),
|
|
6969
|
-
new C.Cartesian3()
|
|
6970
|
-
);
|
|
6971
|
-
const upRotated = C.Cartesian3.add(
|
|
6972
|
-
C.Cartesian3.multiplyByScalar(horizForward, -Math.sin(pitchRad), new C.Cartesian3()),
|
|
6973
|
-
C.Cartesian3.multiplyByScalar(up, Math.cos(pitchRad), new C.Cartesian3()),
|
|
6974
|
-
new C.Cartesian3()
|
|
6975
|
-
);
|
|
6976
|
-
let result = C.Cartesian3.clone(position);
|
|
6977
|
-
result = C.Cartesian3.add(result, C.Cartesian3.multiplyByScalar(forward, offset.forward, new C.Cartesian3()), result);
|
|
6978
|
-
result = C.Cartesian3.add(result, C.Cartesian3.multiplyByScalar(right, offset.right, new C.Cartesian3()), result);
|
|
6979
|
-
result = C.Cartesian3.add(result, C.Cartesian3.multiplyByScalar(upRotated, offset.up, new C.Cartesian3()), result);
|
|
6980
|
-
return result;
|
|
6981
|
-
}
|
|
6982
|
-
/** 初始化视锥体 */
|
|
6983
|
-
initFrustum() {
|
|
6984
|
-
if (!this.showFrustum || !this.layer) return;
|
|
6985
|
-
const C = this.CesiumNS;
|
|
6986
|
-
this.frustum = new FrustumPyramid(this.CesiumNS, this.layer, {
|
|
6987
|
-
fov: 50,
|
|
6988
|
-
length: 500,
|
|
6989
|
-
color: C.Color.CYAN,
|
|
6990
|
-
fillAlpha: 0.25,
|
|
6991
|
-
width: 2
|
|
6992
|
-
});
|
|
6993
|
-
this.frustum.showAtDynamic(
|
|
6994
|
-
() => this.getCurrentPose().position,
|
|
6995
|
-
() => this.getCurrentPose().heading,
|
|
6996
|
-
() => this.getCurrentPose().pitch,
|
|
6997
|
-
() => this.getCurrentPose().roll,
|
|
6998
|
-
() => 50,
|
|
6999
|
-
() => 500
|
|
7000
|
-
);
|
|
7001
|
-
}
|
|
7002
|
-
/** 初始化轨迹高亮 */
|
|
7003
|
-
initTrackHighlight() {
|
|
7004
|
-
if (!this.trackHighlightOptions.enabled || !this.layer) return;
|
|
7005
|
-
if (this.waypoints.length < 2) return;
|
|
7006
|
-
const C = this.CesiumNS;
|
|
7007
|
-
const layer = this.layer;
|
|
7008
|
-
const traveledColor = this.trackHighlightOptions.traveledColor ?? C.Color.fromCssColorString("#00FF88");
|
|
7009
|
-
const remainingColor = this.trackHighlightOptions.remainingColor ?? C.Color.fromCssColorString("#4A90D9").withAlpha(0.7);
|
|
7010
|
-
this.traveledPathEntity = layer.entities.add({
|
|
7011
|
-
polyline: {
|
|
7012
|
-
positions: new C.CallbackProperty(() => this.getTraveledPositions(), false),
|
|
7013
|
-
width: this.trackHighlightOptions.traveledWidth ?? 6,
|
|
7014
|
-
material: traveledColor,
|
|
7015
|
-
clampToGround: false
|
|
7016
|
-
},
|
|
7017
|
-
properties: { _type: "flight-preview-traveled" }
|
|
7018
|
-
});
|
|
7019
|
-
this.remainingPathEntity = layer.entities.add({
|
|
7020
|
-
polyline: {
|
|
7021
|
-
positions: new C.CallbackProperty(() => this.getRemainingPositions(), false),
|
|
7022
|
-
width: this.trackHighlightOptions.remainingWidth ?? 4,
|
|
7023
|
-
material: remainingColor,
|
|
7024
|
-
clampToGround: false
|
|
7025
|
-
},
|
|
7026
|
-
properties: { _type: "flight-preview-remaining" }
|
|
7027
|
-
});
|
|
7028
|
-
}
|
|
7029
|
-
/** 初始化预览窗口 */
|
|
7030
|
-
initPathPreview() {
|
|
7031
|
-
this.pathPreview = new PathPreview(
|
|
7032
|
-
this.CesiumNS,
|
|
7033
|
-
this.viewer,
|
|
7034
|
-
{
|
|
7035
|
-
container: this.options.previewContainer,
|
|
7036
|
-
fov: 50,
|
|
7037
|
-
pitch: -10,
|
|
7038
|
-
useGlobalEventBus: true
|
|
7039
|
-
}
|
|
7040
|
-
);
|
|
7041
|
-
this.pathPreview.hide();
|
|
7042
|
-
}
|
|
7043
|
-
// ==================== 私有方法 - 动画循环 ====================
|
|
7044
|
-
/** 启动动画循环 */
|
|
7045
|
-
startAnimationLoop() {
|
|
7046
|
-
if (this.animationFrameId) return;
|
|
7047
|
-
const animate = (currentTime) => {
|
|
7048
|
-
if (this.state !== "playing" || this.destroyed) {
|
|
7049
|
-
this.animationFrameId = void 0;
|
|
7050
|
-
return;
|
|
7051
|
-
}
|
|
7052
|
-
const deltaTime = this.lastFrameTime ? (currentTime - this.lastFrameTime) / 1e3 : 0;
|
|
7053
|
-
this.lastFrameTime = currentTime;
|
|
7054
|
-
this.currentDistance += this.speed * deltaTime;
|
|
7055
|
-
if (this.currentDistance >= this.totalDistance) {
|
|
7056
|
-
if (this.loop) {
|
|
7057
|
-
this.currentDistance = this.currentDistance % this.totalDistance;
|
|
7058
|
-
} else {
|
|
7059
|
-
this.currentDistance = this.totalDistance;
|
|
7060
|
-
this.setState("stopped");
|
|
7061
|
-
this.stopAnimationLoop();
|
|
7062
|
-
return;
|
|
7063
|
-
}
|
|
7064
|
-
}
|
|
7065
|
-
this.updateVisualization();
|
|
7066
|
-
this.animationFrameId = requestAnimationFrame(animate);
|
|
7067
|
-
};
|
|
7068
|
-
this.animationFrameId = requestAnimationFrame(animate);
|
|
7069
|
-
}
|
|
7070
|
-
/** 停止动画循环 */
|
|
7071
|
-
stopAnimationLoop() {
|
|
7072
|
-
if (this.animationFrameId) {
|
|
7073
|
-
cancelAnimationFrame(this.animationFrameId);
|
|
7074
|
-
this.animationFrameId = void 0;
|
|
7075
|
-
}
|
|
7076
|
-
this.lastFrameTime = void 0;
|
|
7077
|
-
}
|
|
7078
|
-
// ==================== 私有方法 - 路径插值 ====================
|
|
7079
|
-
/** 查找当前所在航段 */
|
|
7080
|
-
findCurrentSegment() {
|
|
7081
|
-
if (this.waypoints.length === 0) {
|
|
7082
|
-
return { segmentIndex: 0, progressInSegment: 0 };
|
|
7083
|
-
}
|
|
7084
|
-
for (let i = 0; i < this.waypoints.length - 1; i++) {
|
|
7085
|
-
const wp = this.waypoints[i];
|
|
7086
|
-
const nextWp = this.waypoints[i + 1];
|
|
7087
|
-
if (this.currentDistance <= nextWp.cumulativeDistance) {
|
|
7088
|
-
const segmentStart = wp.cumulativeDistance;
|
|
7089
|
-
const segmentLength = wp.distanceToNext;
|
|
7090
|
-
const distanceInSegment = this.currentDistance - segmentStart;
|
|
7091
|
-
const progressInSegment = segmentLength > 0 ? distanceInSegment / segmentLength : 0;
|
|
7092
|
-
return { segmentIndex: i, progressInSegment };
|
|
7093
|
-
}
|
|
7094
|
-
}
|
|
7095
|
-
return { segmentIndex: this.waypoints.length - 2, progressInSegment: 1 };
|
|
7096
|
-
}
|
|
7097
|
-
/** 获取当前姿态 */
|
|
7098
|
-
getCurrentPose() {
|
|
7099
|
-
if (this.waypoints.length === 0) {
|
|
7100
|
-
const C = this.CesiumNS;
|
|
7101
|
-
return {
|
|
7102
|
-
position: new C.Cartesian3(),
|
|
7103
|
-
heading: 0,
|
|
7104
|
-
pitch: -10,
|
|
7105
|
-
roll: 0
|
|
7106
|
-
};
|
|
7107
|
-
}
|
|
7108
|
-
const { segmentIndex, progressInSegment } = this.findCurrentSegment();
|
|
7109
|
-
const wp = this.waypoints[segmentIndex];
|
|
7110
|
-
const nextWp = this.waypoints[Math.min(segmentIndex + 1, this.waypoints.length - 1)];
|
|
7111
|
-
const position = this.interpolatePosition(wp.position, nextWp.position, progressInSegment);
|
|
7112
|
-
const heading = this.interpolateAngle(wp.heading, nextWp.heading, progressInSegment);
|
|
7113
|
-
const pitch = this.lerp(wp.pitch, nextWp.pitch, progressInSegment);
|
|
7114
|
-
const roll = this.lerp(wp.roll, nextWp.roll, progressInSegment);
|
|
7115
|
-
return { position, heading, pitch, roll };
|
|
7116
|
-
}
|
|
7117
|
-
/** 位置插值 */
|
|
7118
|
-
interpolatePosition(start, end, t) {
|
|
7119
|
-
const C = this.CesiumNS;
|
|
7120
|
-
return C.Cartesian3.lerp(start, end, t, new C.Cartesian3());
|
|
7121
|
-
}
|
|
7122
|
-
/** 角度插值(处理 0-360 环绕) */
|
|
7123
|
-
interpolateAngle(start, end, t) {
|
|
7124
|
-
let diff = end - start;
|
|
7125
|
-
if (diff > 180) diff -= 360;
|
|
7126
|
-
if (diff < -180) diff += 360;
|
|
7127
|
-
let result = start + diff * t;
|
|
7128
|
-
return (result % 360 + 360) % 360;
|
|
7129
|
-
}
|
|
7130
|
-
/** 线性插值 */
|
|
7131
|
-
lerp(start, end, t) {
|
|
7132
|
-
return start + (end - start) * t;
|
|
7133
|
-
}
|
|
7134
|
-
// ==================== 私有方法 - 轨迹高亮 ====================
|
|
7135
|
-
/** 获取已飞过的位置数组 */
|
|
7136
|
-
getTraveledPositions() {
|
|
7137
|
-
if (this.waypoints.length === 0) return [];
|
|
7138
|
-
const { segmentIndex, progressInSegment } = this.findCurrentSegment();
|
|
7139
|
-
const currentPos = this.getCurrentPose().position;
|
|
7140
|
-
const positions = [];
|
|
7141
|
-
for (let i = 0; i <= segmentIndex; i++) {
|
|
7142
|
-
positions.push(this.waypoints[i].position);
|
|
7143
|
-
}
|
|
7144
|
-
if (progressInSegment > 0) {
|
|
7145
|
-
positions.push(currentPos);
|
|
7146
|
-
}
|
|
7147
|
-
return positions;
|
|
7148
|
-
}
|
|
7149
|
-
/** 获取未飞过的位置数组 */
|
|
7150
|
-
getRemainingPositions() {
|
|
7151
|
-
if (this.waypoints.length === 0) return [];
|
|
7152
|
-
const { segmentIndex } = this.findCurrentSegment();
|
|
7153
|
-
const currentPos = this.getCurrentPose().position;
|
|
7154
|
-
const positions = [];
|
|
7155
|
-
positions.push(currentPos);
|
|
7156
|
-
for (let i = segmentIndex + 1; i < this.waypoints.length; i++) {
|
|
7157
|
-
positions.push(this.waypoints[i].position);
|
|
7158
|
-
}
|
|
7159
|
-
return positions;
|
|
7160
|
-
}
|
|
7161
|
-
// ==================== 私有方法 - 更新 ====================
|
|
7162
|
-
/** 更新可视化 */
|
|
7163
|
-
updateVisualization() {
|
|
7164
|
-
const pose = this.getCurrentPose();
|
|
7165
|
-
if (this.pathPreview) {
|
|
7166
|
-
this.pathPreview.setPose(
|
|
7167
|
-
pose.position,
|
|
7168
|
-
pose.heading,
|
|
7169
|
-
pose.pitch,
|
|
7170
|
-
pose.roll
|
|
7171
|
-
);
|
|
7172
|
-
}
|
|
7173
|
-
this.viewer.scene?.requestRender?.();
|
|
7174
|
-
const { segmentIndex } = this.findCurrentSegment();
|
|
7175
|
-
this.onProgressChange.emit({
|
|
7176
|
-
progress: this.getProgress(),
|
|
7177
|
-
position: pose.position,
|
|
7178
|
-
waypointIndex: segmentIndex,
|
|
7179
|
-
pose: {
|
|
7180
|
-
heading: pose.heading,
|
|
7181
|
-
pitch: pose.pitch,
|
|
7182
|
-
roll: pose.roll
|
|
7183
|
-
}
|
|
7184
|
-
});
|
|
7185
|
-
}
|
|
7186
|
-
/** 设置状态 */
|
|
7187
|
-
setState(newState) {
|
|
7188
|
-
if (this.state !== newState) {
|
|
7189
|
-
this.state = newState;
|
|
7190
|
-
this.onStateChange.emit({ state: newState });
|
|
7191
|
-
}
|
|
7192
|
-
}
|
|
7193
|
-
/** 销毁可视化组件 */
|
|
7194
|
-
destroyVisualization() {
|
|
7195
|
-
const layer = this.layer;
|
|
7196
|
-
if (this.droneEntity && layer) {
|
|
7197
|
-
try {
|
|
7198
|
-
layer.entities.remove(this.droneEntity);
|
|
7199
|
-
} catch {
|
|
7200
|
-
}
|
|
7201
|
-
}
|
|
7202
|
-
if (this.traveledPathEntity && layer) {
|
|
7203
|
-
try {
|
|
7204
|
-
layer.entities.remove(this.traveledPathEntity);
|
|
7205
|
-
} catch {
|
|
7206
|
-
}
|
|
7207
|
-
}
|
|
7208
|
-
if (this.remainingPathEntity && layer) {
|
|
7209
|
-
try {
|
|
7210
|
-
layer.entities.remove(this.remainingPathEntity);
|
|
7211
|
-
} catch {
|
|
7212
|
-
}
|
|
7213
|
-
}
|
|
7214
|
-
try {
|
|
7215
|
-
this.frustum?.destroy();
|
|
7216
|
-
} catch {
|
|
7217
|
-
}
|
|
7218
|
-
try {
|
|
7219
|
-
this.pathPreview?.destroy();
|
|
7220
|
-
} catch {
|
|
7221
|
-
}
|
|
7222
|
-
if (!this.options.layer && this.layer) {
|
|
7223
|
-
try {
|
|
7224
|
-
this.viewer.dataSources.remove(this.layer);
|
|
7225
|
-
} catch {
|
|
7226
|
-
}
|
|
7227
|
-
}
|
|
7228
|
-
this.droneEntity = void 0;
|
|
7229
|
-
this.traveledPathEntity = void 0;
|
|
7230
|
-
this.remainingPathEntity = void 0;
|
|
7231
|
-
this.frustum = void 0;
|
|
7232
|
-
this.pathPreview = void 0;
|
|
7233
|
-
this.layer = void 0;
|
|
7234
|
-
}
|
|
7235
|
-
};
|
|
7236
|
-
|
|
7237
6730
|
// src/core/CZMLPathManager.ts
|
|
7238
6731
|
var _CZMLPathManager = class _CZMLPathManager {
|
|
7239
6732
|
constructor(CesiumNS, viewer) {
|
|
@@ -7347,50 +6840,6 @@ var _CZMLPathManager = class _CZMLPathManager {
|
|
|
7347
6840
|
renderFlightPathPreview(options) {
|
|
7348
6841
|
return renderFlightPathPreview(this.CesiumNS, this.viewer, options);
|
|
7349
6842
|
}
|
|
7350
|
-
/**
|
|
7351
|
-
* 开始飞行预览:飞机沿航线飞行动画
|
|
7352
|
-
*
|
|
7353
|
-
* 功能:
|
|
7354
|
-
* - 飞机游标沿航线从起点飞到终点,循环播放
|
|
7355
|
-
* - 预览窗口实时显示飞机第一人称视角
|
|
7356
|
-
* - 轨迹高亮显示已飞过/未飞过的航段
|
|
7357
|
-
* - 预览模式下禁止选择/编辑航线、航点
|
|
7358
|
-
*
|
|
7359
|
-
* @param options 飞行预览选项
|
|
7360
|
-
* @returns 飞行预览控制器
|
|
7361
|
-
*
|
|
7362
|
-
* @example
|
|
7363
|
-
* ```typescript
|
|
7364
|
-
* const preview = pathManager.startFlightPreview({
|
|
7365
|
-
* waylineData: myWayline,
|
|
7366
|
-
* speed: 15, // 飞行速度 15m/s
|
|
7367
|
-
* loop: true, // 循环播放
|
|
7368
|
-
* trackHighlight: {
|
|
7369
|
-
* enabled: true,
|
|
7370
|
-
* traveledColor: Cesium.Color.fromCssColorString('#00FF88'),
|
|
7371
|
-
* remainingColor: Cesium.Color.fromCssColorString('#4A90D9'),
|
|
7372
|
-
* },
|
|
7373
|
-
* });
|
|
7374
|
-
*
|
|
7375
|
-
* preview.start(); // 开始播放
|
|
7376
|
-
* preview.pause(); // 暂停
|
|
7377
|
-
* preview.resume(); // 继续
|
|
7378
|
-
* preview.stop(); // 停止
|
|
7379
|
-
* preview.seek(0.5); // 跳转到 50%
|
|
7380
|
-
* preview.setSpeed(20); // 设置速度
|
|
7381
|
-
*
|
|
7382
|
-
* // 监听进度变化
|
|
7383
|
-
* preview.onProgressChange.on(({ progress, waypointIndex }) => {
|
|
7384
|
-
* console.log(`进度: ${(progress * 100).toFixed(1)}%`);
|
|
7385
|
-
* });
|
|
7386
|
-
*
|
|
7387
|
-
* // 销毁
|
|
7388
|
-
* preview.destroy();
|
|
7389
|
-
* ```
|
|
7390
|
-
*/
|
|
7391
|
-
startFlightPreview(options) {
|
|
7392
|
-
return new FlightPreviewController(this.CesiumNS, this.viewer, options);
|
|
7393
|
-
}
|
|
7394
6843
|
resolveEntity(entityOrId) {
|
|
7395
6844
|
return typeof entityOrId === "string" ? this.viewer.entities.getById(entityOrId) : entityOrId;
|
|
7396
6845
|
}
|
|
@@ -7586,6 +7035,8 @@ var PolygonEditor = class {
|
|
|
7586
7035
|
__publicField(this, "keydownHandler");
|
|
7587
7036
|
// 保存编码前的原始名称,用于还原
|
|
7588
7037
|
__publicField(this, "originalPolygonNames", /* @__PURE__ */ new Map());
|
|
7038
|
+
// 保存双击缩放是否被禁用的状态
|
|
7039
|
+
__publicField(this, "doubleClickZoomDisabled", false);
|
|
7589
7040
|
}
|
|
7590
7041
|
/**
|
|
7591
7042
|
* 根据图层名称获取颜色配置
|
|
@@ -7860,12 +7311,62 @@ var PolygonEditor = class {
|
|
|
7860
7311
|
}
|
|
7861
7312
|
this.handler = void 0;
|
|
7862
7313
|
}
|
|
7314
|
+
/**
|
|
7315
|
+
* 禁用 Cesium 默认的双击缩放行为
|
|
7316
|
+
* 在绘制/编辑过程中调用,防止双击导致相机乱飞
|
|
7317
|
+
*/
|
|
7318
|
+
disableDoubleClickZoom() {
|
|
7319
|
+
if (this.doubleClickZoomDisabled) return;
|
|
7320
|
+
try {
|
|
7321
|
+
const C = this.CesiumNS;
|
|
7322
|
+
const cesiumWidget = this.viewer.cesiumWidget;
|
|
7323
|
+
if (cesiumWidget?.screenSpaceEventHandler) {
|
|
7324
|
+
cesiumWidget.screenSpaceEventHandler.removeInputAction(
|
|
7325
|
+
C.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
|
|
7326
|
+
);
|
|
7327
|
+
this.doubleClickZoomDisabled = true;
|
|
7328
|
+
}
|
|
7329
|
+
} catch (e) {
|
|
7330
|
+
console.warn("[PolygonEditor] \u7981\u7528\u53CC\u51FB\u7F29\u653E\u5931\u8D25:", e);
|
|
7331
|
+
}
|
|
7332
|
+
}
|
|
7333
|
+
/**
|
|
7334
|
+
* 恢复 Cesium 默认的双击缩放行为
|
|
7335
|
+
* 在绘制/编辑结束后调用
|
|
7336
|
+
*/
|
|
7337
|
+
restoreDoubleClickZoom() {
|
|
7338
|
+
if (!this.doubleClickZoomDisabled) return;
|
|
7339
|
+
try {
|
|
7340
|
+
const C = this.CesiumNS;
|
|
7341
|
+
const viewer = this.viewer;
|
|
7342
|
+
const cesiumWidget = viewer.cesiumWidget;
|
|
7343
|
+
if (cesiumWidget?.screenSpaceEventHandler) {
|
|
7344
|
+
cesiumWidget.screenSpaceEventHandler.setInputAction(
|
|
7345
|
+
(movement) => {
|
|
7346
|
+
try {
|
|
7347
|
+
const pickedObject = viewer.scene.pick(movement.position);
|
|
7348
|
+
if (pickedObject?.id && viewer.trackedEntity !== pickedObject.id) {
|
|
7349
|
+
viewer.flyTo(pickedObject.id, { duration: 1.5 });
|
|
7350
|
+
}
|
|
7351
|
+
} catch {
|
|
7352
|
+
}
|
|
7353
|
+
},
|
|
7354
|
+
C.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
|
|
7355
|
+
);
|
|
7356
|
+
this.doubleClickZoomDisabled = false;
|
|
7357
|
+
}
|
|
7358
|
+
} catch (e) {
|
|
7359
|
+
console.warn("[PolygonEditor] \u6062\u590D\u53CC\u51FB\u7F29\u653E\u5931\u8D25:", e);
|
|
7360
|
+
this.doubleClickZoomDisabled = false;
|
|
7361
|
+
}
|
|
7362
|
+
}
|
|
7863
7363
|
/**
|
|
7864
7364
|
* 完成编辑/绘制的通用清理逻辑
|
|
7865
7365
|
*/
|
|
7866
7366
|
finalizePolygonSession(layer, onComplete, entity) {
|
|
7867
7367
|
this.destroyHandler();
|
|
7868
7368
|
this.removeKeyboardListener();
|
|
7369
|
+
this.restoreDoubleClickZoom();
|
|
7869
7370
|
if (entity && onComplete) {
|
|
7870
7371
|
onComplete(entity);
|
|
7871
7372
|
}
|
|
@@ -7908,6 +7409,7 @@ var PolygonEditor = class {
|
|
|
7908
7409
|
}
|
|
7909
7410
|
this.clearAllPolygonHighlights();
|
|
7910
7411
|
this.stopInternal(layer);
|
|
7412
|
+
this.disableDoubleClickZoom();
|
|
7911
7413
|
this.drawingPositions = [];
|
|
7912
7414
|
this.drawHandles = [];
|
|
7913
7415
|
this.rubberBandPoint = void 0;
|
|
@@ -8052,6 +7554,7 @@ var PolygonEditor = class {
|
|
|
8052
7554
|
}
|
|
8053
7555
|
this.destroyHandler();
|
|
8054
7556
|
this.removeKeyboardListener();
|
|
7557
|
+
this.restoreDoubleClickZoom();
|
|
8055
7558
|
}
|
|
8056
7559
|
/**
|
|
8057
7560
|
* 开始编辑多边形
|
|
@@ -8063,6 +7566,7 @@ var PolygonEditor = class {
|
|
|
8063
7566
|
startEditing(polygonEntity, layer, onComplete) {
|
|
8064
7567
|
const C = this.CesiumNS;
|
|
8065
7568
|
this.cleanupHandles(layer);
|
|
7569
|
+
this.disableDoubleClickZoom();
|
|
8066
7570
|
const colors = this.getColorConfig(layer.name);
|
|
8067
7571
|
const line_color = colors.lineColor;
|
|
8068
7572
|
const line_fina_color = colors.lineFinalColor;
|
|
@@ -8629,7 +8133,7 @@ var PolygonEditor = class {
|
|
|
8629
8133
|
if (!polygon) return [];
|
|
8630
8134
|
const hierarchy = typeof polygon.hierarchy?.getValue === "function" ? polygon.hierarchy.getValue(C.JulianDate.now()) : polygon.hierarchy;
|
|
8631
8135
|
const positions = hierarchy?.positions ?? hierarchy ?? [];
|
|
8632
|
-
|
|
8136
|
+
const points = positions.map((cartesian) => {
|
|
8633
8137
|
const cartographic = C.Cartographic.fromCartesian(cartesian);
|
|
8634
8138
|
return {
|
|
8635
8139
|
lon: C.Math.toDegrees(cartographic.longitude),
|
|
@@ -8637,6 +8141,14 @@ var PolygonEditor = class {
|
|
|
8637
8141
|
height: cartographic.height
|
|
8638
8142
|
};
|
|
8639
8143
|
});
|
|
8144
|
+
if (points.length > 0) {
|
|
8145
|
+
const first = points[0];
|
|
8146
|
+
const last = points[points.length - 1];
|
|
8147
|
+
if (first.lon !== last.lon || first.lat !== last.lat || first.height !== last.height) {
|
|
8148
|
+
points.push({ ...first });
|
|
8149
|
+
}
|
|
8150
|
+
}
|
|
8151
|
+
return points;
|
|
8640
8152
|
}
|
|
8641
8153
|
/**
|
|
8642
8154
|
* 辅助方法:获取实体所属的 DataSource
|
|
@@ -9485,6 +8997,7 @@ var PolygonEditor = class {
|
|
|
9485
8997
|
const nameStr = `circle_${(circleCount + 1).toString().padStart(2, "0")}`;
|
|
9486
8998
|
this.clearAllPolygonHighlights();
|
|
9487
8999
|
this.stopInternal();
|
|
9000
|
+
this.disableDoubleClickZoom();
|
|
9488
9001
|
let centerPosition = null;
|
|
9489
9002
|
let currentRadius = 0;
|
|
9490
9003
|
let tempCenterPoint;
|
|
@@ -9698,6 +9211,7 @@ var PolygonEditor = class {
|
|
|
9698
9211
|
currentRadius = 0;
|
|
9699
9212
|
this.destroyHandler();
|
|
9700
9213
|
this.removeKeyboardListener();
|
|
9214
|
+
this.restoreDoubleClickZoom();
|
|
9701
9215
|
};
|
|
9702
9216
|
this.handler && this.handler.setInputAction(
|
|
9703
9217
|
cancelCircleDrawing,
|
|
@@ -9733,6 +9247,7 @@ var PolygonEditor = class {
|
|
|
9733
9247
|
const line_fina_color = colors.lineFinalColor;
|
|
9734
9248
|
this.clearAllPolygonHighlights();
|
|
9735
9249
|
this.stopInternal();
|
|
9250
|
+
this.disableDoubleClickZoom();
|
|
9736
9251
|
let pointCount = 0;
|
|
9737
9252
|
this.handler = new C.ScreenSpaceEventHandler(this.viewer.scene.canvas);
|
|
9738
9253
|
this.handler && this.handler.setInputAction(
|
|
@@ -9827,6 +9342,7 @@ var PolygonEditor = class {
|
|
|
9827
9342
|
const stopPointDrawing = () => {
|
|
9828
9343
|
this.destroyHandler();
|
|
9829
9344
|
this.removeKeyboardListener();
|
|
9345
|
+
this.restoreDoubleClickZoom();
|
|
9830
9346
|
};
|
|
9831
9347
|
this.handler && this.handler.setInputAction(
|
|
9832
9348
|
stopPointDrawing,
|
|
@@ -10758,7 +10274,15 @@ var CZMLManager = class {
|
|
|
10758
10274
|
const hProp = entity.polygon.hierarchy;
|
|
10759
10275
|
const hVal = typeof hProp?.getValue === "function" ? hProp.getValue(now) : hProp;
|
|
10760
10276
|
const outer = Array.isArray(hVal) ? hVal : hVal?.positions ?? [];
|
|
10761
|
-
|
|
10277
|
+
const points = outer.map(toLonLatHeight);
|
|
10278
|
+
if (points.length > 0) {
|
|
10279
|
+
const first = points[0];
|
|
10280
|
+
const last = points[points.length - 1];
|
|
10281
|
+
if (first.lon !== last.lon || first.lat !== last.lat || first.height !== last.height) {
|
|
10282
|
+
points.push({ ...first });
|
|
10283
|
+
}
|
|
10284
|
+
}
|
|
10285
|
+
return points;
|
|
10762
10286
|
}
|
|
10763
10287
|
if (entity?.polyline?.positions) {
|
|
10764
10288
|
const pProp = entity.polyline.positions;
|