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