@jorgmoritz/gis-manager 0.1.21 → 0.1.26
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/dist/{VertexDetailInfo-BoVDy22s.d.cts → VertexDetailInfo-CProWwqv.d.cts} +51 -1
- package/dist/{VertexDetailInfo-BoVDy22s.d.ts → VertexDetailInfo-CProWwqv.d.ts} +51 -1
- package/dist/index.cjs +347 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -12
- package/dist/index.d.ts +36 -12
- package/dist/index.js +347 -52
- package/dist/index.js.map +1 -1
- package/dist/vue/index.cjs +346 -51
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.d.cts +1 -1
- package/dist/vue/index.d.ts +1 -1
- package/dist/vue/index.js +346 -51
- package/dist/vue/index.js.map +1 -1
- package/package.json +1 -1
package/dist/vue/index.cjs
CHANGED
|
@@ -62,6 +62,8 @@ var CameraEventBus = class {
|
|
|
62
62
|
__publicField(this, "onPoseChange", new Emitter());
|
|
63
63
|
/** 视锥体形状变化事件 */
|
|
64
64
|
__publicField(this, "onFrustumShapeChange", new Emitter());
|
|
65
|
+
/** 飞机游标姿态变化事件 */
|
|
66
|
+
__publicField(this, "onCursorPoseChange", new Emitter());
|
|
65
67
|
}
|
|
66
68
|
/**
|
|
67
69
|
* 清理所有监听器
|
|
@@ -70,9 +72,20 @@ var CameraEventBus = class {
|
|
|
70
72
|
this.onFOVChange.clear();
|
|
71
73
|
this.onPoseChange.clear();
|
|
72
74
|
this.onFrustumShapeChange.clear();
|
|
75
|
+
this.onCursorPoseChange.clear();
|
|
73
76
|
}
|
|
74
77
|
};
|
|
75
|
-
var
|
|
78
|
+
var GLOBAL_KEY = "__gisManager_globalCameraEventBus__";
|
|
79
|
+
function getGlobalEventBus() {
|
|
80
|
+
if (typeof window !== "undefined") {
|
|
81
|
+
if (!window[GLOBAL_KEY]) {
|
|
82
|
+
window[GLOBAL_KEY] = new CameraEventBus();
|
|
83
|
+
}
|
|
84
|
+
return window[GLOBAL_KEY];
|
|
85
|
+
}
|
|
86
|
+
return new CameraEventBus();
|
|
87
|
+
}
|
|
88
|
+
var globalCameraEventBus = getGlobalEventBus();
|
|
76
89
|
|
|
77
90
|
// src/core/LayerManager.ts
|
|
78
91
|
var layerIdSeq = 0;
|
|
@@ -1080,7 +1093,9 @@ var SceneManager = class {
|
|
|
1080
1093
|
depth: true,
|
|
1081
1094
|
stencil: true,
|
|
1082
1095
|
antialias: true,
|
|
1083
|
-
powerPreference: "high-performance"
|
|
1096
|
+
powerPreference: "high-performance",
|
|
1097
|
+
preserveDrawingBuffer: true
|
|
1098
|
+
// 必需:允许 canvas.toDataURL() 截图
|
|
1084
1099
|
}
|
|
1085
1100
|
},
|
|
1086
1101
|
...viewerOptions
|
|
@@ -1518,8 +1533,8 @@ var CameraFOVController = class {
|
|
|
1518
1533
|
if (!this.sliderEl) return;
|
|
1519
1534
|
const sliderValue = parseFloat(this.sliderEl.value);
|
|
1520
1535
|
const sliderIndex = this.focalLengthPresets.length - 1 - sliderValue;
|
|
1521
|
-
const
|
|
1522
|
-
const fov = this.
|
|
1536
|
+
const focalLength = this.interpolateFocalLength(sliderIndex);
|
|
1537
|
+
const fov = this.focalLengthToFOV(focalLength);
|
|
1523
1538
|
this.currentFOV = fov;
|
|
1524
1539
|
this.updateDisplay();
|
|
1525
1540
|
this.emitChange();
|
|
@@ -1527,24 +1542,35 @@ var CameraFOVController = class {
|
|
|
1527
1542
|
this.sensorWidth = opts.sensorWidth ?? 36;
|
|
1528
1543
|
this.focalLengthPresets = opts.focalLengthPresets ?? [112, 56, 14, 7, 3, 1];
|
|
1529
1544
|
if (opts.minFOV === void 0 || opts.maxFOV === void 0) {
|
|
1530
|
-
const
|
|
1531
|
-
const
|
|
1532
|
-
this.maxFOV = this.
|
|
1533
|
-
this.minFOV = this.
|
|
1545
|
+
const minFocalLength = Math.min(...this.focalLengthPresets);
|
|
1546
|
+
const maxFocalLength = Math.max(...this.focalLengthPresets);
|
|
1547
|
+
this.maxFOV = this.focalLengthToFOVDirect(minFocalLength);
|
|
1548
|
+
this.minFOV = this.focalLengthToFOVDirect(maxFocalLength);
|
|
1534
1549
|
} else {
|
|
1535
1550
|
this.minFOV = opts.minFOV;
|
|
1536
1551
|
this.maxFOV = opts.maxFOV;
|
|
1537
1552
|
}
|
|
1538
|
-
this.currentFOV = opts.initialFOV ?? this.
|
|
1553
|
+
this.currentFOV = opts.initialFOV ?? this.focalLengthToFOVDirect(56);
|
|
1539
1554
|
this.useGlobalEventBus = opts.useGlobalEventBus ?? true;
|
|
1540
1555
|
this.createUI();
|
|
1556
|
+
this.setupExternalFOVListener();
|
|
1541
1557
|
}
|
|
1542
1558
|
/**
|
|
1543
|
-
*
|
|
1559
|
+
* 🆕 监听外部 FOV 变化事件(来自 UI 面板等),同步更新滑块位置
|
|
1544
1560
|
*/
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1561
|
+
setupExternalFOVListener() {
|
|
1562
|
+
if (!this.useGlobalEventBus) return;
|
|
1563
|
+
globalCameraEventBus.onFOVChange.on((event) => {
|
|
1564
|
+
if (event.source !== "controller") {
|
|
1565
|
+
this.setFOVSilent(event.fov);
|
|
1566
|
+
}
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1569
|
+
/**
|
|
1570
|
+
* 焦距转换为 FOV(度)- 直接计算版本
|
|
1571
|
+
*/
|
|
1572
|
+
focalLengthToFOVDirect(focalLengthMm) {
|
|
1573
|
+
const fovRad = 2 * Math.atan(this.sensorWidth / (2 * focalLengthMm));
|
|
1548
1574
|
return fovRad * 180 / Math.PI;
|
|
1549
1575
|
}
|
|
1550
1576
|
/**
|
|
@@ -1668,7 +1694,7 @@ var CameraFOVController = class {
|
|
|
1668
1694
|
`;
|
|
1669
1695
|
this.focalLengthPresets.forEach((fl) => {
|
|
1670
1696
|
const marker = document.createElement("div");
|
|
1671
|
-
marker.textContent = `${fl}
|
|
1697
|
+
marker.textContent = `${fl}`;
|
|
1672
1698
|
marker.style.cssText = `
|
|
1673
1699
|
cursor: pointer;
|
|
1674
1700
|
padding: 2px 4px;
|
|
@@ -1683,7 +1709,7 @@ var CameraFOVController = class {
|
|
|
1683
1709
|
marker.style.background = "transparent";
|
|
1684
1710
|
});
|
|
1685
1711
|
marker.addEventListener("click", () => {
|
|
1686
|
-
this.
|
|
1712
|
+
this.setFocalLength(fl);
|
|
1687
1713
|
});
|
|
1688
1714
|
markersContainer.appendChild(marker);
|
|
1689
1715
|
});
|
|
@@ -1696,38 +1722,38 @@ var CameraFOVController = class {
|
|
|
1696
1722
|
this.emitChange();
|
|
1697
1723
|
}
|
|
1698
1724
|
/**
|
|
1699
|
-
*
|
|
1725
|
+
* 根据索引插值计算焦距值
|
|
1700
1726
|
*/
|
|
1701
|
-
|
|
1727
|
+
interpolateFocalLength(index) {
|
|
1702
1728
|
const clampedIndex = Math.max(0, Math.min(this.focalLengthPresets.length - 1, index));
|
|
1703
1729
|
if (Number.isInteger(clampedIndex)) {
|
|
1704
1730
|
return this.focalLengthPresets[clampedIndex];
|
|
1705
1731
|
}
|
|
1706
1732
|
const lowerIndex = Math.floor(clampedIndex);
|
|
1707
1733
|
const upperIndex = Math.ceil(clampedIndex);
|
|
1708
|
-
const
|
|
1709
|
-
const
|
|
1734
|
+
const lowerFL = this.focalLengthPresets[lowerIndex];
|
|
1735
|
+
const upperFL = this.focalLengthPresets[upperIndex];
|
|
1710
1736
|
const fraction = clampedIndex - lowerIndex;
|
|
1711
|
-
return
|
|
1737
|
+
return lowerFL + (upperFL - lowerFL) * fraction;
|
|
1712
1738
|
}
|
|
1713
1739
|
/**
|
|
1714
|
-
*
|
|
1740
|
+
* 根据焦距值计算对应的索引(可以是小数)
|
|
1715
1741
|
*/
|
|
1716
|
-
|
|
1717
|
-
const
|
|
1718
|
-
const
|
|
1719
|
-
const
|
|
1742
|
+
getFocalLengthIndex(focalLength) {
|
|
1743
|
+
const minFL = Math.min(...this.focalLengthPresets);
|
|
1744
|
+
const maxFL = Math.max(...this.focalLengthPresets);
|
|
1745
|
+
const clampedFL = Math.max(minFL, Math.min(maxFL, focalLength));
|
|
1720
1746
|
for (let i = 0; i < this.focalLengthPresets.length - 1; i++) {
|
|
1721
1747
|
const current = this.focalLengthPresets[i];
|
|
1722
1748
|
const next = this.focalLengthPresets[i + 1];
|
|
1723
|
-
if (current <=
|
|
1724
|
-
const fraction = (
|
|
1749
|
+
if (current <= clampedFL && clampedFL <= next || current >= clampedFL && clampedFL >= next) {
|
|
1750
|
+
const fraction = (clampedFL - current) / (next - current);
|
|
1725
1751
|
return i + fraction;
|
|
1726
1752
|
}
|
|
1727
1753
|
}
|
|
1728
1754
|
return this.focalLengthPresets.indexOf(
|
|
1729
1755
|
this.focalLengthPresets.reduce(
|
|
1730
|
-
(prev, curr) => Math.abs(curr -
|
|
1756
|
+
(prev, curr) => Math.abs(curr - clampedFL) < Math.abs(prev - clampedFL) ? curr : prev
|
|
1731
1757
|
)
|
|
1732
1758
|
);
|
|
1733
1759
|
}
|
|
@@ -1736,8 +1762,7 @@ var CameraFOVController = class {
|
|
|
1736
1762
|
*/
|
|
1737
1763
|
getClosestPresetIndex(fov) {
|
|
1738
1764
|
const focalLength = this.fovToFocalLength(fov);
|
|
1739
|
-
const
|
|
1740
|
-
const index = this.getZoomMultiplierIndex(zoomMultiplier);
|
|
1765
|
+
const index = this.getFocalLengthIndex(focalLength);
|
|
1741
1766
|
return this.focalLengthPresets.length - 1 - index;
|
|
1742
1767
|
}
|
|
1743
1768
|
/**
|
|
@@ -1745,9 +1770,8 @@ var CameraFOVController = class {
|
|
|
1745
1770
|
*/
|
|
1746
1771
|
updateDisplay() {
|
|
1747
1772
|
const focalLength = this.fovToFocalLength(this.currentFOV);
|
|
1748
|
-
const zoomMultiplier = focalLength / this.sensorWidth;
|
|
1749
1773
|
if (this.labelEl) {
|
|
1750
|
-
this.labelEl.textContent = `\
|
|
1774
|
+
this.labelEl.textContent = `\u7126\u8DDD ${Math.round(focalLength)}`;
|
|
1751
1775
|
}
|
|
1752
1776
|
}
|
|
1753
1777
|
/**
|
|
@@ -1818,6 +1842,18 @@ var CameraFOVController = class {
|
|
|
1818
1842
|
this.updateDisplay();
|
|
1819
1843
|
this.emitChange();
|
|
1820
1844
|
}
|
|
1845
|
+
/**
|
|
1846
|
+
* 🆕 静默设置 FOV(度)- 只更新滑块位置,不广播事件
|
|
1847
|
+
* 用于响应外部 FOV 变化事件,避免循环广播
|
|
1848
|
+
*/
|
|
1849
|
+
setFOVSilent(fovDeg) {
|
|
1850
|
+
this.currentFOV = Math.max(this.minFOV, Math.min(this.maxFOV, fovDeg));
|
|
1851
|
+
if (this.sliderEl) {
|
|
1852
|
+
const index = this.getClosestPresetIndex(this.currentFOV);
|
|
1853
|
+
this.sliderEl.value = String(index);
|
|
1854
|
+
}
|
|
1855
|
+
this.updateDisplay();
|
|
1856
|
+
}
|
|
1821
1857
|
/**
|
|
1822
1858
|
* 获取当前 FOV
|
|
1823
1859
|
*/
|
|
@@ -2884,6 +2920,7 @@ var AirplaneCursor = class {
|
|
|
2884
2920
|
this.opts?.onPose?.({ ...pose });
|
|
2885
2921
|
this.viewer.scene?.requestRender?.();
|
|
2886
2922
|
this.updateFrustum();
|
|
2923
|
+
this.broadcastPoseChange();
|
|
2887
2924
|
}
|
|
2888
2925
|
requestAnimationFrame(update);
|
|
2889
2926
|
};
|
|
@@ -2941,9 +2978,15 @@ var AirplaneCursor = class {
|
|
|
2941
2978
|
} catch {
|
|
2942
2979
|
}
|
|
2943
2980
|
}
|
|
2944
|
-
/**
|
|
2981
|
+
/** 获取当前姿态(包含高度信息) */
|
|
2945
2982
|
getPose() {
|
|
2946
|
-
|
|
2983
|
+
const C = this.CesiumNS;
|
|
2984
|
+
const cartographic = C.Cartographic.fromCartesian(this.pose.position);
|
|
2985
|
+
const altitude = cartographic ? cartographic.height : 0;
|
|
2986
|
+
return {
|
|
2987
|
+
...this.pose,
|
|
2988
|
+
altitude
|
|
2989
|
+
};
|
|
2947
2990
|
}
|
|
2948
2991
|
/** 获取内部实体(用于拾取识别) */
|
|
2949
2992
|
getEntity() {
|
|
@@ -3003,8 +3046,58 @@ var AirplaneCursor = class {
|
|
|
3003
3046
|
} catch {
|
|
3004
3047
|
}
|
|
3005
3048
|
this.updateFrustum();
|
|
3049
|
+
this.broadcastPoseChange();
|
|
3006
3050
|
this.viewer.scene?.requestRender?.();
|
|
3007
3051
|
}
|
|
3052
|
+
/**
|
|
3053
|
+
* 广播游标姿态变化事件到全局事件总线
|
|
3054
|
+
*/
|
|
3055
|
+
broadcastPoseChange() {
|
|
3056
|
+
try {
|
|
3057
|
+
const C = this.CesiumNS;
|
|
3058
|
+
const cartographic = C.Cartographic.fromCartesian(this.pose.position);
|
|
3059
|
+
const altitude = cartographic ? cartographic.height : 0;
|
|
3060
|
+
console.log("[AirplaneCursor] \u{1F4E1} \u5E7F\u64AD\u59FF\u6001\u53D8\u5316:", {
|
|
3061
|
+
heading: this.pose.heading,
|
|
3062
|
+
pitch: this.pose.pitch,
|
|
3063
|
+
altitude
|
|
3064
|
+
});
|
|
3065
|
+
globalCameraEventBus.onCursorPoseChange.emit({
|
|
3066
|
+
position: this.pose.position,
|
|
3067
|
+
heading: this.pose.heading,
|
|
3068
|
+
pitch: this.pose.pitch,
|
|
3069
|
+
roll: this.pose.roll,
|
|
3070
|
+
altitude,
|
|
3071
|
+
source: "cursor"
|
|
3072
|
+
});
|
|
3073
|
+
} catch (e) {
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
/**
|
|
3077
|
+
* 模拟按键按下(用于虚拟控制器)
|
|
3078
|
+
* @param key 按键名称 (w/a/s/d/q/e/c/z)
|
|
3079
|
+
* @param duration 按键持续时间(毫秒),默认 100ms
|
|
3080
|
+
*/
|
|
3081
|
+
simulateKeyPress(key, duration = 100) {
|
|
3082
|
+
const lowerKey = key.toLowerCase();
|
|
3083
|
+
const keyMap = {
|
|
3084
|
+
"c": "c",
|
|
3085
|
+
// 上升
|
|
3086
|
+
"z": "z"
|
|
3087
|
+
// 下降
|
|
3088
|
+
};
|
|
3089
|
+
const mappedKey = keyMap[lowerKey] || lowerKey;
|
|
3090
|
+
console.log("[AirplaneCursor] \u{1F3AE} simulateKeyPress:", mappedKey, "duration:", duration);
|
|
3091
|
+
console.log("[AirplaneCursor] \u{1F3AE} updateLoopRunning:", this.updateLoopRunning);
|
|
3092
|
+
this.keysPressed.add(mappedKey);
|
|
3093
|
+
if (!this.updateLoopRunning) {
|
|
3094
|
+
console.log("[AirplaneCursor] \u{1F3AE} \u542F\u52A8 updateLoop");
|
|
3095
|
+
this.startUpdateLoop();
|
|
3096
|
+
}
|
|
3097
|
+
setTimeout(() => {
|
|
3098
|
+
this.keysPressed.delete(mappedKey);
|
|
3099
|
+
}, duration);
|
|
3100
|
+
}
|
|
3008
3101
|
destroy() {
|
|
3009
3102
|
if (this.destroyed) return;
|
|
3010
3103
|
this.destroyed = true;
|
|
@@ -5067,6 +5160,31 @@ function startPathEditing(CesiumNS, viewer, entityOrId, options) {
|
|
|
5067
5160
|
vertexLabelManager.updateLabelPosition(index, newPosition);
|
|
5068
5161
|
} catch {
|
|
5069
5162
|
}
|
|
5163
|
+
if (options?.onVertexDragMoveDetail) {
|
|
5164
|
+
try {
|
|
5165
|
+
let coordinates = { longitude: 0, latitude: 0, height: 0 };
|
|
5166
|
+
try {
|
|
5167
|
+
const cartographic = C.Cartographic.fromCartesian(newPosition);
|
|
5168
|
+
coordinates = {
|
|
5169
|
+
longitude: C.Math.toDegrees(cartographic.longitude),
|
|
5170
|
+
latitude: C.Math.toDegrees(cartographic.latitude),
|
|
5171
|
+
height: cartographic.height
|
|
5172
|
+
};
|
|
5173
|
+
} catch {
|
|
5174
|
+
}
|
|
5175
|
+
const displayNumber = hiddenClimbIndex === 1 && index > 1 ? index - 1 : index;
|
|
5176
|
+
const dragMoveInfo = {
|
|
5177
|
+
index,
|
|
5178
|
+
displayNumber,
|
|
5179
|
+
position: newPosition,
|
|
5180
|
+
coordinates,
|
|
5181
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
5182
|
+
};
|
|
5183
|
+
options.onVertexDragMoveDetail(dragMoveInfo);
|
|
5184
|
+
} catch (error) {
|
|
5185
|
+
console.error("Error in onVertexDragMoveDetail:", error);
|
|
5186
|
+
}
|
|
5187
|
+
}
|
|
5070
5188
|
},
|
|
5071
5189
|
onVertexDragEnd: (index, finalPosition) => {
|
|
5072
5190
|
editedIndices.add(index);
|
|
@@ -5107,6 +5225,12 @@ function startPathEditing(CesiumNS, viewer, entityOrId, options) {
|
|
|
5107
5225
|
getAirplaneCursor: () => airplaneCursor,
|
|
5108
5226
|
getPoseData: () => ({ headings, pitches, rolls, fovs }),
|
|
5109
5227
|
getEntity: () => entity,
|
|
5228
|
+
/** 模拟按键控制飞机游标(用于虚拟控制器) */
|
|
5229
|
+
simulateKeyPress: (key, duration) => {
|
|
5230
|
+
airplaneCursor?.simulateKeyPress(key, duration);
|
|
5231
|
+
},
|
|
5232
|
+
/** 获取游标当前姿态(包含高度) */
|
|
5233
|
+
getCursorPose: () => airplaneCursor?.getPose(),
|
|
5110
5234
|
// 🆕 快速编辑回调
|
|
5111
5235
|
getQuickEditEnabled: () => quickEditEnabled,
|
|
5112
5236
|
getQuickEditOptions: () => ({
|
|
@@ -5289,9 +5413,166 @@ function startPathEditing(CesiumNS, viewer, entityOrId, options) {
|
|
|
5289
5413
|
/** 🆕 检查快速编辑模式是否启用 */
|
|
5290
5414
|
isQuickEditEnabled: () => {
|
|
5291
5415
|
return quickEditEnabled;
|
|
5292
|
-
}
|
|
5416
|
+
},
|
|
5417
|
+
// ========================
|
|
5418
|
+
// 🆕 程序化更新方法
|
|
5419
|
+
// ========================
|
|
5420
|
+
/**
|
|
5421
|
+
* 🆕 程序化更新指定航点
|
|
5422
|
+
* @param index 航点索引
|
|
5423
|
+
* @param updates 需要更新的字段
|
|
5424
|
+
* @returns 是否更新成功
|
|
5425
|
+
*/
|
|
5426
|
+
updateWaypoint: (index, updates) => {
|
|
5427
|
+
if (index < 0 || index >= positions.length) {
|
|
5428
|
+
console.warn(`[updateWaypoint] Invalid index: ${index}, valid range: 0-${positions.length - 1}`);
|
|
5429
|
+
return false;
|
|
5430
|
+
}
|
|
5431
|
+
try {
|
|
5432
|
+
let positionUpdated = false;
|
|
5433
|
+
if (updates.position) {
|
|
5434
|
+
positions[index] = updates.position;
|
|
5435
|
+
positionUpdated = true;
|
|
5436
|
+
}
|
|
5437
|
+
if (updates.altitude !== void 0 && !updates.position) {
|
|
5438
|
+
const currentPos = positions[index];
|
|
5439
|
+
const cartographic = C.Cartographic.fromCartesian(currentPos);
|
|
5440
|
+
const newPos = C.Cartesian3.fromRadians(
|
|
5441
|
+
cartographic.longitude,
|
|
5442
|
+
cartographic.latitude,
|
|
5443
|
+
updates.altitude
|
|
5444
|
+
);
|
|
5445
|
+
positions[index] = newPos;
|
|
5446
|
+
positionUpdated = true;
|
|
5447
|
+
}
|
|
5448
|
+
if (positionUpdated) {
|
|
5449
|
+
const newPos = positions[index];
|
|
5450
|
+
if (handles[index]) {
|
|
5451
|
+
try {
|
|
5452
|
+
handles[index].position = newPos;
|
|
5453
|
+
} catch {
|
|
5454
|
+
}
|
|
5455
|
+
}
|
|
5456
|
+
try {
|
|
5457
|
+
vertexLabelManager.updateLabelPosition(index, newPos);
|
|
5458
|
+
} catch {
|
|
5459
|
+
}
|
|
5460
|
+
try {
|
|
5461
|
+
createOrUpdateMarkerForIndex(index);
|
|
5462
|
+
} catch {
|
|
5463
|
+
}
|
|
5464
|
+
}
|
|
5465
|
+
if (updates.heading !== void 0) headings[index] = updates.heading;
|
|
5466
|
+
if (updates.pitch !== void 0) pitches[index] = updates.pitch;
|
|
5467
|
+
if (updates.roll !== void 0) rolls[index] = updates.roll;
|
|
5468
|
+
if (updates.fov !== void 0) {
|
|
5469
|
+
fovs[index] = updates.fov;
|
|
5470
|
+
if (index === activeIndex) {
|
|
5471
|
+
globalCameraEventBus.onFOVChange.emit({
|
|
5472
|
+
fov: updates.fov,
|
|
5473
|
+
focalLength: fovToFocalLength(updates.fov),
|
|
5474
|
+
source: "user"
|
|
5475
|
+
});
|
|
5476
|
+
}
|
|
5477
|
+
}
|
|
5478
|
+
if (index === activeIndex && airplaneCursor) {
|
|
5479
|
+
try {
|
|
5480
|
+
airplaneCursor.setPose(
|
|
5481
|
+
positions[index],
|
|
5482
|
+
headings[index] ?? 0,
|
|
5483
|
+
pitches[index] ?? -10,
|
|
5484
|
+
rolls[index] ?? 0
|
|
5485
|
+
);
|
|
5486
|
+
} catch {
|
|
5487
|
+
}
|
|
5488
|
+
}
|
|
5489
|
+
stateManager.persistToEntity(positions, headings, pitches, rolls, fovs);
|
|
5490
|
+
return true;
|
|
5491
|
+
} catch (error) {
|
|
5492
|
+
console.error("[updateWaypoint] Error:", error);
|
|
5493
|
+
return false;
|
|
5494
|
+
}
|
|
5495
|
+
},
|
|
5496
|
+
/**
|
|
5497
|
+
* 🆕 更新航点位置
|
|
5498
|
+
*/
|
|
5499
|
+
updateWaypointPosition: function(index, position) {
|
|
5500
|
+
return this.updateWaypoint(index, { position });
|
|
5501
|
+
},
|
|
5502
|
+
/**
|
|
5503
|
+
* 🆕 更新航点高度(仅垂直方向,保持经纬度不变)
|
|
5504
|
+
*/
|
|
5505
|
+
updateWaypointAltitude: function(index, altitude) {
|
|
5506
|
+
return this.updateWaypoint(index, { altitude });
|
|
5507
|
+
},
|
|
5508
|
+
/**
|
|
5509
|
+
* 🆕 更新航点偏航角
|
|
5510
|
+
*/
|
|
5511
|
+
updateWaypointHeading: function(index, heading) {
|
|
5512
|
+
return this.updateWaypoint(index, { heading });
|
|
5513
|
+
},
|
|
5514
|
+
/**
|
|
5515
|
+
* 🆕 更新航点俯仰角
|
|
5516
|
+
*/
|
|
5517
|
+
updateWaypointPitch: function(index, pitch) {
|
|
5518
|
+
return this.updateWaypoint(index, { pitch });
|
|
5519
|
+
},
|
|
5520
|
+
/**
|
|
5521
|
+
* 🆕 更新航点视野角
|
|
5522
|
+
*/
|
|
5523
|
+
updateWaypointFov: function(index, fov) {
|
|
5524
|
+
return this.updateWaypoint(index, { fov });
|
|
5525
|
+
},
|
|
5526
|
+
/**
|
|
5527
|
+
* 🆕 批量更新多个航点
|
|
5528
|
+
*/
|
|
5529
|
+
batchUpdateWaypoints: function(updates) {
|
|
5530
|
+
let allSuccess = true;
|
|
5531
|
+
for (const { index, data } of updates) {
|
|
5532
|
+
if (!this.updateWaypoint(index, data)) {
|
|
5533
|
+
allSuccess = false;
|
|
5534
|
+
}
|
|
5535
|
+
}
|
|
5536
|
+
return allSuccess;
|
|
5537
|
+
},
|
|
5538
|
+
/**
|
|
5539
|
+
* 🆕 程序化选中指定航点
|
|
5540
|
+
* 将飞机游标移动到指定航点位置,更新选中状态
|
|
5541
|
+
* @param index 航点索引
|
|
5542
|
+
* @returns 是否选中成功
|
|
5543
|
+
*/
|
|
5544
|
+
selectVertex: (index) => {
|
|
5545
|
+
if (index < 0 || index >= positions.length) {
|
|
5546
|
+
console.warn(`[selectVertex] Invalid index: ${index}, valid range: 0-${positions.length - 1}`);
|
|
5547
|
+
return false;
|
|
5548
|
+
}
|
|
5549
|
+
try {
|
|
5550
|
+
setActiveIndex(index);
|
|
5551
|
+
return true;
|
|
5552
|
+
} catch (e) {
|
|
5553
|
+
console.error("[selectVertex] Failed to select vertex:", e);
|
|
5554
|
+
return false;
|
|
5555
|
+
}
|
|
5556
|
+
},
|
|
5557
|
+
/**
|
|
5558
|
+
* 🆕 模拟按键控制飞机游标(用于虚拟控制器)
|
|
5559
|
+
* @param key 按键名称 (w/a/s/d/q/e/c/z)
|
|
5560
|
+
* @param duration 按键持续时间(毫秒)
|
|
5561
|
+
*/
|
|
5562
|
+
simulateKeyPress: (key, duration) => {
|
|
5563
|
+
airplaneCursor?.simulateKeyPress(key, duration);
|
|
5564
|
+
},
|
|
5565
|
+
/**
|
|
5566
|
+
* 🆕 获取游标当前姿态(包含高度)
|
|
5567
|
+
*/
|
|
5568
|
+
getCursorPose: () => airplaneCursor?.getPose()
|
|
5293
5569
|
};
|
|
5294
5570
|
}
|
|
5571
|
+
function fovToFocalLength(fovDeg) {
|
|
5572
|
+
const sensorWidth = 36;
|
|
5573
|
+
const fovRad = fovDeg * Math.PI / 180;
|
|
5574
|
+
return sensorWidth / (2 * Math.tan(fovRad / 2));
|
|
5575
|
+
}
|
|
5295
5576
|
|
|
5296
5577
|
// src/core/path-manager/ArrowShape.ts
|
|
5297
5578
|
var ArrowShape = class {
|
|
@@ -5688,7 +5969,6 @@ function parsePoseFromAction(action) {
|
|
|
5688
5969
|
fov: parseFloat(numbers[3])
|
|
5689
5970
|
};
|
|
5690
5971
|
}
|
|
5691
|
-
console.warn("[sinoflyAdapter] \u65E0\u6CD5\u89E3\u6790 action \u5B57\u6BB5:", action, error);
|
|
5692
5972
|
return {};
|
|
5693
5973
|
}
|
|
5694
5974
|
}
|
|
@@ -5706,15 +5986,40 @@ function parseTakeOffRefPoint(takeOffRefPoint, takeOffSecurityHeight, CesiumNS)
|
|
|
5706
5986
|
if (!takeOffRefPoint || typeof takeOffRefPoint !== "string" || takeOffRefPoint.trim() === "") {
|
|
5707
5987
|
return null;
|
|
5708
5988
|
}
|
|
5989
|
+
const C = CesiumNS;
|
|
5990
|
+
let longitude;
|
|
5991
|
+
let latitude;
|
|
5992
|
+
let height;
|
|
5993
|
+
const trimmed = takeOffRefPoint.trim();
|
|
5994
|
+
if (trimmed.includes(",")) {
|
|
5995
|
+
try {
|
|
5996
|
+
const parts = trimmed.split(",").map((p) => p.trim());
|
|
5997
|
+
if (parts.length >= 2) {
|
|
5998
|
+
latitude = parseFloat(parts[0]);
|
|
5999
|
+
longitude = parseFloat(parts[1]);
|
|
6000
|
+
height = parts.length >= 3 ? parseFloat(parts[2]) : takeOffSecurityHeight;
|
|
6001
|
+
if (isNaN(latitude) || isNaN(longitude) || isNaN(height)) {
|
|
6002
|
+
throw new Error("\u65E0\u6CD5\u89E3\u6790\u9017\u53F7\u5206\u9694\u7684\u5750\u6807\u503C");
|
|
6003
|
+
}
|
|
6004
|
+
const startPosition = C.Cartesian3.fromDegrees(longitude, latitude, height);
|
|
6005
|
+
const climbPosition = C.Cartesian3.fromDegrees(
|
|
6006
|
+
longitude,
|
|
6007
|
+
latitude,
|
|
6008
|
+
height + takeOffSecurityHeight
|
|
6009
|
+
);
|
|
6010
|
+
return {
|
|
6011
|
+
startPosition,
|
|
6012
|
+
climbPosition
|
|
6013
|
+
};
|
|
6014
|
+
}
|
|
6015
|
+
} catch (error) {
|
|
6016
|
+
}
|
|
6017
|
+
}
|
|
5709
6018
|
try {
|
|
5710
6019
|
const parsed = JSON.parse(takeOffRefPoint);
|
|
5711
6020
|
if (typeof parsed !== "object" || parsed === null) {
|
|
5712
6021
|
return null;
|
|
5713
6022
|
}
|
|
5714
|
-
const C = CesiumNS;
|
|
5715
|
-
let longitude;
|
|
5716
|
-
let latitude;
|
|
5717
|
-
let height;
|
|
5718
6023
|
if (typeof parsed.longitude === "number") {
|
|
5719
6024
|
longitude = parsed.longitude;
|
|
5720
6025
|
} else if (typeof parsed.lon === "number") {
|
|
@@ -5745,7 +6050,6 @@ function parseTakeOffRefPoint(takeOffRefPoint, takeOffSecurityHeight, CesiumNS)
|
|
|
5745
6050
|
climbPosition
|
|
5746
6051
|
};
|
|
5747
6052
|
} catch (error) {
|
|
5748
|
-
console.warn("[sinoflyAdapter] \u65E0\u6CD5\u89E3\u6790 takeOffRefPoint:", takeOffRefPoint, error);
|
|
5749
6053
|
return null;
|
|
5750
6054
|
}
|
|
5751
6055
|
}
|
|
@@ -5767,16 +6071,10 @@ function convertSinoflyWayline(data, options) {
|
|
|
5767
6071
|
if (!data.waypointInfo || !Array.isArray(data.waypointInfo)) {
|
|
5768
6072
|
throw new Error("[sinoflyAdapter] waypointInfo \u5FC5\u987B\u662F\u6570\u7EC4");
|
|
5769
6073
|
}
|
|
5770
|
-
if (data.waypointInfo.length === 0)
|
|
5771
|
-
console.warn("[sinoflyAdapter] waypointInfo \u6570\u7EC4\u4E3A\u7A7A\uFF0C\u5C06\u8FD4\u56DE\u7A7A\u7684\u822A\u70B9\u6570\u636E");
|
|
5772
|
-
}
|
|
6074
|
+
if (data.waypointInfo.length === 0) ;
|
|
5773
6075
|
if (data.waylineId === void 0 || data.waylineId === null) {
|
|
5774
6076
|
throw new Error("[sinoflyAdapter] waylineId \u4E0D\u80FD\u4E3A\u7A7A");
|
|
5775
6077
|
}
|
|
5776
|
-
console.log(`[sinoflyAdapter] \u5F00\u59CB\u8F6C\u6362\u822A\u7EBF ${data.waylineId}\uFF0C\u5305\u542B ${data.waypointInfo.length} \u4E2A\u822A\u70B9`);
|
|
5777
|
-
if (data.takeOffRefPoint) {
|
|
5778
|
-
console.log(`[sinoflyAdapter] \u68C0\u6D4B\u5230 takeOffRefPoint: ${data.takeOffRefPoint}`);
|
|
5779
|
-
}
|
|
5780
6078
|
const takeOffInfo = parseTakeOffRefPoint(
|
|
5781
6079
|
data.takeOffRefPoint,
|
|
5782
6080
|
data.takeOffSecurityHeight,
|
|
@@ -5841,7 +6139,6 @@ function convertSinoflyWayline(data, options) {
|
|
|
5841
6139
|
if (poseFromAction.roll !== void 0) roll = poseFromAction.roll;
|
|
5842
6140
|
if (poseFromAction.fov !== void 0) fov = poseFromAction.fov;
|
|
5843
6141
|
} catch (actionError) {
|
|
5844
|
-
console.warn(`[sinoflyAdapter] \u822A\u70B9 ${idx} action \u89E3\u6790\u5931\u8D25:`, actionError);
|
|
5845
6142
|
}
|
|
5846
6143
|
}
|
|
5847
6144
|
return {
|
|
@@ -5854,7 +6151,6 @@ function convertSinoflyWayline(data, options) {
|
|
|
5854
6151
|
// 重新分配 index,从 waypointStartIndex 开始
|
|
5855
6152
|
};
|
|
5856
6153
|
} catch (error) {
|
|
5857
|
-
console.error(`[sinoflyAdapter] \u822A\u70B9 ${idx} \u8F6C\u6362\u5931\u8D25:`, error);
|
|
5858
6154
|
throw new Error(`\u822A\u70B9 ${idx} \u8F6C\u6362\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
|
|
5859
6155
|
}
|
|
5860
6156
|
});
|
|
@@ -5862,7 +6158,6 @@ function convertSinoflyWayline(data, options) {
|
|
|
5862
6158
|
if (!Array.isArray(waypointData)) {
|
|
5863
6159
|
throw new Error("[sinoflyAdapter] waypointData \u4E0D\u662F\u6570\u7EC4");
|
|
5864
6160
|
}
|
|
5865
|
-
console.log(`[sinoflyAdapter] \u8F6C\u6362\u5B8C\u6210\uFF0C\u5171\u751F\u6210 ${waypointData.length} \u4E2A\u822A\u70B9`);
|
|
5866
6161
|
const metadata = {
|
|
5867
6162
|
waylineId: data.waylineId,
|
|
5868
6163
|
waylineType: data.waylineType,
|