@jorgmoritz/gis-manager 0.1.30 → 0.1.32

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/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 modelVerticalOffset = 35;
2841
- const modelForwardOffset = 5;
2842
- const modelRightOffset = -30;
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: 0.5,
2889
- minimumPixelSize: 32,
2890
- maximumScale: 100,
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
  },
@@ -3249,6 +3248,11 @@ var AirplaneCursor = class {
3249
3248
  } catch {
3250
3249
  }
3251
3250
  this.pyramidLayer = void 0;
3251
+ try {
3252
+ this.cameraChangedListener?.();
3253
+ } catch {
3254
+ }
3255
+ this.cameraChangedListener = void 0;
3252
3256
  try {
3253
3257
  this.frustum?.destroy();
3254
3258
  } catch {
@@ -4567,34 +4571,6 @@ var PathEditingEventHandler = class {
4567
4571
  * 🆕 处理快速编辑模式的点击
4568
4572
  */
4569
4573
  handleQuickEditClick(movement) {
4570
- const C = this.CesiumNS;
4571
- try {
4572
- const picked = this.viewer.scene.pick?.(movement.position);
4573
- const entity = picked?.id;
4574
- if (entity?.properties) {
4575
- const props = entity.properties;
4576
- const vertexIndex = props._vertexIndex?.getValue?.() ?? props._vertexIndex;
4577
- const type = props._type?.getValue?.() ?? props._type;
4578
- if (typeof vertexIndex === "number" && (type === "path-vertex" || type === "vertex-label")) {
4579
- if (vertexIndex !== this.hiddenClimbIndex && vertexIndex !== 0) {
4580
- console.log("[QuickEdit] \u70B9\u51FB\u5230\u5DF2\u5B58\u5728\u822A\u70B9\uFF0C\u9009\u4E2D\u800C\u975E\u65B0\u589E:", vertexIndex);
4581
- if (this.callbacks.onVertexSelect) {
4582
- this.callbacks.onVertexSelect(vertexIndex);
4583
- }
4584
- if (this.callbacks.onVertexSelectDetail) {
4585
- try {
4586
- const detailInfo = this.buildVertexDetailInfo(vertexIndex);
4587
- this.callbacks.onVertexSelectDetail(detailInfo);
4588
- } catch (error) {
4589
- console.error("Error building vertex detail info:", error);
4590
- }
4591
- }
4592
- return;
4593
- }
4594
- }
4595
- }
4596
- } catch (error) {
4597
- }
4598
4574
  const position = this.getPositionFromMouse(movement);
4599
4575
  if (!position) {
4600
4576
  console.warn("[QuickEdit] \u65E0\u6CD5\u83B7\u53D6\u70B9\u51FB\u4F4D\u7F6E");
@@ -4603,6 +4579,7 @@ var PathEditingEventHandler = class {
4603
4579
  const quickEditOptions = this.callbacks.getQuickEditOptions?.();
4604
4580
  if (!quickEditOptions) return;
4605
4581
  const { climbHeight, altitudeMode } = quickEditOptions;
4582
+ const C = this.CesiumNS;
4606
4583
  const originalCarto = C.Cartographic.fromCartesian(position);
4607
4584
  const originalHeight = originalCarto.height;
4608
4585
  const newPosition = this.applyClimbHeight(position, climbHeight, altitudeMode);
@@ -5457,10 +5434,6 @@ function startPathEditing(CesiumNS, viewer, entityOrId, options) {
5457
5434
  );
5458
5435
  const cleanupSession = () => {
5459
5436
  setActiveIndex(void 0);
5460
- try {
5461
- preview?.destroy();
5462
- } catch {
5463
- }
5464
5437
  try {
5465
5438
  handles.forEach((handle) => {
5466
5439
  if (handle) {
@@ -5870,6 +5843,13 @@ var ArrowShape = class {
5870
5843
  __publicField(this, "baseAlpha");
5871
5844
  __publicField(this, "outline");
5872
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);
5873
5853
  const C = this.CesiumNS;
5874
5854
  this.shaftHeight = opts.shaftHeight ?? 17;
5875
5855
  this.headHeight = opts.headHeight ?? 8;
@@ -5877,12 +5857,17 @@ var ArrowShape = class {
5877
5857
  this.shaftRadius = opts.shaftRadius ?? 3;
5878
5858
  this.headRadius = opts.headRadius ?? 6;
5879
5859
  this.baseRadius = opts.baseRadius ?? 8;
5880
- this.color = opts.color ? C.Color.fromCssColorString(opts.color) : C.Color.fromCssColorString("#2E77FB");
5860
+ this.color = opts.color ? C.Color.fromCssColorString(opts.color) : C.Color.fromCssColorString("#FFD700");
5881
5861
  this.shaftAlpha = opts.shaftAlpha ?? 1;
5882
5862
  this.headAlpha = opts.headAlpha ?? 1;
5883
- this.baseAlpha = opts.baseAlpha ?? 1;
5863
+ this.baseAlpha = opts.baseAlpha ?? 0.65;
5884
5864
  this.outline = opts.outline ?? false;
5885
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;
5886
5871
  }
5887
5872
  /**
5888
5873
  * Create arrow entities at given position
@@ -5900,22 +5885,40 @@ var ArrowShape = class {
5900
5885
  const carto = C.Cartographic.fromCartesian(position);
5901
5886
  const lon = C.Math.toDegrees(carto.longitude);
5902
5887
  const lat = C.Math.toDegrees(carto.latitude);
5903
- const shaftPosition = C.Cartesian3.fromDegrees(lon, lat, baseHeight + this.shaftHeight / 2);
5904
- const headPosition = C.Cartesian3.fromDegrees(
5905
- lon,
5906
- lat,
5907
- baseHeight + this.shaftHeight + this.headHeight / 2
5908
- );
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
+ }
5909
5904
  const hpr = new C.HeadingPitchRoll(0, 0, 0);
5910
5905
  const baseOrientation = C.Transforms.headingPitchRollQuaternion(position, hpr);
5911
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
+ };
5912
5915
  const shaftEntity = layer.entities.add({
5913
- position: new C.ConstantPositionProperty(shaftPosition),
5916
+ position: this.dynamicScale ? new C.CallbackProperty(getShaftPosition, false) : new C.ConstantPositionProperty(C.Cartesian3.fromDegrees(lon, lat, baseHeight + this.shaftHeight / 2)),
5914
5917
  orientation: fixedOrientation,
5915
5918
  cylinder: {
5916
- length: this.shaftHeight,
5917
- topRadius: this.shaftRadius,
5918
- 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,
5919
5922
  material: this.color.withAlpha(this.shaftAlpha),
5920
5923
  outline: this.outline,
5921
5924
  outlineColor: this.outlineColor,
@@ -5928,13 +5931,13 @@ var ArrowShape = class {
5928
5931
  });
5929
5932
  entities.push(shaftEntity);
5930
5933
  const headEntity = layer.entities.add({
5931
- position: new C.ConstantPositionProperty(headPosition),
5934
+ position: this.dynamicScale ? new C.CallbackProperty(getHeadPosition, false) : new C.ConstantPositionProperty(C.Cartesian3.fromDegrees(lon, lat, baseHeight + this.shaftHeight + this.headHeight / 2)),
5932
5935
  orientation: fixedOrientation,
5933
5936
  cylinder: {
5934
- length: this.headHeight,
5937
+ length: this.dynamicScale ? new C.CallbackProperty(() => this.headHeight * this.cachedScaleFactor, false) : this.headHeight,
5935
5938
  topRadius: 0,
5936
5939
  // Creates cone shape
5937
- bottomRadius: this.headRadius,
5940
+ bottomRadius: this.dynamicScale ? new C.CallbackProperty(() => this.headRadius * this.cachedScaleFactor, false) : this.headRadius,
5938
5941
  material: this.color.withAlpha(this.headAlpha),
5939
5942
  outline: this.outline,
5940
5943
  outlineColor: this.outlineColor,
@@ -5949,8 +5952,8 @@ var ArrowShape = class {
5949
5952
  const baseEntity = layer.entities.add({
5950
5953
  position,
5951
5954
  ellipse: {
5952
- semiMajorAxis: this.baseRadius,
5953
- 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,
5954
5957
  height: baseHeight,
5955
5958
  material: this.color.withAlpha(this.baseAlpha),
5956
5959
  outline: this.outline,
@@ -6089,7 +6092,13 @@ function startPathDrawing(CesiumNS, viewer, options, onComplete) {
6089
6092
  color: "#FFD700",
6090
6093
  shaftAlpha: 1,
6091
6094
  headAlpha: 1,
6092
- baseAlpha: 0.5
6095
+ baseAlpha: 0.5,
6096
+ // 启用动态缩放,和无人机模型一样根据相机距离调整大小
6097
+ dynamicScale: true,
6098
+ viewer,
6099
+ referenceDistance: 300,
6100
+ minScale: 0.3,
6101
+ maxScale: 2
6093
6102
  });
6094
6103
  const arrowEntities = arrowShape.createEntities(
6095
6104
  layer,
@@ -6588,7 +6597,13 @@ function renderFlightPath(CesiumNS, viewer, options) {
6588
6597
  color: "#FFD700",
6589
6598
  shaftAlpha: 0.98,
6590
6599
  headAlpha: 0.98,
6591
- baseAlpha: 0.65
6600
+ baseAlpha: 0.65,
6601
+ // 启用动态缩放
6602
+ dynamicScale: true,
6603
+ viewer,
6604
+ referenceDistance: 300,
6605
+ minScale: 0.3,
6606
+ maxScale: 2
6592
6607
  });
6593
6608
  arrowShape.createEntities(
6594
6609
  layer,
@@ -6712,515 +6727,6 @@ function renderFlightPathPreview(CesiumNS, viewer, options) {
6712
6727
  return { entity, controller };
6713
6728
  }
6714
6729
 
6715
- // src/core/path-manager/FlightPreviewController.ts
6716
- var FlightPreviewController = class {
6717
- constructor(CesiumNS, viewer, options) {
6718
- this.CesiumNS = CesiumNS;
6719
- this.viewer = viewer;
6720
- this.options = options;
6721
- // ========== 状态 ==========
6722
- __publicField(this, "state", "stopped");
6723
- __publicField(this, "destroyed", false);
6724
- // ========== 配置 ==========
6725
- __publicField(this, "speed");
6726
- __publicField(this, "loop");
6727
- __publicField(this, "showFrustum");
6728
- __publicField(this, "trackHighlightOptions");
6729
- // ========== 路径数据 ==========
6730
- __publicField(this, "waypoints", []);
6731
- __publicField(this, "totalDistance", 0);
6732
- // ========== 动画状态 ==========
6733
- __publicField(this, "currentDistance", 0);
6734
- // 当前已飞行距离
6735
- __publicField(this, "animationFrameId");
6736
- __publicField(this, "lastFrameTime");
6737
- // ========== 可视化组件 ==========
6738
- __publicField(this, "layer");
6739
- __publicField(this, "droneEntity");
6740
- __publicField(this, "frustum");
6741
- __publicField(this, "pathPreview");
6742
- // ========== 轨迹高亮 ==========
6743
- __publicField(this, "traveledPathEntity");
6744
- __publicField(this, "remainingPathEntity");
6745
- // ========== 事件 ==========
6746
- __publicField(this, "onStateChange", new Emitter());
6747
- __publicField(this, "onProgressChange", new Emitter());
6748
- this.speed = options.speed ?? 10;
6749
- this.loop = options.loop ?? true;
6750
- this.showFrustum = options.showFrustum ?? true;
6751
- this.trackHighlightOptions = {
6752
- enabled: true,
6753
- traveledWidth: 6,
6754
- remainingWidth: 4,
6755
- ...options.trackHighlight
6756
- };
6757
- this.initLayer();
6758
- this.parseWaylineData();
6759
- this.initVisualization();
6760
- console.log("[FlightPreviewController] \u521D\u59CB\u5316\u5B8C\u6210", {
6761
- waypointCount: this.waypoints.length,
6762
- totalDistance: this.totalDistance,
6763
- speed: this.speed
6764
- });
6765
- }
6766
- // ==================== 公共方法 ====================
6767
- /** 开始预览 */
6768
- start() {
6769
- if (this.destroyed) return;
6770
- if (this.state === "playing") return;
6771
- if (this.state === "stopped") {
6772
- this.currentDistance = 0;
6773
- }
6774
- this.setState("playing");
6775
- this.lastFrameTime = performance.now();
6776
- this.startAnimationLoop();
6777
- globalState.startFlightPreview();
6778
- this.pathPreview?.show();
6779
- console.log("[FlightPreviewController] \u5F00\u59CB\u64AD\u653E");
6780
- }
6781
- /** 暂停 */
6782
- pause() {
6783
- if (this.destroyed) return;
6784
- if (this.state !== "playing") return;
6785
- this.setState("paused");
6786
- this.stopAnimationLoop();
6787
- console.log("[FlightPreviewController] \u6682\u505C");
6788
- }
6789
- /** 继续 */
6790
- resume() {
6791
- if (this.destroyed) return;
6792
- if (this.state !== "paused") return;
6793
- this.setState("playing");
6794
- this.lastFrameTime = performance.now();
6795
- this.startAnimationLoop();
6796
- console.log("[FlightPreviewController] \u7EE7\u7EED\u64AD\u653E");
6797
- }
6798
- /** 停止并重置 */
6799
- stop() {
6800
- if (this.destroyed) return;
6801
- this.setState("stopped");
6802
- this.stopAnimationLoop();
6803
- this.currentDistance = 0;
6804
- globalState.stopFlightPreview();
6805
- this.updateVisualization();
6806
- this.pathPreview?.hide();
6807
- console.log("[FlightPreviewController] \u505C\u6B62");
6808
- }
6809
- /** 跳转到指定进度 (0-1) */
6810
- seek(progress) {
6811
- if (this.destroyed) return;
6812
- const clampedProgress = Math.max(0, Math.min(1, progress));
6813
- this.currentDistance = clampedProgress * this.totalDistance;
6814
- this.updateVisualization();
6815
- console.log("[FlightPreviewController] \u8DF3\u8F6C\u5230", (clampedProgress * 100).toFixed(1) + "%");
6816
- }
6817
- /** 设置速度 */
6818
- setSpeed(speed) {
6819
- this.speed = Math.max(1, speed);
6820
- console.log("[FlightPreviewController] \u8BBE\u7F6E\u901F\u5EA6:", this.speed, "m/s");
6821
- }
6822
- /** 获取当前状态 */
6823
- getState() {
6824
- return this.state;
6825
- }
6826
- /** 获取当前进度 (0-1) */
6827
- getProgress() {
6828
- if (this.totalDistance === 0) return 0;
6829
- return this.currentDistance / this.totalDistance;
6830
- }
6831
- /** 获取当前航点索引 */
6832
- getCurrentWaypointIndex() {
6833
- return this.findCurrentSegment().segmentIndex;
6834
- }
6835
- /** 销毁 */
6836
- destroy() {
6837
- if (this.destroyed) return;
6838
- this.destroyed = true;
6839
- this.stopAnimationLoop();
6840
- globalState.stopFlightPreview();
6841
- this.destroyVisualization();
6842
- this.onStateChange.clear();
6843
- this.onProgressChange.clear();
6844
- console.log("[FlightPreviewController] \u5DF2\u9500\u6BC1");
6845
- }
6846
- // ==================== 私有方法 - 初始化 ====================
6847
- /** 初始化图层 */
6848
- initLayer() {
6849
- const C = this.CesiumNS;
6850
- if (this.options.layer) {
6851
- this.layer = this.options.layer;
6852
- } else {
6853
- const newLayer = new C.CustomDataSource("FlightPreviewLayer");
6854
- this.layer = newLayer;
6855
- this.viewer.dataSources.add(newLayer);
6856
- }
6857
- }
6858
- /** 解析航线数据 */
6859
- parseWaylineData() {
6860
- const C = this.CesiumNS;
6861
- const { waylineData } = this.options;
6862
- const converted = convertSinoflyWayline(waylineData, { CesiumNS: this.CesiumNS });
6863
- const waypointData = converted.waypointData;
6864
- if (!waypointData || waypointData.length < 2) {
6865
- console.warn("[FlightPreviewController] \u822A\u70B9\u6570\u91CF\u4E0D\u8DB3");
6866
- return;
6867
- }
6868
- let cumulativeDistance = 0;
6869
- for (let i = 0; i < waypointData.length; i++) {
6870
- const wp = waypointData[i];
6871
- let distanceToNext = 0;
6872
- if (i < waypointData.length - 1) {
6873
- const nextWp = waypointData[i + 1];
6874
- distanceToNext = C.Cartesian3.distance(wp.position, nextWp.position);
6875
- }
6876
- this.waypoints.push({
6877
- position: wp.position,
6878
- heading: wp.heading ?? 0,
6879
- pitch: wp.pitch ?? -10,
6880
- roll: wp.roll ?? 0,
6881
- distanceToNext,
6882
- cumulativeDistance
6883
- });
6884
- cumulativeDistance += distanceToNext;
6885
- }
6886
- this.totalDistance = cumulativeDistance;
6887
- }
6888
- /** 初始化可视化组件 */
6889
- initVisualization() {
6890
- this.initDroneModel();
6891
- this.initFrustum();
6892
- this.initTrackHighlight();
6893
- this.initPathPreview();
6894
- this.updateVisualization();
6895
- }
6896
- /** 初始化无人机模型 */
6897
- initDroneModel() {
6898
- if (!this.layer || this.waypoints.length === 0) return;
6899
- const C = this.CesiumNS;
6900
- const layer = this.layer;
6901
- const modelHeadingOffset = 270;
6902
- const modelVerticalOffset = 35;
6903
- const modelForwardOffset = 5;
6904
- const modelRightOffset = -30;
6905
- this.droneEntity = layer.entities.add({
6906
- position: new C.CallbackProperty(() => {
6907
- const { position, heading, pitch } = this.getCurrentPose();
6908
- return this.applyModelOffset(position, heading, pitch, {
6909
- forward: modelForwardOffset,
6910
- right: modelRightOffset,
6911
- up: modelVerticalOffset
6912
- });
6913
- }, false),
6914
- orientation: new C.CallbackProperty(() => {
6915
- const { position, heading, pitch, roll } = this.getCurrentPose();
6916
- const hpr = new C.HeadingPitchRoll(
6917
- C.Math.toRadians(heading + modelHeadingOffset),
6918
- C.Math.toRadians(pitch),
6919
- C.Math.toRadians(roll)
6920
- );
6921
- return C.Transforms.headingPitchRollQuaternion(position, hpr);
6922
- }, false),
6923
- model: {
6924
- uri: wurenji_default,
6925
- scale: 0.5,
6926
- minimumPixelSize: 32,
6927
- maximumScale: 100,
6928
- silhouetteColor: C.Color.CYAN,
6929
- silhouetteSize: 1
6930
- },
6931
- properties: { _type: "flight-preview-drone" }
6932
- });
6933
- }
6934
- /** 应用模型偏移 */
6935
- applyModelOffset(position, heading, pitch, offset) {
6936
- const C = this.CesiumNS;
6937
- const headingRad = C.Math.toRadians(heading);
6938
- const pitchRad = C.Math.toRadians(pitch);
6939
- const enu = C.Transforms.eastNorthUpToFixedFrame(position);
6940
- const east = C.Cartesian3.fromCartesian4(C.Matrix4.getColumn(enu, 0, new C.Cartesian4()));
6941
- const north = C.Cartesian3.fromCartesian4(C.Matrix4.getColumn(enu, 1, new C.Cartesian4()));
6942
- const up = C.Cartesian3.fromCartesian4(C.Matrix4.getColumn(enu, 2, new C.Cartesian4()));
6943
- const horizForward = C.Cartesian3.add(
6944
- C.Cartesian3.multiplyByScalar(east, Math.sin(headingRad), new C.Cartesian3()),
6945
- C.Cartesian3.multiplyByScalar(north, Math.cos(headingRad), new C.Cartesian3()),
6946
- new C.Cartesian3()
6947
- );
6948
- const right = C.Cartesian3.add(
6949
- C.Cartesian3.multiplyByScalar(east, Math.cos(headingRad), new C.Cartesian3()),
6950
- C.Cartesian3.multiplyByScalar(north, -Math.sin(headingRad), new C.Cartesian3()),
6951
- new C.Cartesian3()
6952
- );
6953
- const forward = C.Cartesian3.add(
6954
- C.Cartesian3.multiplyByScalar(horizForward, Math.cos(pitchRad), new C.Cartesian3()),
6955
- C.Cartesian3.multiplyByScalar(up, Math.sin(pitchRad), new C.Cartesian3()),
6956
- new C.Cartesian3()
6957
- );
6958
- const upRotated = C.Cartesian3.add(
6959
- C.Cartesian3.multiplyByScalar(horizForward, -Math.sin(pitchRad), new C.Cartesian3()),
6960
- C.Cartesian3.multiplyByScalar(up, Math.cos(pitchRad), new C.Cartesian3()),
6961
- new C.Cartesian3()
6962
- );
6963
- let result = C.Cartesian3.clone(position);
6964
- result = C.Cartesian3.add(result, C.Cartesian3.multiplyByScalar(forward, offset.forward, new C.Cartesian3()), result);
6965
- result = C.Cartesian3.add(result, C.Cartesian3.multiplyByScalar(right, offset.right, new C.Cartesian3()), result);
6966
- result = C.Cartesian3.add(result, C.Cartesian3.multiplyByScalar(upRotated, offset.up, new C.Cartesian3()), result);
6967
- return result;
6968
- }
6969
- /** 初始化视锥体 */
6970
- initFrustum() {
6971
- if (!this.showFrustum || !this.layer) return;
6972
- const C = this.CesiumNS;
6973
- this.frustum = new FrustumPyramid(this.CesiumNS, this.layer, {
6974
- fov: 50,
6975
- length: 500,
6976
- color: C.Color.CYAN,
6977
- fillAlpha: 0.25,
6978
- width: 2
6979
- });
6980
- this.frustum.showAtDynamic(
6981
- () => this.getCurrentPose().position,
6982
- () => this.getCurrentPose().heading,
6983
- () => this.getCurrentPose().pitch,
6984
- () => this.getCurrentPose().roll,
6985
- () => 50,
6986
- () => 500
6987
- );
6988
- }
6989
- /** 初始化轨迹高亮 */
6990
- initTrackHighlight() {
6991
- if (!this.trackHighlightOptions.enabled || !this.layer) return;
6992
- if (this.waypoints.length < 2) return;
6993
- const C = this.CesiumNS;
6994
- const layer = this.layer;
6995
- const traveledColor = this.trackHighlightOptions.traveledColor ?? C.Color.fromCssColorString("#00FF88");
6996
- const remainingColor = this.trackHighlightOptions.remainingColor ?? C.Color.fromCssColorString("#4A90D9").withAlpha(0.7);
6997
- this.traveledPathEntity = layer.entities.add({
6998
- polyline: {
6999
- positions: new C.CallbackProperty(() => this.getTraveledPositions(), false),
7000
- width: this.trackHighlightOptions.traveledWidth ?? 6,
7001
- material: traveledColor,
7002
- clampToGround: false
7003
- },
7004
- properties: { _type: "flight-preview-traveled" }
7005
- });
7006
- this.remainingPathEntity = layer.entities.add({
7007
- polyline: {
7008
- positions: new C.CallbackProperty(() => this.getRemainingPositions(), false),
7009
- width: this.trackHighlightOptions.remainingWidth ?? 4,
7010
- material: remainingColor,
7011
- clampToGround: false
7012
- },
7013
- properties: { _type: "flight-preview-remaining" }
7014
- });
7015
- }
7016
- /** 初始化预览窗口 */
7017
- initPathPreview() {
7018
- this.pathPreview = new PathPreview(
7019
- this.CesiumNS,
7020
- this.viewer,
7021
- {
7022
- container: this.options.previewContainer,
7023
- fov: 50,
7024
- pitch: -10,
7025
- useGlobalEventBus: true
7026
- }
7027
- );
7028
- this.pathPreview.hide();
7029
- }
7030
- // ==================== 私有方法 - 动画循环 ====================
7031
- /** 启动动画循环 */
7032
- startAnimationLoop() {
7033
- if (this.animationFrameId) return;
7034
- const animate = (currentTime) => {
7035
- if (this.state !== "playing" || this.destroyed) {
7036
- this.animationFrameId = void 0;
7037
- return;
7038
- }
7039
- const deltaTime = this.lastFrameTime ? (currentTime - this.lastFrameTime) / 1e3 : 0;
7040
- this.lastFrameTime = currentTime;
7041
- this.currentDistance += this.speed * deltaTime;
7042
- if (this.currentDistance >= this.totalDistance) {
7043
- if (this.loop) {
7044
- this.currentDistance = this.currentDistance % this.totalDistance;
7045
- } else {
7046
- this.currentDistance = this.totalDistance;
7047
- this.setState("stopped");
7048
- this.stopAnimationLoop();
7049
- return;
7050
- }
7051
- }
7052
- this.updateVisualization();
7053
- this.animationFrameId = requestAnimationFrame(animate);
7054
- };
7055
- this.animationFrameId = requestAnimationFrame(animate);
7056
- }
7057
- /** 停止动画循环 */
7058
- stopAnimationLoop() {
7059
- if (this.animationFrameId) {
7060
- cancelAnimationFrame(this.animationFrameId);
7061
- this.animationFrameId = void 0;
7062
- }
7063
- this.lastFrameTime = void 0;
7064
- }
7065
- // ==================== 私有方法 - 路径插值 ====================
7066
- /** 查找当前所在航段 */
7067
- findCurrentSegment() {
7068
- if (this.waypoints.length === 0) {
7069
- return { segmentIndex: 0, progressInSegment: 0 };
7070
- }
7071
- for (let i = 0; i < this.waypoints.length - 1; i++) {
7072
- const wp = this.waypoints[i];
7073
- const nextWp = this.waypoints[i + 1];
7074
- if (this.currentDistance <= nextWp.cumulativeDistance) {
7075
- const segmentStart = wp.cumulativeDistance;
7076
- const segmentLength = wp.distanceToNext;
7077
- const distanceInSegment = this.currentDistance - segmentStart;
7078
- const progressInSegment = segmentLength > 0 ? distanceInSegment / segmentLength : 0;
7079
- return { segmentIndex: i, progressInSegment };
7080
- }
7081
- }
7082
- return { segmentIndex: this.waypoints.length - 2, progressInSegment: 1 };
7083
- }
7084
- /** 获取当前姿态 */
7085
- getCurrentPose() {
7086
- if (this.waypoints.length === 0) {
7087
- const C = this.CesiumNS;
7088
- return {
7089
- position: new C.Cartesian3(),
7090
- heading: 0,
7091
- pitch: -10,
7092
- roll: 0
7093
- };
7094
- }
7095
- const { segmentIndex, progressInSegment } = this.findCurrentSegment();
7096
- const wp = this.waypoints[segmentIndex];
7097
- const nextWp = this.waypoints[Math.min(segmentIndex + 1, this.waypoints.length - 1)];
7098
- const position = this.interpolatePosition(wp.position, nextWp.position, progressInSegment);
7099
- const heading = this.interpolateAngle(wp.heading, nextWp.heading, progressInSegment);
7100
- const pitch = this.lerp(wp.pitch, nextWp.pitch, progressInSegment);
7101
- const roll = this.lerp(wp.roll, nextWp.roll, progressInSegment);
7102
- return { position, heading, pitch, roll };
7103
- }
7104
- /** 位置插值 */
7105
- interpolatePosition(start, end, t) {
7106
- const C = this.CesiumNS;
7107
- return C.Cartesian3.lerp(start, end, t, new C.Cartesian3());
7108
- }
7109
- /** 角度插值(处理 0-360 环绕) */
7110
- interpolateAngle(start, end, t) {
7111
- let diff = end - start;
7112
- if (diff > 180) diff -= 360;
7113
- if (diff < -180) diff += 360;
7114
- let result = start + diff * t;
7115
- return (result % 360 + 360) % 360;
7116
- }
7117
- /** 线性插值 */
7118
- lerp(start, end, t) {
7119
- return start + (end - start) * t;
7120
- }
7121
- // ==================== 私有方法 - 轨迹高亮 ====================
7122
- /** 获取已飞过的位置数组 */
7123
- getTraveledPositions() {
7124
- if (this.waypoints.length === 0) return [];
7125
- const { segmentIndex, progressInSegment } = this.findCurrentSegment();
7126
- const currentPos = this.getCurrentPose().position;
7127
- const positions = [];
7128
- for (let i = 0; i <= segmentIndex; i++) {
7129
- positions.push(this.waypoints[i].position);
7130
- }
7131
- if (progressInSegment > 0) {
7132
- positions.push(currentPos);
7133
- }
7134
- return positions;
7135
- }
7136
- /** 获取未飞过的位置数组 */
7137
- getRemainingPositions() {
7138
- if (this.waypoints.length === 0) return [];
7139
- const { segmentIndex } = this.findCurrentSegment();
7140
- const currentPos = this.getCurrentPose().position;
7141
- const positions = [];
7142
- positions.push(currentPos);
7143
- for (let i = segmentIndex + 1; i < this.waypoints.length; i++) {
7144
- positions.push(this.waypoints[i].position);
7145
- }
7146
- return positions;
7147
- }
7148
- // ==================== 私有方法 - 更新 ====================
7149
- /** 更新可视化 */
7150
- updateVisualization() {
7151
- const pose = this.getCurrentPose();
7152
- if (this.pathPreview) {
7153
- this.pathPreview.setPose(
7154
- pose.position,
7155
- pose.heading,
7156
- pose.pitch,
7157
- pose.roll
7158
- );
7159
- }
7160
- this.viewer.scene?.requestRender?.();
7161
- const { segmentIndex } = this.findCurrentSegment();
7162
- this.onProgressChange.emit({
7163
- progress: this.getProgress(),
7164
- position: pose.position,
7165
- waypointIndex: segmentIndex,
7166
- pose: {
7167
- heading: pose.heading,
7168
- pitch: pose.pitch,
7169
- roll: pose.roll
7170
- }
7171
- });
7172
- }
7173
- /** 设置状态 */
7174
- setState(newState) {
7175
- if (this.state !== newState) {
7176
- this.state = newState;
7177
- this.onStateChange.emit({ state: newState });
7178
- }
7179
- }
7180
- /** 销毁可视化组件 */
7181
- destroyVisualization() {
7182
- const layer = this.layer;
7183
- if (this.droneEntity && layer) {
7184
- try {
7185
- layer.entities.remove(this.droneEntity);
7186
- } catch {
7187
- }
7188
- }
7189
- if (this.traveledPathEntity && layer) {
7190
- try {
7191
- layer.entities.remove(this.traveledPathEntity);
7192
- } catch {
7193
- }
7194
- }
7195
- if (this.remainingPathEntity && layer) {
7196
- try {
7197
- layer.entities.remove(this.remainingPathEntity);
7198
- } catch {
7199
- }
7200
- }
7201
- try {
7202
- this.frustum?.destroy();
7203
- } catch {
7204
- }
7205
- try {
7206
- this.pathPreview?.destroy();
7207
- } catch {
7208
- }
7209
- if (!this.options.layer && this.layer) {
7210
- try {
7211
- this.viewer.dataSources.remove(this.layer);
7212
- } catch {
7213
- }
7214
- }
7215
- this.droneEntity = void 0;
7216
- this.traveledPathEntity = void 0;
7217
- this.remainingPathEntity = void 0;
7218
- this.frustum = void 0;
7219
- this.pathPreview = void 0;
7220
- this.layer = void 0;
7221
- }
7222
- };
7223
-
7224
6730
  // src/core/CZMLPathManager.ts
7225
6731
  var _CZMLPathManager = class _CZMLPathManager {
7226
6732
  constructor(CesiumNS, viewer) {
@@ -7334,50 +6840,6 @@ var _CZMLPathManager = class _CZMLPathManager {
7334
6840
  renderFlightPathPreview(options) {
7335
6841
  return renderFlightPathPreview(this.CesiumNS, this.viewer, options);
7336
6842
  }
7337
- /**
7338
- * 开始飞行预览:飞机沿航线飞行动画
7339
- *
7340
- * 功能:
7341
- * - 飞机游标沿航线从起点飞到终点,循环播放
7342
- * - 预览窗口实时显示飞机第一人称视角
7343
- * - 轨迹高亮显示已飞过/未飞过的航段
7344
- * - 预览模式下禁止选择/编辑航线、航点
7345
- *
7346
- * @param options 飞行预览选项
7347
- * @returns 飞行预览控制器
7348
- *
7349
- * @example
7350
- * ```typescript
7351
- * const preview = pathManager.startFlightPreview({
7352
- * waylineData: myWayline,
7353
- * speed: 15, // 飞行速度 15m/s
7354
- * loop: true, // 循环播放
7355
- * trackHighlight: {
7356
- * enabled: true,
7357
- * traveledColor: Cesium.Color.fromCssColorString('#00FF88'),
7358
- * remainingColor: Cesium.Color.fromCssColorString('#4A90D9'),
7359
- * },
7360
- * });
7361
- *
7362
- * preview.start(); // 开始播放
7363
- * preview.pause(); // 暂停
7364
- * preview.resume(); // 继续
7365
- * preview.stop(); // 停止
7366
- * preview.seek(0.5); // 跳转到 50%
7367
- * preview.setSpeed(20); // 设置速度
7368
- *
7369
- * // 监听进度变化
7370
- * preview.onProgressChange.on(({ progress, waypointIndex }) => {
7371
- * console.log(`进度: ${(progress * 100).toFixed(1)}%`);
7372
- * });
7373
- *
7374
- * // 销毁
7375
- * preview.destroy();
7376
- * ```
7377
- */
7378
- startFlightPreview(options) {
7379
- return new FlightPreviewController(this.CesiumNS, this.viewer, options);
7380
- }
7381
6843
  resolveEntity(entityOrId) {
7382
6844
  return typeof entityOrId === "string" ? this.viewer.entities.getById(entityOrId) : entityOrId;
7383
6845
  }
@@ -7573,6 +7035,8 @@ var PolygonEditor = class {
7573
7035
  __publicField(this, "keydownHandler");
7574
7036
  // 保存编码前的原始名称,用于还原
7575
7037
  __publicField(this, "originalPolygonNames", /* @__PURE__ */ new Map());
7038
+ // 保存双击缩放是否被禁用的状态
7039
+ __publicField(this, "doubleClickZoomDisabled", false);
7576
7040
  }
7577
7041
  /**
7578
7042
  * 根据图层名称获取颜色配置
@@ -7847,12 +7311,62 @@ var PolygonEditor = class {
7847
7311
  }
7848
7312
  this.handler = void 0;
7849
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
+ }
7850
7363
  /**
7851
7364
  * 完成编辑/绘制的通用清理逻辑
7852
7365
  */
7853
7366
  finalizePolygonSession(layer, onComplete, entity) {
7854
7367
  this.destroyHandler();
7855
7368
  this.removeKeyboardListener();
7369
+ this.restoreDoubleClickZoom();
7856
7370
  if (entity && onComplete) {
7857
7371
  onComplete(entity);
7858
7372
  }
@@ -7895,6 +7409,7 @@ var PolygonEditor = class {
7895
7409
  }
7896
7410
  this.clearAllPolygonHighlights();
7897
7411
  this.stopInternal(layer);
7412
+ this.disableDoubleClickZoom();
7898
7413
  this.drawingPositions = [];
7899
7414
  this.drawHandles = [];
7900
7415
  this.rubberBandPoint = void 0;
@@ -8039,6 +7554,7 @@ var PolygonEditor = class {
8039
7554
  }
8040
7555
  this.destroyHandler();
8041
7556
  this.removeKeyboardListener();
7557
+ this.restoreDoubleClickZoom();
8042
7558
  }
8043
7559
  /**
8044
7560
  * 开始编辑多边形
@@ -8050,6 +7566,7 @@ var PolygonEditor = class {
8050
7566
  startEditing(polygonEntity, layer, onComplete) {
8051
7567
  const C = this.CesiumNS;
8052
7568
  this.cleanupHandles(layer);
7569
+ this.disableDoubleClickZoom();
8053
7570
  const colors = this.getColorConfig(layer.name);
8054
7571
  const line_color = colors.lineColor;
8055
7572
  const line_fina_color = colors.lineFinalColor;
@@ -9472,6 +8989,7 @@ var PolygonEditor = class {
9472
8989
  const nameStr = `circle_${(circleCount + 1).toString().padStart(2, "0")}`;
9473
8990
  this.clearAllPolygonHighlights();
9474
8991
  this.stopInternal();
8992
+ this.disableDoubleClickZoom();
9475
8993
  let centerPosition = null;
9476
8994
  let currentRadius = 0;
9477
8995
  let tempCenterPoint;
@@ -9685,6 +9203,7 @@ var PolygonEditor = class {
9685
9203
  currentRadius = 0;
9686
9204
  this.destroyHandler();
9687
9205
  this.removeKeyboardListener();
9206
+ this.restoreDoubleClickZoom();
9688
9207
  };
9689
9208
  this.handler && this.handler.setInputAction(
9690
9209
  cancelCircleDrawing,
@@ -9720,6 +9239,7 @@ var PolygonEditor = class {
9720
9239
  const line_fina_color = colors.lineFinalColor;
9721
9240
  this.clearAllPolygonHighlights();
9722
9241
  this.stopInternal();
9242
+ this.disableDoubleClickZoom();
9723
9243
  let pointCount = 0;
9724
9244
  this.handler = new C.ScreenSpaceEventHandler(this.viewer.scene.canvas);
9725
9245
  this.handler && this.handler.setInputAction(
@@ -9814,6 +9334,7 @@ var PolygonEditor = class {
9814
9334
  const stopPointDrawing = () => {
9815
9335
  this.destroyHandler();
9816
9336
  this.removeKeyboardListener();
9337
+ this.restoreDoubleClickZoom();
9817
9338
  };
9818
9339
  this.handler && this.handler.setInputAction(
9819
9340
  stopPointDrawing,