@jorgmoritz/gis-manager 0.1.27 → 0.1.28

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/index.js CHANGED
@@ -11,7 +11,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
11
11
  // package.json
12
12
  var package_default = {
13
13
  name: "@jorgmoritz/gis-manager",
14
- version: "0.1.26"};
14
+ version: "0.1.27"};
15
15
 
16
16
  // src/utils/version.ts
17
17
  var version = package_default.version;
@@ -1227,6 +1227,7 @@ var SceneManager = class {
1227
1227
  const tileset = await this.apply3Dtiles(url);
1228
1228
  if (tileset) {
1229
1229
  tileset._customId = layer_id;
1230
+ tileset._url = url;
1230
1231
  this.viewer.scene.primitives.add(tileset);
1231
1232
  console.log(`[SceneManager] \u65B0\u5EFA 3DTiles_id`, tileset._customId);
1232
1233
  }
@@ -1958,6 +1959,8 @@ var PathPreview = class {
1958
1959
  __publicField(this, "fovController");
1959
1960
  // FOV 控制器
1960
1961
  __publicField(this, "currentFOV");
1962
+ /** 已加载的 3D Tiles 实例(预览窗口独立的) */
1963
+ __publicField(this, "tilesets", /* @__PURE__ */ new Map());
1961
1964
  this.currentFOV = opts.fov ?? 50;
1962
1965
  this.ensureViewer();
1963
1966
  this.ensureFOVController();
@@ -2012,8 +2015,201 @@ var PathPreview = class {
2012
2015
  }
2013
2016
  } catch {
2014
2017
  }
2015
- v.scene;
2016
2018
  this.overlayViewer = v;
2019
+ this.syncFromMainViewer();
2020
+ this.disableUserInteraction();
2021
+ }
2022
+ /**
2023
+ * 从主 viewer 同步配置
2024
+ * 共享 Provider(安全)而非 DataSource
2025
+ */
2026
+ syncFromMainViewer() {
2027
+ if (!this.overlayViewer) return;
2028
+ this.syncImageryLayers();
2029
+ this.syncTerrainProvider();
2030
+ this.syncSceneSettings();
2031
+ this.sync3DTiles();
2032
+ }
2033
+ /**
2034
+ * 同步影像图层(共享 ImageryProvider)
2035
+ */
2036
+ syncImageryLayers() {
2037
+ const v = this.overlayViewer;
2038
+ if (!v) return;
2039
+ try {
2040
+ v.imageryLayers?.removeAll?.();
2041
+ const mainImageryLayers = this.mainViewer.imageryLayers;
2042
+ for (let i = 0; i < mainImageryLayers.length; i++) {
2043
+ const layer = mainImageryLayers.get(i);
2044
+ try {
2045
+ v.imageryLayers?.addImageryProvider?.(layer.imageryProvider);
2046
+ } catch {
2047
+ }
2048
+ }
2049
+ } catch (e) {
2050
+ console.warn("[PathPreview] Failed to sync imagery layers:", e);
2051
+ }
2052
+ }
2053
+ /**
2054
+ * 同步地形提供者(共享 TerrainProvider)
2055
+ */
2056
+ syncTerrainProvider() {
2057
+ const v = this.overlayViewer;
2058
+ if (!v) return;
2059
+ try {
2060
+ if (this.mainViewer.terrainProvider) {
2061
+ v.terrainProvider = this.mainViewer.terrainProvider;
2062
+ }
2063
+ } catch (e) {
2064
+ console.warn("[PathPreview] Failed to sync terrain provider:", e);
2065
+ }
2066
+ }
2067
+ /**
2068
+ * 同步 3D Tiles(点云、倾斜摄影等)
2069
+ * 注意:Primitive 不能直接共享,需要创建独立实例
2070
+ * 此方法查找主 viewer 中的 tileset 并尝试使用相同 URL 创建新实例
2071
+ */
2072
+ sync3DTiles() {
2073
+ const v = this.overlayViewer;
2074
+ if (!v) return;
2075
+ const C = this.CesiumNS;
2076
+ const mainPrimitives = this.mainViewer.scene.primitives;
2077
+ try {
2078
+ for (let i = 0; i < mainPrimitives.length; i++) {
2079
+ const primitive = mainPrimitives.get(i);
2080
+ if (primitive && primitive instanceof C.Cesium3DTileset) {
2081
+ const customId = primitive._customId;
2082
+ const url = primitive._url || primitive.resource?.url;
2083
+ if (url && customId && !this.tilesets.has(customId)) {
2084
+ this.add3DTiles(url, customId);
2085
+ }
2086
+ }
2087
+ }
2088
+ } catch (e) {
2089
+ console.warn("[PathPreview] Failed to sync 3DTiles:", e);
2090
+ }
2091
+ }
2092
+ /**
2093
+ * 手动添加 3D Tiles 到预览窗口
2094
+ * @param url 3D Tiles URL
2095
+ * @param id 唯一标识符
2096
+ */
2097
+ async add3DTiles(url, id) {
2098
+ const v = this.overlayViewer;
2099
+ if (!v) return void 0;
2100
+ if (this.tilesets.has(id)) {
2101
+ return this.tilesets.get(id);
2102
+ }
2103
+ const C = this.CesiumNS;
2104
+ try {
2105
+ const tileset = await C.Cesium3DTileset.fromUrl(url, {
2106
+ maximumScreenSpaceError: 16
2107
+ });
2108
+ if (tileset) {
2109
+ tileset._customId = id;
2110
+ tileset._url = url;
2111
+ v.scene.primitives.add(tileset);
2112
+ this.tilesets.set(id, tileset);
2113
+ console.log("[PathPreview] Added 3DTiles:", id);
2114
+ }
2115
+ return tileset;
2116
+ } catch (e) {
2117
+ console.warn("[PathPreview] Failed to add 3DTiles:", url, e);
2118
+ return void 0;
2119
+ }
2120
+ }
2121
+ /**
2122
+ * 移除 3D Tiles
2123
+ */
2124
+ remove3DTiles(id) {
2125
+ const v = this.overlayViewer;
2126
+ if (!v) return;
2127
+ const tileset = this.tilesets.get(id);
2128
+ if (tileset) {
2129
+ try {
2130
+ v.scene.primitives.remove(tileset);
2131
+ } catch {
2132
+ }
2133
+ this.tilesets.delete(id);
2134
+ }
2135
+ }
2136
+ /**
2137
+ * 同步场景设置(Globe、天空、雾效等)
2138
+ */
2139
+ syncSceneSettings() {
2140
+ const v = this.overlayViewer;
2141
+ if (!v) return;
2142
+ const s = v.scene;
2143
+ const mainScene = this.mainViewer.scene;
2144
+ try {
2145
+ if (s.globe && mainScene.globe) {
2146
+ s.globe.show = mainScene.globe.show;
2147
+ s.globe.enableLighting = mainScene.globe.enableLighting;
2148
+ s.globe.baseColor = mainScene.globe.baseColor;
2149
+ s.globe.showGroundAtmosphere = mainScene.globe.showGroundAtmosphere;
2150
+ s.globe.depthTestAgainstTerrain = mainScene.globe.depthTestAgainstTerrain;
2151
+ }
2152
+ if (mainScene.skyBox) {
2153
+ s.skyBox = mainScene.skyBox;
2154
+ } else {
2155
+ s.skyBox = void 0;
2156
+ }
2157
+ if (mainScene.skyAtmosphere) {
2158
+ s.skyAtmosphere.show = mainScene.skyAtmosphere.show;
2159
+ }
2160
+ if (s.fog && mainScene.fog) {
2161
+ s.fog.enabled = mainScene.fog.enabled;
2162
+ s.fog.density = mainScene.fog.density;
2163
+ }
2164
+ v.shadows = this.mainViewer.shadows;
2165
+ if (s.postProcessStages?.fxaa && mainScene.postProcessStages?.fxaa) {
2166
+ s.postProcessStages.fxaa.enabled = mainScene.postProcessStages.fxaa.enabled;
2167
+ }
2168
+ } catch (e) {
2169
+ console.warn("[PathPreview] Failed to sync scene settings:", e);
2170
+ }
2171
+ }
2172
+ /**
2173
+ * 禁用用户交互,相机仅通过 setPose() 控制
2174
+ */
2175
+ disableUserInteraction() {
2176
+ const v = this.overlayViewer;
2177
+ if (!v) return;
2178
+ const s = v.scene;
2179
+ try {
2180
+ const scc = s.screenSpaceCameraController;
2181
+ if (scc) {
2182
+ scc.enableInputs = false;
2183
+ scc.enableRotate = false;
2184
+ scc.enableTranslate = false;
2185
+ scc.enableZoom = false;
2186
+ scc.enableTilt = false;
2187
+ scc.enableLook = false;
2188
+ scc.inertiaSpin = 0;
2189
+ scc.inertiaZoom = 0;
2190
+ scc.inertiaTranslate = 0;
2191
+ }
2192
+ const canvas = s?.canvas ?? v.scene?.canvas;
2193
+ if (canvas && canvas.style) {
2194
+ canvas.style.pointerEvents = "none";
2195
+ try {
2196
+ canvas.setAttribute("tabindex", "-1");
2197
+ } catch {
2198
+ }
2199
+ }
2200
+ v.trackedEntity = void 0;
2201
+ if (v.clock) {
2202
+ v.clock.shouldAnimate = false;
2203
+ }
2204
+ } catch (e) {
2205
+ console.warn("[PathPreview] Failed to disable user interaction:", e);
2206
+ }
2207
+ }
2208
+ /**
2209
+ * 刷新同步(运行时更新)
2210
+ */
2211
+ refresh() {
2212
+ this.syncFromMainViewer();
2017
2213
  }
2018
2214
  /**
2019
2215
  * 创建 FOV 控制器
@@ -2175,30 +2371,63 @@ var PathPreview = class {
2175
2371
  this.fovController.hide();
2176
2372
  }
2177
2373
  }
2178
- // destroy(): void {
2179
- // if (this.destroyed) return;
2180
- // this.destroyed = true;
2181
- // // try {
2182
- // // if (this.footprintEntity) (this.layer.entities as any).remove(this.footprintEntity);
2183
- // // } catch {}
2184
- // this.footprintEntity = undefined;
2185
- //
2186
- // // 销毁 FOV 控制器
2187
- // try {
2188
- // this.fovController?.destroy();
2189
- // } catch {}
2190
- // this.fovController = undefined;
2191
- //
2192
- // try {
2193
- // (this.overlayViewer as any)?.destroy?.();
2194
- // } catch {}
2195
- // this.overlayViewer = undefined;
2196
- // try {
2197
- // if (this.containerEl && this.containerEl.parentElement)
2198
- // this.containerEl.parentElement.removeChild(this.containerEl);
2199
- // } catch {}
2200
- // this.containerEl = undefined;
2201
- // }
2374
+ /**
2375
+ * 显示预览窗口
2376
+ */
2377
+ show() {
2378
+ if (this.containerEl) {
2379
+ this.containerEl.style.display = "block";
2380
+ }
2381
+ }
2382
+ /**
2383
+ * 隐藏预览窗口
2384
+ */
2385
+ hide() {
2386
+ if (this.containerEl) {
2387
+ this.containerEl.style.display = "none";
2388
+ }
2389
+ }
2390
+ /**
2391
+ * 获取预览 viewer 实例
2392
+ */
2393
+ getOverlayViewer() {
2394
+ return this.overlayViewer;
2395
+ }
2396
+ /**
2397
+ * 销毁预览窗口,释放所有资源
2398
+ */
2399
+ destroy() {
2400
+ if (this.destroyed) return;
2401
+ this.destroyed = true;
2402
+ try {
2403
+ this.fovController?.destroy();
2404
+ } catch {
2405
+ }
2406
+ this.fovController = void 0;
2407
+ this.footprintEntity = void 0;
2408
+ try {
2409
+ this.tilesets.forEach((tileset) => {
2410
+ try {
2411
+ this.overlayViewer?.scene?.primitives?.remove?.(tileset);
2412
+ } catch {
2413
+ }
2414
+ });
2415
+ this.tilesets.clear();
2416
+ } catch {
2417
+ }
2418
+ try {
2419
+ this.overlayViewer?.destroy?.();
2420
+ } catch {
2421
+ }
2422
+ this.overlayViewer = void 0;
2423
+ try {
2424
+ if (this.containerEl && this.containerEl.parentElement) {
2425
+ this.containerEl.parentElement.removeChild(this.containerEl);
2426
+ }
2427
+ } catch {
2428
+ }
2429
+ this.containerEl = void 0;
2430
+ }
2202
2431
  };
2203
2432
 
2204
2433
  // src/core/path-manager/FrustumPyramid.ts
@@ -4086,6 +4315,7 @@ var PathEditingEventHandler = class {
4086
4315
  __publicField(this, "contextMenuManager");
4087
4316
  __publicField(this, "vertexDragHandler");
4088
4317
  __publicField(this, "callbacks");
4318
+ __publicField(this, "keydownListener");
4089
4319
  this.CesiumNS = options.CesiumNS;
4090
4320
  this.viewer = options.viewer;
4091
4321
  this.hiddenClimbIndex = options.hiddenClimbIndex;
@@ -4210,6 +4440,37 @@ var PathEditingEventHandler = class {
4210
4440
  }
4211
4441
  this.handleRightClick(movement);
4212
4442
  }, C.ScreenSpaceEventType.RIGHT_CLICK);
4443
+ this.keydownListener = (e) => {
4444
+ if (e.code !== "Space") return;
4445
+ const target = e.target;
4446
+ if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) {
4447
+ return;
4448
+ }
4449
+ if (this.vertexDragHandler.isDragging()) return;
4450
+ e.preventDefault();
4451
+ this.handleSpaceKeyInsert();
4452
+ };
4453
+ document.addEventListener("keydown", this.keydownListener);
4454
+ }
4455
+ /**
4456
+ * 处理空格键快捷插入航点
4457
+ * 在飞机游标当前位置,将航点添加到所有航点末尾
4458
+ */
4459
+ handleSpaceKeyInsert() {
4460
+ const airplaneCursor = this.callbacks.getAirplaneCursor?.();
4461
+ if (!airplaneCursor) {
4462
+ console.warn("[PathEditingEventHandler] \u7A7A\u683C\u952E\u63D2\u5165\uFF1A\u98DE\u673A\u6E38\u6807\u4E0D\u5B58\u5728");
4463
+ return;
4464
+ }
4465
+ const pose = airplaneCursor.getPose();
4466
+ if (!pose || !pose.position) {
4467
+ console.warn("[PathEditingEventHandler] \u7A7A\u683C\u952E\u63D2\u5165\uFF1A\u65E0\u6CD5\u83B7\u53D6\u6E38\u6807\u59FF\u6001");
4468
+ return;
4469
+ }
4470
+ const positions = this.callbacks.getPositions?.() || [];
4471
+ const insertAt = positions.length;
4472
+ console.log("[PathEditingEventHandler] \u7A7A\u683C\u952E\u5FEB\u6377\u63D2\u5165\u822A\u70B9\uFF0C\u4F4D\u7F6E\u7D22\u5F15:", insertAt);
4473
+ this.handleInsertVertex(insertAt, pose, "after");
4213
4474
  }
4214
4475
  /**
4215
4476
  * 处理右键点击事件
@@ -4224,12 +4485,13 @@ var PathEditingEventHandler = class {
4224
4485
  const entity = picked?.id;
4225
4486
  const airplaneCursor = this.callbacks.getAirplaneCursor?.();
4226
4487
  const vertexIndex = pickVertexIndex(this.viewer, movement.position, this.hiddenClimbIndex);
4488
+ const viewportPosition = this.canvasToViewportPosition(movement.position);
4227
4489
  if (typeof vertexIndex === "number") {
4228
4490
  const menuItems = this.buildVertexContextMenuItems(vertexIndex);
4229
- this.contextMenuManager.show(movement.position, menuItems);
4491
+ this.contextMenuManager.show(viewportPosition, menuItems);
4230
4492
  } else if (airplaneCursor && airplaneCursor.containsEntity(entity)) {
4231
4493
  const menuItems = this.buildAirplaneCursorContextMenuItems();
4232
- this.contextMenuManager.show(movement.position, menuItems);
4494
+ this.contextMenuManager.show(viewportPosition, menuItems);
4233
4495
  }
4234
4496
  } catch (error) {
4235
4497
  console.error("Error handling right click:", error);
@@ -4533,6 +4795,18 @@ var PathEditingEventHandler = class {
4533
4795
  return 0;
4534
4796
  }
4535
4797
  }
4798
+ /**
4799
+ * 将 canvas 坐标转换为视口坐标
4800
+ * Cesium 事件返回的坐标是相对于 canvas 的,而菜单需要相对于视口的坐标
4801
+ */
4802
+ canvasToViewportPosition(canvasPosition) {
4803
+ const canvas = this.viewer.scene.canvas;
4804
+ const rect = canvas.getBoundingClientRect();
4805
+ return {
4806
+ x: canvasPosition.x + rect.left,
4807
+ y: canvasPosition.y + rect.top
4808
+ };
4809
+ }
4536
4810
  /**
4537
4811
  * 🆕 从鼠标事件获取位置
4538
4812
  */
@@ -4558,6 +4832,10 @@ var PathEditingEventHandler = class {
4558
4832
  * 销毁事件处理器
4559
4833
  */
4560
4834
  destroy() {
4835
+ if (this.keydownListener) {
4836
+ document.removeEventListener("keydown", this.keydownListener);
4837
+ this.keydownListener = void 0;
4838
+ }
4561
4839
  try {
4562
4840
  this.vertexDragHandler.destroy();
4563
4841
  } catch {