@soonspacejs/plugin-tiles 2.14.28 → 2.14.30

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.esm.js CHANGED
@@ -1,47 +1,97 @@
1
- import c from "soonspacejs";
2
- import { TilesRenderer as g } from "3d-tiles-renderer";
3
- import { GLTFLoader as p } from "three/examples/jsm/loaders/GLTFLoader.js";
4
- import { MathUtils as h, MeshBasicMaterial as m } from "three";
5
- import { TilesFadePlugin as f, UpdateOnChangePlugin as v, QuantizedMeshPlugin as w, ImageOverlayPlugin as P, XYZTilesOverlay as T, ReorientationPlugin as C } from "3d-tiles-renderer/plugins";
6
- class L {
7
- constructor(t) {
8
- this.parser = t, this.name = "KHR_texture_basisu_patch";
9
- }
10
- loadTexture(t) {
11
- const s = this.parser, i = s.json, r = i.textures[t].source, a = i.images[r];
12
- if (!a || a.mimeType !== "image/ktx2")
1
+ import _ from "soonspacejs";
2
+ import { TilesRenderer as u } from "um-3d-tiles-renderer";
3
+ import { GLTFLoader as C } from "three/examples/jsm/loaders/GLTFLoader.js";
4
+ import { MathUtils as c, MeshBasicMaterial as R, Color as v, Box3 as I, Sphere as x, MeshStandardMaterial as N, ShaderMaterial as P } from "three";
5
+ import { TilesFadePlugin as O, UpdateOnChangePlugin as T, QuantizedMeshPlugin as M, ImageOverlayPlugin as E, XYZTilesOverlay as b, ReorientationPlugin as w, GeoJSONOverlay as k, CesiumIonOverlay as U, TMSTilesOverlay as F, UrlTemplateTilesOverlay as A, WMSTilesOverlay as G, WMTSCapabilitiesLoader as D, WMTSTilesOverlay as W, CesiumIonAuthPlugin as L } from "um-3d-tiles-renderer/plugins";
6
+ class Q {
7
+ constructor(e) {
8
+ this.parser = e, this.name = "KHR_texture_basisu_patch";
9
+ }
10
+ loadTexture(e) {
11
+ const t = this.parser, r = t.json, s = r.textures[e].source, l = r.images[s];
12
+ if (!l || l.mimeType !== "image/ktx2")
13
13
  return null;
14
- const n = s.options.ktx2Loader;
15
- if (!n)
16
- throw new Error(`${c.utils.consoleSspTitle}请使用 setModelKtx2DecoderPath 设置 ktx2 解压库路径`);
17
- return s.loadTextureImage(t, r, n);
14
+ const o = t.options.ktx2Loader;
15
+ if (!o)
16
+ throw new Error(`${_.utils.consoleSspTitle}请使用 setModelKtx2DecoderPath 设置 ktx2 解压库路径`);
17
+ return t.loadTextureImage(e, s, o);
18
18
  }
19
19
  }
20
- class M {
21
- priority = -999;
22
- processTileModel(t) {
23
- t.traverse((s) => {
24
- s.material && (s.material = new m());
20
+ class se {
21
+ constructor(e) {
22
+ this.ssp = e;
23
+ const { controls: t, viewport: r } = e;
24
+ this._tilesCamera = r.camera, t.addEventListener("transitionstart", () => {
25
+ this.cameraTransitionStart = !0, r.state.useFreq = 1;
26
+ }), t.addEventListener("rest", () => {
27
+ this.cameraTransitionStart = !1, this.needsUpdate = !0, r.state.useFreq = 60;
28
+ }), e.signals.beforeRender.add(() => {
29
+ this.needsUpdate && (this.needsUpdate = !1, e.viewport.camera.updateMatrixWorld(), this.tilesMap.forEach((i) => {
30
+ i.group.updateMatrixWorld(), i.update();
31
+ }));
32
+ }), e.signals.cameraObjectChange.add(() => {
33
+ this.tilesMap.forEach((i) => {
34
+ i.deleteCamera(this._tilesCamera), i.setCamera(e.viewport.camera), i.setResolutionFromRenderer(e.viewport.camera, e.viewport.renderer);
35
+ }), this._tilesCamera = e.viewport.camera;
25
36
  });
26
37
  }
38
+ tilesMap = /* @__PURE__ */ new Map();
39
+ needsUpdate = !0;
40
+ cameraTransitionStart = !1;
41
+ _tilesCamera;
42
+ lruCache = null;
43
+ parseQueue = null;
44
+ downloadQueue = null;
45
+ async loadTiles(e) {
46
+ if (this.tilesMap.has(e)) {
47
+ _.utils.warn(`${e} already loaded`);
48
+ return;
49
+ }
50
+ const { ssp: t, ssp: { viewport: r } } = this, i = new u(e);
51
+ this.lruCache === null ? this.lruCache = i.lruCache : i.lruCache = this.lruCache, this.parseQueue === null ? this.parseQueue = i.parseQueue : i.parseQueue = this.parseQueue, this.downloadQueue === null ? this.downloadQueue = i.downloadQueue : i.downloadQueue = this.downloadQueue;
52
+ const s = new C(i.manager);
53
+ s.register((p) => new Q(p));
54
+ const { dracoLoader: l, ktx2Loader: o, meshoptDecoder: d } = t.manager.store.modelManager.gltfLoader;
55
+ l && s.setDRACOLoader(l), o && s.setKTX2Loader(o), d && s.setMeshoptDecoder(d), i.manager.addHandler(/\.gltf$/, s), this.tilesMap.set(e, i), i.setCamera(this._tilesCamera), i.setResolutionFromRenderer(this._tilesCamera, r.renderer), i.lruCache.maxSize = 600, i.lruCache.minSize = 300, i.lruCache.unloadPercent = 0.8, t.addObject(i.group);
56
+ const S = () => {
57
+ this.cameraTransitionStart || (this.needsUpdate = !0, t.render());
58
+ };
59
+ return i.addEventListener("load-model", S), new Promise((p) => {
60
+ i.addEventListener("load-tile-set", () => {
61
+ S(), p(i);
62
+ });
63
+ });
64
+ }
65
+ removeTiles(e) {
66
+ const t = this.tilesMap.get(e);
67
+ return t ? (t.dispose(), this.tilesMap.delete(e), this.ssp.removeObject(t.group), !0) : !1;
68
+ }
27
69
  }
28
- const R = "https://sooncps.xwbuilders.com/api/ugis-dataprocess/v1/terrain/NhBLlMx3/";
29
- class E {
30
- constructor(t) {
31
- this.ssp = t, this.tiles = new g(R), this.tiles.fetchData = async (s, i) => {
32
- if (/layer\.json$/.test(s)) {
33
- const e = await fetch(s, i).then((r) => r.json());
34
- return e.metadataAvailability = -1, new Response(JSON.stringify(e));
70
+ let j = class {
71
+ priority = -999;
72
+ processTileModel(e) {
73
+ e.traverse((t) => {
74
+ t.material && (t.material = new R());
75
+ });
76
+ }
77
+ };
78
+ const J = "https://sooncps.xwbuilders.com/api/ugis-dataprocess/v1/terrain/NhBLlMx3/";
79
+ class ne {
80
+ constructor(e) {
81
+ this.ssp = e, this.tiles = new u(J), this.tiles.fetchData = async (t, r) => {
82
+ if (/layer\.json$/.test(t)) {
83
+ const i = await fetch(t, r).then((s) => s.json());
84
+ return i.metadataAvailability = -1, new Response(JSON.stringify(i));
35
85
  }
36
- return fetch(s, i);
37
- }, this.tilesFadePlugin = new f({ maximumFadeOutTiles: 200 }), this.updateOnChangePlugin = new v(), this.quantizedPlugin = new w({}), this.customMaterialPlugin = new M(), this.imageOverlayPlugin = new P({
38
- renderer: t.viewport.renderer,
86
+ return fetch(t, r);
87
+ }, this.tilesFadePlugin = new O({ maximumFadeOutTiles: 200 }), this.updateOnChangePlugin = new T(), this.quantizedPlugin = new M({}), this.customMaterialPlugin = new j(), this.imageOverlayPlugin = new E({
88
+ renderer: e.viewport.renderer,
39
89
  overlays: [
40
- new T({
90
+ new b({
41
91
  url: "https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"
42
92
  })
43
93
  ]
44
- }), this.reorientationPlugin = new C({
94
+ }), this.reorientationPlugin = new w({
45
95
  lon: 120,
46
96
  lat: 30,
47
97
  height: 0.1
@@ -70,76 +120,1372 @@ class E {
70
120
  disable() {
71
121
  this.ssp.removeObject(this.tiles.group), this.ssp.signals.beforeRender.remove(this.beforeRenderHandler);
72
122
  }
73
- invalidate(t, s, i) {
74
- const e = () => {
75
- const a = h.degToRad(s), n = h.degToRad(t);
123
+ invalidate(e, t, r) {
124
+ const i = () => {
125
+ const l = c.degToRad(t), o = c.degToRad(e);
76
126
  this.reorientationPlugin.transformLatLonHeightToOrigin(
77
- a,
78
- n,
79
- i
80
- ), this.ssp.render(), r();
81
- }, r = () => {
82
- this.tiles.removeEventListener("load-root-tileset", e), this.loedTilesSets.delete(e);
127
+ l,
128
+ o,
129
+ r
130
+ ), this.ssp.render(), s();
131
+ }, s = () => {
132
+ this.tiles.removeEventListener("load-root-tileset", i), this.loedTilesSets.delete(i);
83
133
  };
84
- return this.tiles.addEventListener("load-root-tileset", e), this.loedTilesSets.add(e), this.tiles.root && e(), r;
134
+ return this.tiles.addEventListener("load-root-tileset", i), this.loedTilesSets.add(i), this.tiles.root && i(), s;
85
135
  }
86
136
  dispose() {
87
137
  this.disable(), this.loedTilesSets.forEach(
88
- (t) => this.tiles.removeEventListener("load-root-tileset", t)
138
+ (e) => this.tiles.removeEventListener("load-root-tileset", e)
89
139
  ), this.loedTilesSets.clear(), this.tiles.removeEventListener("needs-render", this.render), this.tiles.removeEventListener("needs-update", this.render), this.tiles.dispose();
90
140
  }
91
141
  }
92
- class Q {
93
- constructor(t) {
94
- this.ssp = t;
95
- const { controls: s, viewport: i } = t;
96
- this._tilesCamera = i.camera, s.addEventListener("transitionstart", () => {
97
- this.cameraTransitionStart = !0, i.state.useFreq = 1;
98
- }), s.addEventListener("rest", () => {
99
- this.cameraTransitionStart = !1, this.needsUpdate = !0, i.state.useFreq = 60;
100
- }), t.signals.beforeRender.add(() => {
101
- this.needsUpdate && (this.needsUpdate = !1, t.viewport.camera.updateMatrixWorld(), this.tilesMap.forEach((e) => {
102
- e.group.updateMatrixWorld(), e.update();
103
- }));
104
- }), t.signals.cameraObjectChange.add(() => {
105
- this.tilesMap.forEach((e) => {
106
- e.deleteCamera(this._tilesCamera), e.setCamera(t.viewport.camera), e.setResolutionFromRenderer(t.viewport.camera, t.viewport.renderer);
107
- }), this._tilesCamera = t.viewport.camera;
142
+ class H {
143
+ // 使用较低的 priority 确保在 ImageOverlayPlugin 之后执行
144
+ // ImageOverlayPlugin 默认 priority 是 -1
145
+ priority = -10;
146
+ /** Alpha 裁剪模式 */
147
+ alphaClipMode = "alphaTest";
148
+ /**
149
+ * um-3d-tiles-renderer 插件接口:处理新加载的瓦片模型
150
+ */
151
+ processTileModel(e) {
152
+ e.traverse((t) => {
153
+ t.material && this._applyToMaterial(t.material);
154
+ });
155
+ }
156
+ /**
157
+ * 更新所有已加载模型的材质
158
+ * @param tiles TilesRenderer 实例
159
+ */
160
+ updateAllLoadedModels(e) {
161
+ e.forEachLoadedModel((t) => {
162
+ t.traverse((r) => {
163
+ r.material && this._applyToMaterial(r.material);
164
+ });
165
+ });
166
+ }
167
+ /**
168
+ * 应用配置到单个材质
169
+ */
170
+ _applyToMaterial(e) {
171
+ switch (e.alphaTest = 0, e.transparent = !1, e.alphaToCoverage = !1, this.alphaClipMode) {
172
+ case "alphaTest":
173
+ e.alphaTest = 0.01;
174
+ break;
175
+ case "transparent":
176
+ e.transparent = !0;
177
+ break;
178
+ case "alphaToCoverage":
179
+ e.alphaToCoverage = !0;
180
+ break;
181
+ }
182
+ e.needsUpdate = !0;
183
+ }
184
+ }
185
+ var a = /* @__PURE__ */ ((n) => (n.GEOJSON = "geojson", n.CESIUM_ION = "cesiumIon", n.TMS = "tms", n.XYZ = "xyz", n.WMS = "wms", n.WMTS = "wmts", n.URL_TEMPLATE = "urlTemplate", n))(a || {}), g = /* @__PURE__ */ ((n) => (n.QUANTIZED_MESH = "quantizedMesh", n.CESIUM_ION = "cesiumIon", n))(g || {});
186
+ class B {
187
+ constructor(e, t) {
188
+ this.imageOverlayPlugin = e, this.resourceManager = t;
189
+ }
190
+ /** 存储所有 overlay 实例 */
191
+ _instances = /* @__PURE__ */ new Map();
192
+ // =============== GeoJSON ===============
193
+ addGeoJSON(e) {
194
+ if (!this.imageOverlayPlugin) return null;
195
+ if (this._instances.has(e.id))
196
+ return console.warn(`OverlayManager: Overlay "${e.id}" already exists`), null;
197
+ const t = {
198
+ url: e.url,
199
+ geojson: e.geojson,
200
+ opacity: e.opacity ?? 1,
201
+ fillStyle: e.fillStyle,
202
+ strokeStyle: e.strokeStyle,
203
+ strokeWidth: e.strokeWidth
204
+ };
205
+ e.color && (t.color = new v(e.color));
206
+ const r = new k(t);
207
+ return this.imageOverlayPlugin.addOverlay(r, e.order), this._instances.set(e.id, {
208
+ id: e.id,
209
+ type: a.GEOJSON,
210
+ instance: r
211
+ }), this.resourceManager?.addOverlay({
212
+ id: e.id,
213
+ type: a.GEOJSON,
214
+ options: e
215
+ }), r;
216
+ }
217
+ updateGeoJSONColor(e, t) {
218
+ const r = this._instances.get(e);
219
+ if (!r || r.type !== a.GEOJSON) return !1;
220
+ const i = r.instance;
221
+ return i.color.set(t), i.redraw(), this.resourceManager?.updateOverlay(e, { color: t }), !0;
222
+ }
223
+ updateGeoJSONStrokeStyle(e, t) {
224
+ const r = this._instances.get(e);
225
+ if (!r || r.type !== a.GEOJSON) return !1;
226
+ const i = r.instance;
227
+ return i.strokeStyle = t, i.redraw(), this.resourceManager?.updateOverlay(e, { strokeStyle: t }), !0;
228
+ }
229
+ updateGeoJSONStrokeWidth(e, t) {
230
+ const r = this._instances.get(e);
231
+ if (!r || r.type !== a.GEOJSON) return !1;
232
+ const i = r.instance;
233
+ return i.strokeWidth = t, i.redraw(), this.resourceManager?.updateOverlay(e, { strokeWidth: t }), !0;
234
+ }
235
+ updateGeoJSONFillStyle(e, t) {
236
+ const r = this._instances.get(e);
237
+ if (!r || r.type !== a.GEOJSON) return !1;
238
+ const i = r.instance;
239
+ return i.fillStyle = t, i.redraw(), this.resourceManager?.updateOverlay(e, { fillStyle: t }), !0;
240
+ }
241
+ updateGeoJSONMode(e, t) {
242
+ const r = this._instances.get(e);
243
+ if (!r || r.type !== a.GEOJSON) return !1;
244
+ const i = r.instance;
245
+ return i.alphaInvert = !1, i.alphaMask = !1, i.fillStyle = "rgba( 255, 255, 255, 0.5 )", t === "mask" ? (i.alphaMask = !0, i.fillStyle = "white") : t === "invertMask" && (i.alphaInvert = !0, i.alphaMask = !0, i.fillStyle = "white"), i.redraw(), !0;
246
+ }
247
+ // =============== Cesium Ion ===============
248
+ addCesiumIon(e) {
249
+ if (!this.imageOverlayPlugin) return null;
250
+ if (this._instances.has(e.id))
251
+ return console.warn(`OverlayManager: Overlay "${e.id}" already exists`), null;
252
+ const t = new U({
253
+ assetId: e.assetId,
254
+ apiToken: e.apiToken,
255
+ autoRefreshToken: e.autoRefreshToken ?? !0,
256
+ color: typeof e.color == "number" ? e.color : 16777215,
257
+ opacity: e.opacity ?? 1
258
+ });
259
+ return this.imageOverlayPlugin.addOverlay(t, e.order), this._instances.set(e.id, {
260
+ id: e.id,
261
+ type: a.CESIUM_ION,
262
+ instance: t
263
+ }), this.resourceManager?.addOverlay({
264
+ id: e.id,
265
+ type: a.CESIUM_ION,
266
+ options: e
267
+ }), t;
268
+ }
269
+ // =============== TMS ===============
270
+ addTMS(e) {
271
+ if (!this.imageOverlayPlugin) return null;
272
+ if (this._instances.has(e.id))
273
+ return console.warn(`OverlayManager: Overlay "${e.id}" already exists`), null;
274
+ const t = new F({
275
+ url: e.url,
276
+ color: typeof e.color == "number" ? e.color : 16777215,
277
+ opacity: e.opacity ?? 1
278
+ });
279
+ return this.imageOverlayPlugin.addOverlay(t, e.order), this._instances.set(e.id, {
280
+ id: e.id,
281
+ type: a.TMS,
282
+ instance: t
283
+ }), this.resourceManager?.addOverlay({
284
+ id: e.id,
285
+ type: a.TMS,
286
+ options: e
287
+ }), t;
288
+ }
289
+ // =============== XYZ ===============
290
+ addXYZ(e) {
291
+ if (!this.imageOverlayPlugin) return null;
292
+ if (this._instances.has(e.id))
293
+ return console.warn(`OverlayManager: Overlay "${e.id}" already exists`), null;
294
+ const t = new b({
295
+ url: e.url,
296
+ color: typeof e.color == "number" ? e.color : 16777215,
297
+ opacity: e.opacity ?? 1
298
+ });
299
+ return this.imageOverlayPlugin.addOverlay(t, e.order), this._instances.set(e.id, {
300
+ id: e.id,
301
+ type: a.XYZ,
302
+ instance: t
303
+ }), this.resourceManager?.addOverlay({
304
+ id: e.id,
305
+ type: a.XYZ,
306
+ options: e
307
+ }), t;
308
+ }
309
+ // =============== URL Template ===============
310
+ /**
311
+ * 添加 URL 模板 Overlay
312
+ *
313
+ * 这是一个通用的瓦片加载方式,支持多种 URL 模板变量:
314
+ * - `{z}`, `{x}`, `{y}` - 标准 XYZ 坐标
315
+ * - `{s}` - 子域名轮换
316
+ * - `{reverseY}` - TMS 风格的 Y 坐标
317
+ * - 地理边界框变量等
318
+ *
319
+ * @example
320
+ * // 标准 XYZ 瓦片
321
+ * addUrlTemplate({
322
+ * id: 'osm',
323
+ * url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'
324
+ * })
325
+ *
326
+ * @example
327
+ * // 带子域名的瓦片
328
+ * addUrlTemplate({
329
+ * id: 'carto',
330
+ * url: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
331
+ * subdomains: 'abcd'
332
+ * })
333
+ *
334
+ * @example
335
+ * // ESRI 风格(y/x 顺序)
336
+ * addUrlTemplate({
337
+ * id: 'esri',
338
+ * url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'
339
+ * })
340
+ */
341
+ addUrlTemplate(e) {
342
+ if (!this.imageOverlayPlugin) return null;
343
+ if (this._instances.has(e.id))
344
+ return console.warn(`OverlayManager: Overlay "${e.id}" already exists`), null;
345
+ const t = new A({
346
+ url: e.url,
347
+ subdomains: e.subdomains,
348
+ levels: e.levels,
349
+ tileDimension: e.tileDimension,
350
+ projection: e.projection,
351
+ contentBoundingBox: e.contentBoundingBox,
352
+ customTags: e.customTags,
353
+ color: typeof e.color == "number" ? e.color : 16777215,
354
+ opacity: e.opacity ?? 1
355
+ });
356
+ return this.imageOverlayPlugin.addOverlay(t, e.order), this._instances.set(e.id, {
357
+ id: e.id,
358
+ type: a.URL_TEMPLATE,
359
+ instance: t
360
+ }), this.resourceManager?.addOverlay({
361
+ id: e.id,
362
+ type: a.URL_TEMPLATE,
363
+ options: e
364
+ }), t;
365
+ }
366
+ // =============== WMS ===============
367
+ async addWMS(e) {
368
+ if (!this.imageOverlayPlugin) return null;
369
+ if (this._instances.has(e.id))
370
+ return console.warn(`OverlayManager: Overlay "${e.id}" already exists`), null;
371
+ const t = {
372
+ layer: e.layer || "",
373
+ styles: e.styles || "",
374
+ crs: e.crs || "EPSG:4326",
375
+ format: e.format || "image/png",
376
+ tileDimension: e.tileDimension || 256
377
+ }, r = new G({
378
+ url: e.url,
379
+ layer: t.layer,
380
+ crs: t.crs,
381
+ format: t.format,
382
+ tileDimension: t.tileDimension,
383
+ styles: t.styles,
384
+ color: new v(typeof e.color == "number" ? e.color : 16777215),
385
+ opacity: e.opacity ?? 1
386
+ });
387
+ return this.imageOverlayPlugin.addOverlay(r, e.order), this._instances.set(e.id, {
388
+ id: e.id,
389
+ type: a.WMS,
390
+ instance: r
391
+ }), this.resourceManager?.addOverlay({
392
+ id: e.id,
393
+ type: a.WMS,
394
+ options: e
395
+ }), r;
396
+ }
397
+ // =============== WMTS ===============
398
+ async addWMTS(e) {
399
+ if (!this.imageOverlayPlugin) return null;
400
+ if (this._instances.has(e.id))
401
+ return console.warn(`OverlayManager: Overlay "${e.id}" already exists`), null;
402
+ const t = await new D().loadAsync(e.url), r = ["EPSG:4326", "EPSG:3857"];
403
+ let i = e.layer || "";
404
+ t.layers.find((l) => l.identifier === i) || (i = t.layers.find(
405
+ (l) => l?.tileMatrixSets?.some((o) => r.includes(o.supportedCRS))
406
+ )?.identifier || t.layers[0].identifier);
407
+ const s = new W({
408
+ capabilities: t,
409
+ layer: i,
410
+ dimensions: e.dimensions || null,
411
+ style: e.style || void 0,
412
+ tileMatrixSet: e.tileMatrixSet || null,
413
+ planar: !1,
414
+ color: new v(typeof e.color == "number" ? e.color : 16777215),
415
+ opacity: e.opacity ?? 1
416
+ });
417
+ return this.imageOverlayPlugin.addOverlay(s, e.order), this._instances.set(e.id, {
418
+ id: e.id,
419
+ type: a.WMTS,
420
+ instance: s
421
+ }), this.resourceManager?.addOverlay({
422
+ id: e.id,
423
+ type: a.WMTS,
424
+ options: e
425
+ }), s;
426
+ }
427
+ // =============== 通用方法 ===============
428
+ /**
429
+ * 移除 overlay
430
+ */
431
+ remove(e) {
432
+ const t = this._instances.get(e);
433
+ return t ? [
434
+ a.XYZ,
435
+ a.TMS,
436
+ a.WMS,
437
+ a.WMTS,
438
+ a.CESIUM_ION,
439
+ a.URL_TEMPLATE
440
+ ].includes(t.type) && (this.resourceManager?.getImageryOverlayCount() ?? this._getLocalImageryCount()) <= 1 ? (console.warn("OverlayManager: Cannot remove overlay - at least one imagery overlay must remain"), !1) : (this.imageOverlayPlugin?.deleteOverlay(t.instance), this._instances.delete(e), this.resourceManager?.removeOverlay(e), !0) : (console.warn(`OverlayManager: Overlay "${e}" not found`), !1);
441
+ }
442
+ /**
443
+ * 获取 overlay 实例
444
+ */
445
+ get(e) {
446
+ return this._instances.get(e)?.instance;
447
+ }
448
+ /**
449
+ * 检查 overlay 是否存在
450
+ */
451
+ has(e) {
452
+ return this._instances.has(e);
453
+ }
454
+ /**
455
+ * 设置 overlay 可见性
456
+ */
457
+ setVisible(e, t) {
458
+ const r = this._instances.get(e);
459
+ return r && "opacity" in r.instance ? (r.instance.opacity = t ? 1 : 0, this.resourceManager?.updateOverlay(e, { opacity: t ? 1 : 0 }), !0) : !1;
460
+ }
461
+ /**
462
+ * 设置 overlay 透明度
463
+ */
464
+ setOpacity(e, t) {
465
+ const r = this._instances.get(e);
466
+ return r && "opacity" in r.instance ? (r.instance.opacity = t, this.resourceManager?.updateOverlay(e, { opacity: t }), r.instance.redraw?.(), !0) : !1;
467
+ }
468
+ /**
469
+ * 设置 overlay 层级
470
+ */
471
+ setOrder(e, t) {
472
+ if (!this.imageOverlayPlugin) return !1;
473
+ const r = this._instances.get(e);
474
+ return r ? (this.imageOverlayPlugin.setOverlayOrder(r.instance, t), this.resourceManager?.updateOverlay(e, { order: t }), !0) : !1;
475
+ }
476
+ /**
477
+ * 获取 overlay 层级
478
+ */
479
+ getOrder(e) {
480
+ if (!this.imageOverlayPlugin) return -1;
481
+ const t = this._instances.get(e);
482
+ return t ? this.imageOverlayPlugin.overlayInfo.get(t.instance)?.order ?? -1 : -1;
483
+ }
484
+ /**
485
+ * 将 overlay 移到最顶层
486
+ */
487
+ bringToFront(e) {
488
+ if (!this.imageOverlayPlugin) return !1;
489
+ const t = this._instances.get(e);
490
+ if (!t) return !1;
491
+ const r = this.imageOverlayPlugin.overlayInfo;
492
+ let i = 0;
493
+ return r.forEach((s) => {
494
+ s.order > i && (i = s.order);
495
+ }), this.imageOverlayPlugin.setOverlayOrder(t.instance, i + 1), this.resourceManager?.updateOverlay(e, { order: i + 1 }), !0;
496
+ }
497
+ /**
498
+ * 将 overlay 移到最底层
499
+ */
500
+ sendToBack(e) {
501
+ if (!this.imageOverlayPlugin) return !1;
502
+ const t = this._instances.get(e);
503
+ if (!t) return !1;
504
+ const r = this.imageOverlayPlugin.overlayInfo;
505
+ let i = 1 / 0;
506
+ return r.forEach((s) => {
507
+ s.order < i && (i = s.order);
508
+ }), this.imageOverlayPlugin.setOverlayOrder(t.instance, i - 1), this.resourceManager?.updateOverlay(e, { order: i - 1 }), !0;
509
+ }
510
+ // =============== 资源恢复 ===============
511
+ /**
512
+ * 从 ResourceManager 恢复所有资源
513
+ */
514
+ restoreFromResourceManager() {
515
+ if (!this.resourceManager) return;
516
+ const e = this.resourceManager.getAllOverlays();
517
+ for (const t of e)
518
+ this._createOverlayFromResource(t);
519
+ }
520
+ /**
521
+ * 根据资源配置创建 overlay(不保存到 ResourceManager)
522
+ */
523
+ _createOverlayFromResource(e) {
524
+ const t = this.resourceManager;
525
+ switch (this.resourceManager = void 0, e.type) {
526
+ case a.GEOJSON:
527
+ this.addGeoJSON(e.options);
528
+ break;
529
+ case a.CESIUM_ION:
530
+ this.addCesiumIon(e.options);
531
+ break;
532
+ case a.TMS:
533
+ this.addTMS(e.options);
534
+ break;
535
+ case a.XYZ:
536
+ this.addXYZ(e.options);
537
+ break;
538
+ case a.WMS:
539
+ this.addWMS(e.options);
540
+ break;
541
+ case a.WMTS:
542
+ this.addWMTS(e.options);
543
+ break;
544
+ case a.URL_TEMPLATE:
545
+ this.addUrlTemplate(e.options);
546
+ break;
547
+ }
548
+ this.resourceManager = t;
549
+ }
550
+ // =============== 生命周期 ===============
551
+ /**
552
+ * 获取所有 overlay ID
553
+ */
554
+ getIds() {
555
+ return Array.from(this._instances.keys());
556
+ }
557
+ /**
558
+ * 获取 overlay 数量
559
+ */
560
+ get count() {
561
+ return this._instances.size;
562
+ }
563
+ /**
564
+ * 获取本地影像数量(不依赖 ResourceManager)
565
+ */
566
+ _getLocalImageryCount() {
567
+ let e = 0;
568
+ return this._instances.forEach((t) => {
569
+ [a.XYZ, a.TMS, a.WMS, a.WMTS, a.CESIUM_ION, a.URL_TEMPLATE].includes(t.type) && e++;
570
+ }), e;
571
+ }
572
+ /**
573
+ * 只清理实例(保留 ResourceManager 中的配置)
574
+ */
575
+ disposeInstances() {
576
+ this._instances.forEach((e) => {
577
+ this.imageOverlayPlugin?.deleteOverlay(e.instance);
578
+ }), this._instances.clear();
579
+ }
580
+ /**
581
+ * 完全销毁(清理实例和配置)
582
+ */
583
+ dispose() {
584
+ this.disposeInstances(), this.resourceManager?.clear();
585
+ }
586
+ }
587
+ class z {
588
+ /** Overlay 资源配置 */
589
+ _overlays = /* @__PURE__ */ new Map();
590
+ // =============== Overlay 资源管理 ===============
591
+ /**
592
+ * 添加 Overlay 资源配置
593
+ */
594
+ addOverlay(e) {
595
+ this._overlays.has(e.id) && console.warn(`ResourceManager: Overlay "${e.id}" already exists, will be overwritten.`), this._overlays.set(e.id, { ...e });
596
+ }
597
+ /**
598
+ * 获取 Overlay 资源配置
599
+ */
600
+ getOverlay(e) {
601
+ return this._overlays.get(e);
602
+ }
603
+ /**
604
+ * 移除 Overlay 资源配置
605
+ */
606
+ removeOverlay(e) {
607
+ return this._overlays.delete(e);
608
+ }
609
+ /**
610
+ * 检查 Overlay 是否存在
611
+ */
612
+ hasOverlay(e) {
613
+ return this._overlays.has(e);
614
+ }
615
+ /**
616
+ * 获取所有 Overlay 资源配置
617
+ */
618
+ getAllOverlays() {
619
+ return Array.from(this._overlays.values());
620
+ }
621
+ /**
622
+ * 获取指定类型的 Overlay 资源配置
623
+ */
624
+ getOverlaysByType(e) {
625
+ return this.getAllOverlays().filter((t) => t.type === e);
626
+ }
627
+ /**
628
+ * 获取所有 Overlay 的 ID 列表
629
+ */
630
+ getOverlayIds() {
631
+ return Array.from(this._overlays.keys());
632
+ }
633
+ /**
634
+ * 获取 Overlay 数量
635
+ */
636
+ get overlayCount() {
637
+ return this._overlays.size;
638
+ }
639
+ /**
640
+ * 获取影像类型的 Overlay 数量
641
+ */
642
+ getImageryOverlayCount() {
643
+ let e = 0;
644
+ return this._overlays.forEach((t) => {
645
+ (t.type === a.XYZ || t.type === a.TMS || t.type === a.WMS || t.type === a.WMTS || t.type === a.CESIUM_ION || t.type === a.URL_TEMPLATE) && e++;
646
+ }), e;
647
+ }
648
+ /**
649
+ * 更新 Overlay 配置
650
+ */
651
+ updateOverlay(e, t) {
652
+ const r = this._overlays.get(e);
653
+ return r ? (r.options = { ...r.options, ...t }, !0) : !1;
654
+ }
655
+ // =============== 工具方法 ===============
656
+ /**
657
+ * 清空所有资源配置
658
+ */
659
+ clear() {
660
+ this._overlays.clear();
661
+ }
662
+ /**
663
+ * 导出所有资源配置(用于调试或持久化)
664
+ */
665
+ export() {
666
+ return {
667
+ overlays: this.getAllOverlays()
668
+ };
669
+ }
670
+ /**
671
+ * 导入资源配置
672
+ */
673
+ import(e) {
674
+ e.overlays && (this._overlays.clear(), e.overlays.forEach((t) => this._overlays.set(t.id, { ...t })));
675
+ }
676
+ }
677
+ class $ {
678
+ /** 地形配置映射表 */
679
+ _terrains = /* @__PURE__ */ new Map();
680
+ /** 当前激活的地形 ID */
681
+ _currentId = null;
682
+ /**
683
+ * 获取当前激活的地形 ID
684
+ */
685
+ get currentId() {
686
+ return this._currentId;
687
+ }
688
+ /**
689
+ * 获取已注册的地形数量
690
+ */
691
+ get count() {
692
+ return this._terrains.size;
693
+ }
694
+ /**
695
+ * 添加地形配置
696
+ */
697
+ add(e) {
698
+ this._terrains.has(e.id) && console.warn(`TerrainManager: Terrain "${e.id}" already exists, will be overwritten.`), this._terrains.set(e.id, { ...e });
699
+ }
700
+ /**
701
+ * 移除地形配置
702
+ */
703
+ remove(e) {
704
+ return this._terrains.has(e) ? (this._currentId === e && (this._currentId = null), this._terrains.delete(e)) : !1;
705
+ }
706
+ /**
707
+ * 设置当前激活的地形 ID
708
+ */
709
+ setCurrentId(e) {
710
+ this._currentId = e;
711
+ }
712
+ /**
713
+ * 检查地形是否已注册
714
+ */
715
+ has(e) {
716
+ return this._terrains.has(e);
717
+ }
718
+ /**
719
+ * 获取指定地形配置
720
+ */
721
+ get(e) {
722
+ return this._terrains.get(e);
723
+ }
724
+ /**
725
+ * 获取当前激活的地形配置
726
+ */
727
+ getCurrent() {
728
+ if (this._currentId)
729
+ return this._terrains.get(this._currentId);
730
+ }
731
+ /**
732
+ * 获取所有地形配置列表(用于前端列表渲染)
733
+ */
734
+ getList() {
735
+ return Array.from(this._terrains.values()).map((e) => ({
736
+ id: e.id,
737
+ config: e,
738
+ active: e.id === this._currentId
739
+ }));
740
+ }
741
+ /**
742
+ * 获取所有地形配置
743
+ */
744
+ getAll() {
745
+ return Array.from(this._terrains.values());
746
+ }
747
+ /**
748
+ * 获取所有地形 ID
749
+ */
750
+ getIds() {
751
+ return Array.from(this._terrains.keys());
752
+ }
753
+ /**
754
+ * 清空所有地形配置
755
+ */
756
+ clear() {
757
+ this._terrains.clear(), this._currentId = null;
758
+ }
759
+ /**
760
+ * 销毁管理器
761
+ */
762
+ dispose() {
763
+ this.clear();
764
+ }
765
+ }
766
+ const Z = "https://sooncps.xwbuilders.com/api/ugis-dataprocess/v1/terrain/NhBLlMx3/", X = "https://c.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png";
767
+ class le {
768
+ constructor(e, t = {}) {
769
+ this.ssp = e, this.options = t;
770
+ const r = t.baseUrl || Z;
771
+ if (this.resourceManager = new z(), this.terrainManager = new $(), t.imageryUrl !== !1) {
772
+ const i = t.imageryUrl || X;
773
+ this.resourceManager.addOverlay({
774
+ id: this.defaultImageryId,
775
+ type: a.XYZ,
776
+ options: { id: this.defaultImageryId, url: i }
777
+ });
778
+ }
779
+ this._alphaClipMode = t.alphaClipMode ?? "alphaTest", this._currentTerrainConfig = {
780
+ id: this.defaultTerrainId,
781
+ type: g.QUANTIZED_MESH,
782
+ url: r
783
+ }, this.terrainManager.add(this._currentTerrainConfig), this.terrainManager.setCurrentId(this._currentTerrainConfig.id), this.tiles = this._initTilesRenderer(this._currentTerrainConfig), this._initPlugins(this.tiles, this._currentTerrainConfig);
784
+ }
785
+ defaultTerrainId = "__default_terrain__";
786
+ defaultImageryId = "__default_imagery__";
787
+ tiles;
788
+ tilesFadePlugin;
789
+ updateOnChangePlugin;
790
+ customMaterialPlugin;
791
+ imageOverlayPlugin;
792
+ reorientationPlugin;
793
+ /** 资源管理器(存储配置) */
794
+ resourceManager;
795
+ /** 地形管理器(记录地形列表) */
796
+ terrainManager;
797
+ /** Overlay 管理器(管理实例) */
798
+ overlayManager;
799
+ /** 当前地形配置 */
800
+ _currentTerrainConfig;
801
+ /** Alpha 裁剪模式 */
802
+ _alphaClipMode = "alphaTest";
803
+ /** 是否已启用(添加到场景) */
804
+ _enabled = !1;
805
+ loedTilesSets = /* @__PURE__ */ new Set();
806
+ options;
807
+ /**
808
+ * 是否使用 Cesium Ion 地形
809
+ */
810
+ get isCesiumIon() {
811
+ return this._currentTerrainConfig.type === g.CESIUM_ION;
812
+ }
813
+ /**
814
+ * 获取当前地形配置
815
+ */
816
+ get currentTerrainConfig() {
817
+ return this._currentTerrainConfig;
818
+ }
819
+ /**
820
+ * 获取/设置最大深度(GUI 可控)
821
+ */
822
+ get maxDepth() {
823
+ return this.tiles.maxDepth;
824
+ }
825
+ set maxDepth(e) {
826
+ this.tiles.maxDepth = e, this.render();
827
+ }
828
+ /**
829
+ * 获取/设置误差目标(GUI 可控)
830
+ */
831
+ get errorTarget() {
832
+ return this.tiles.errorTarget;
833
+ }
834
+ set errorTarget(e) {
835
+ this.tiles.errorTarget = e, this.render();
836
+ }
837
+ /**
838
+ * 获取/设置地形显示状态(GUI 可控)
839
+ */
840
+ get showTerrain() {
841
+ return this.tiles.group.visible;
842
+ }
843
+ set showTerrain(e) {
844
+ this.tiles.group.visible = e, this.render();
845
+ }
846
+ /**
847
+ * 获取/设置 Alpha 裁剪模式(GUI 可控)
848
+ * - 用于支持 GeoJSON mask 功能
849
+ */
850
+ get alphaClipMode() {
851
+ return this._alphaClipMode;
852
+ }
853
+ set alphaClipMode(e) {
854
+ this._alphaClipMode = e, this.customMaterialPlugin && (this.customMaterialPlugin.alphaClipMode = e), this._updateAlphaClipMode(), this.render();
855
+ }
856
+ _initTilesRenderer(e) {
857
+ return e.type === g.CESIUM_ION ? new u() : (
858
+ // Cesium Ion 由插件设置 URL
859
+ new u(e.url)
860
+ );
861
+ }
862
+ /**
863
+ * 创建 TilesRenderer(统一方法,支持自定义地形和 Cesium Ion 地形)
864
+ * @param config 地形配置
865
+ */
866
+ _initPlugins(e, t) {
867
+ if (this.tilesFadePlugin = new O({ maximumFadeOutTiles: 200 }), this.updateOnChangePlugin = new T(), e.registerPlugin(this.tilesFadePlugin), e.registerPlugin(this.updateOnChangePlugin), t.type === g.CESIUM_ION ? e.registerPlugin(new L({
868
+ apiToken: t.apiToken,
869
+ assetId: t.assetId || "1",
870
+ autoRefreshToken: t.autoRefreshToken ?? !0,
871
+ assetTypeHandler: (r, i) => {
872
+ r === "TERRAIN" && i.getPluginByName("QUANTIZED_MESH_PLUGIN") === null && i.registerPlugin(new M({ useRecommendedSettings: !0 }));
873
+ }
874
+ })) : (e.registerPlugin(new M({ useRecommendedSettings: !0 })), e.fetchData = async (r) => {
875
+ const i = { method: "GET", mode: "cors" };
876
+ if (/layer\.json$/.test(r)) {
877
+ const s = await fetch(r, i).then((l) => l.json());
878
+ return s.metadataAvailability = -1, new Response(JSON.stringify(s));
879
+ }
880
+ return fetch(r, i);
881
+ }), this.options.useCustomMaterial !== !1 && (this.customMaterialPlugin = new H(), this.customMaterialPlugin.alphaClipMode = this._alphaClipMode, e.registerPlugin(this.customMaterialPlugin)), this.imageOverlayPlugin = new E({
882
+ renderer: this.ssp.viewport.renderer,
883
+ overlays: []
884
+ }), e.registerPlugin(this.imageOverlayPlugin), this.overlayManager = new B(this.imageOverlayPlugin, this.resourceManager), this.overlayManager.restoreFromResourceManager(), this.options.reorientation !== !1) {
885
+ const r = this.options.reorientation || { lon: 120, lat: 30 };
886
+ this.reorientationPlugin = new w({
887
+ lon: r.lon,
888
+ lat: r.lat,
889
+ height: r.height ?? 0.1
890
+ }), e.registerPlugin(this.reorientationPlugin), this.invalidate(r.lon, r.lat, r.height ?? 0.1);
891
+ }
892
+ e.maxDepth = this.options.maxDepth ?? 20, e.errorTarget = this.options.errorTarget ?? 1, e.addEventListener("needs-render", this.render), e.addEventListener("needs-update", this.render);
893
+ }
894
+ /**
895
+ * 销毁当前 tiles 实例
896
+ */
897
+ _disposeTilesRenderer() {
898
+ const e = this.tiles;
899
+ this._enabled && this.ssp.removeObject(e.group), e.removeEventListener("needs-render", this.render), e.removeEventListener("needs-update", this.render), this.overlayManager.disposeInstances(), e.dispose();
900
+ }
901
+ /**
902
+ * 更新所有已加载模型的 alpha 裁剪模式
903
+ */
904
+ _updateAlphaClipMode() {
905
+ this.customMaterialPlugin && this.customMaterialPlugin.updateAllLoadedModels(this.tiles);
906
+ }
907
+ // =============== 地形管理 API ===============
908
+ /**
909
+ * 设置地形
910
+ * 会创建新的 TilesRenderer 实例以避免状态残留问题
911
+ * @param config 地形配置
912
+ * @example
913
+ * // 设置量化网格地形
914
+ * tilesRenderer.setTerrain({
915
+ * type: TerrainType.QUANTIZED_MESH,
916
+ * url: 'https://terrain.example.com/'
917
+ * })
918
+ *
919
+ * // 设置 Cesium Ion 地形
920
+ * tilesRenderer.setTerrain({
921
+ * type: TerrainType.CESIUM_ION,
922
+ * apiToken: 'your-token',
923
+ * assetId: '1'
924
+ * })
925
+ */
926
+ setTerrain(e, t = void 0) {
927
+ e.id !== this._currentTerrainConfig.id && (t && (this.options = { ...this.options, ...t }), this.terrainManager.has(e.id) || this.terrainManager.add(e), this.terrainManager.setCurrentId(e.id), this._disposeTilesRenderer(), this._currentTerrainConfig = e, this.tiles = this._initTilesRenderer(e), this._initPlugins(this.tiles, e), this._enabled && this.ssp.addObject(this.tiles.group), this.render());
928
+ }
929
+ // =============== Overlay 快捷方法 ===============
930
+ /**
931
+ * 添加 GeoJSON Overlay
932
+ * @example
933
+ * tilesRenderer.addGeoJSON({
934
+ * id: 'china-boundary',
935
+ * url: './data/china.geojson',
936
+ * color: '#ff0000',
937
+ * opacity: 0.8
938
+ * })
939
+ */
940
+ addGeoJSON(e) {
941
+ return this.overlayManager.addGeoJSON(e);
942
+ }
943
+ /**
944
+ * 添加 Cesium Ion Overlay
945
+ */
946
+ addCesiumIonOverlay(e) {
947
+ return this.overlayManager.addCesiumIon(e);
948
+ }
949
+ /**
950
+ * 添加 TMS Tiles Overlay
951
+ */
952
+ addTMSOverlay(e) {
953
+ return this.overlayManager.addTMS(e);
954
+ }
955
+ /**
956
+ * 添加 XYZ Tiles Overlay
957
+ */
958
+ addXYZOverlay(e) {
959
+ return this.overlayManager.addXYZ(e);
960
+ }
961
+ /**
962
+ * 添加 URL Template Overlay
963
+ *
964
+ * 支持多种 URL 模板变量:
965
+ * - `{z}`, `{x}`, `{y}` - 标准 XYZ 坐标
966
+ * - `{s}` - 子域名轮换
967
+ * - `{reverseY}` - TMS 风格的 Y 坐标
968
+ * - `{westDegrees}`, `{southDegrees}`, `{eastDegrees}`, `{northDegrees}` - 地理边界框
969
+ *
970
+ * @example
971
+ * tilesPlugin.addUrlTemplateOverlay({
972
+ * id: 'osm',
973
+ * url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'
974
+ * })
975
+ *
976
+ * @example
977
+ * tilesPlugin.addUrlTemplateOverlay({
978
+ * id: 'carto',
979
+ * url: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
980
+ * subdomains: 'abcd'
981
+ * })
982
+ */
983
+ addUrlTemplateOverlay(e) {
984
+ return this.overlayManager.addUrlTemplate(e);
985
+ }
986
+ /**
987
+ * 添加 WMS Tiles Overlay
988
+ */
989
+ addWMSOverlay(e) {
990
+ return this.overlayManager.addWMS(e);
991
+ }
992
+ /**
993
+ * 添加 WMTS Tiles Overlay
994
+ */
995
+ addWMTSOverlay(e) {
996
+ return this.overlayManager.addWMTS(e);
997
+ }
998
+ /**
999
+ * 移除指定 overlay
1000
+ */
1001
+ removeOverlay(e) {
1002
+ return this.overlayManager.remove(e);
1003
+ }
1004
+ /**
1005
+ * 更新 GeoJSON 颜色
1006
+ */
1007
+ updateGeoJSONColor(e, t) {
1008
+ const r = this.overlayManager.updateGeoJSONColor(e, t);
1009
+ return r && this.render(), r;
1010
+ }
1011
+ /**
1012
+ * 更新 GeoJSON 模式
1013
+ * - overlay: 普通叠加显示
1014
+ * - mask: 只显示 GeoJSON 区域内的地形
1015
+ * - invertMask: 只显示 GeoJSON 区域外的地形
1016
+ */
1017
+ updateGeoJSONMode(e, t) {
1018
+ const r = this.overlayManager.updateGeoJSONMode(e, t);
1019
+ return r && this.render(), r;
1020
+ }
1021
+ /**
1022
+ * 更新 GeoJSON 描边样式
1023
+ */
1024
+ updateGeoJSONStrokeStyle(e, t) {
1025
+ const r = this.overlayManager.updateGeoJSONStrokeStyle(e, t);
1026
+ return r && this.render(), r;
1027
+ }
1028
+ /**
1029
+ * 更新 GeoJSON 描边宽度
1030
+ */
1031
+ updateGeoJSONStrokeWidth(e, t) {
1032
+ const r = this.overlayManager.updateGeoJSONStrokeWidth(e, t);
1033
+ return r && this.render(), r;
1034
+ }
1035
+ /**
1036
+ * 更新 GeoJSON 填充样式
1037
+ */
1038
+ updateGeoJSONFillStyle(e, t) {
1039
+ const r = this.overlayManager.updateGeoJSONFillStyle(e, t);
1040
+ return r && this.render(), r;
1041
+ }
1042
+ // =============== Overlay 层级控制 ===============
1043
+ /**
1044
+ * 设置 overlay 层级顺序
1045
+ * @param id overlay ID
1046
+ * @param order 层级顺序,数值越大越靠上
1047
+ * @example
1048
+ * tilesRenderer.setOverlayOrder('china-boundary', 10)
1049
+ */
1050
+ setOverlayOrder(e, t) {
1051
+ return this.overlayManager.setOrder(e, t);
1052
+ }
1053
+ /**
1054
+ * 获取 overlay 当前的层级顺序
1055
+ * @param id overlay ID
1056
+ */
1057
+ getOverlayOrder(e) {
1058
+ return this.overlayManager.getOrder(e);
1059
+ }
1060
+ /**
1061
+ * 将 overlay 移动到最顶层
1062
+ */
1063
+ bringOverlayToFront(e) {
1064
+ return this.overlayManager.bringToFront(e);
1065
+ }
1066
+ /**
1067
+ * 将 overlay 移动到最底层
1068
+ */
1069
+ sendOverlayToBack(e) {
1070
+ return this.overlayManager.sendToBack(e);
1071
+ }
1072
+ /**
1073
+ * 设置 overlay 可见性
1074
+ */
1075
+ setOverlayVisible(e, t) {
1076
+ const r = this.overlayManager.setVisible(e, t);
1077
+ return r && this.render(), r;
1078
+ }
1079
+ /**
1080
+ * 设置 overlay 透明度
1081
+ */
1082
+ setOverlayOpacity(e, t) {
1083
+ const r = this.overlayManager.setOpacity(e, t);
1084
+ return r && this.render(), r;
1085
+ }
1086
+ // =============== 生命周期 ===============
1087
+ render = () => {
1088
+ this.ssp.render();
1089
+ };
1090
+ beforeRenderHandler = () => {
1091
+ this.ssp.viewport.camera.updateMatrixWorld(), this.tiles.setCamera(this.ssp.viewport.camera), this.tiles.setResolutionFromRenderer(
1092
+ this.ssp.viewport.camera,
1093
+ this.ssp.viewport.renderer
1094
+ ), this.tiles.update();
1095
+ };
1096
+ enable() {
1097
+ this._enabled = !0, this.ssp.addObject(this.tiles.group), this.ssp.signals.beforeRender.add(this.beforeRenderHandler);
1098
+ }
1099
+ disable() {
1100
+ this._enabled = !1, this.ssp.removeObject(this.tiles.group), this.ssp.signals.beforeRender.remove(this.beforeRenderHandler);
1101
+ }
1102
+ invalidate(e, t, r) {
1103
+ if (!this.reorientationPlugin)
1104
+ return console.warn("TilesRenderer: reorientationPlugin is not enabled, invalidate() will not work."), () => {
1105
+ };
1106
+ const i = this.reorientationPlugin;
1107
+ this.options.reorientation = {
1108
+ lon: e,
1109
+ lat: t,
1110
+ height: r
1111
+ };
1112
+ const s = () => {
1113
+ const o = c.degToRad(t), d = c.degToRad(e);
1114
+ i.transformLatLonHeightToOrigin(
1115
+ o,
1116
+ d,
1117
+ r
1118
+ ), this.render(), l();
1119
+ }, l = () => {
1120
+ this.tiles.removeEventListener("load-root-tileset", s), this.loedTilesSets.delete(s);
1121
+ };
1122
+ return this.tiles.addEventListener("load-root-tileset", s), this.loedTilesSets.add(s), this.tiles.root && s(), l;
1123
+ }
1124
+ dispose() {
1125
+ this.disable(), this.terrainManager.dispose(), this.overlayManager.dispose(), this.loedTilesSets.forEach(
1126
+ (e) => this.tiles.removeEventListener("load-root-tileset", e)
1127
+ ), this.loedTilesSets.clear(), this.tiles.removeEventListener("needs-render", this.render), this.tiles.removeEventListener("needs-update", this.render), this.tiles.dispose();
1128
+ }
1129
+ }
1130
+ const h = {
1131
+ DEFAULT: 0,
1132
+ GRADIENT: 1,
1133
+ TOPOGRAPHIC_LINES: 2,
1134
+ LIGHTING: 3
1135
+ }, Y = {
1136
+ vertexShader: (
1137
+ /* glsl */
1138
+ `
1139
+ varying vec3 wPosition;
1140
+ void main() {
1141
+ #include <begin_vertex>
1142
+ #include <project_vertex>
1143
+ wPosition = ( modelMatrix * vec4( transformed, 1.0 ) ).xyz;
1144
+ }
1145
+ `
1146
+ ),
1147
+ fragmentShader: (
1148
+ /* glsl */
1149
+ `
1150
+ varying vec3 wPosition;
1151
+ void main() {
1152
+ float minVal = - 30.0;
1153
+ float maxVal = 30.0;
1154
+ float val = ( wPosition.y - minVal ) / ( maxVal - minVal );
1155
+ vec4 color1 = vec4( 0.149, 0.196, 0.219, 1.0 ) * 0.5;
1156
+ vec4 color2 = vec4( 1.0 );
1157
+ gl_FragColor = mix( color1, color2, val );
1158
+ }
1159
+ `
1160
+ )
1161
+ }, V = {
1162
+ vertexShader: (
1163
+ /* glsl */
1164
+ `
1165
+ varying vec3 wPosition;
1166
+ varying vec3 vViewPosition;
1167
+ void main() {
1168
+ #include <begin_vertex>
1169
+ #include <project_vertex>
1170
+ wPosition = ( modelMatrix * vec4( transformed, 1.0 ) ).xyz;
1171
+ vViewPosition = - mvPosition.xyz;
1172
+ }
1173
+ `
1174
+ ),
1175
+ fragmentShader: (
1176
+ /* glsl */
1177
+ `
1178
+ varying vec3 wPosition;
1179
+ varying vec3 vViewPosition;
1180
+ void main() {
1181
+ // lighting
1182
+ vec3 fdx = vec3( dFdx( wPosition.x ), dFdx( wPosition.y ), dFdx( wPosition.z ) );
1183
+ vec3 fdy = vec3( dFdy( wPosition.x ), dFdy( wPosition.y ), dFdy( wPosition.z ) );
1184
+ vec3 worldNormal = normalize( cross( fdx, fdy ) );
1185
+ float lighting =
1186
+ 0.4 +
1187
+ clamp( dot( worldNormal, vec3( 1.0, 1.0, 1.0 ) ), 0.0, 1.0 ) * 0.5 +
1188
+ clamp( dot( worldNormal, vec3( - 1.0, 1.0, - 1.0 ) ), 0.0, 1.0 ) * 0.3;
1189
+ // thickness scale
1190
+ float upwardness = dot( worldNormal, vec3( 0.0, 1.0, 0.0 ) );
1191
+ float yInv = clamp( 1.0 - abs( upwardness ), 0.0, 1.0 );
1192
+ float thicknessScale = pow( yInv, 0.4 );
1193
+ thicknessScale *= 0.25 + 0.5 * ( vViewPosition.z + 1.0 ) / 2.0;
1194
+ // thickness
1195
+ float thickness = 0.01 * thicknessScale;
1196
+ float thickness2 = thickness / 2.0;
1197
+ float m = mod( wPosition.y, 3.0 );
1198
+ // soften edge
1199
+ float center = thickness2;
1200
+ float dist = clamp( abs( m - thickness2 ) / thickness2, 0.0, 1.0 );
1201
+ vec4 topoColor = vec4( 0.149, 0.196, 0.219, 1.0 ) * 0.5;
1202
+ gl_FragColor = mix( topoColor * lighting, vec4( lighting ), dist );
1203
+ }
1204
+ `
1205
+ )
1206
+ };
1207
+ let m = null, y = null, f = null;
1208
+ class q {
1209
+ constructor(e, t) {
1210
+ this.ssp = e, this.options = t, "url" in this.options ? this.tiles = new u(this.options.url) : (this.tiles = new u(), this._initCesiumIon(this.options)), this._initBasePlugins(this.options);
1211
+ }
1212
+ tiles;
1213
+ tilesFadePlugin;
1214
+ updateOnChangePlugin;
1215
+ reorientationPlugin;
1216
+ options;
1217
+ // 用于模型居中
1218
+ _box = new I();
1219
+ _sphere = new x();
1220
+ // 当前材质类型
1221
+ _materialType = h.DEFAULT;
1222
+ // 按需渲染标志
1223
+ _needsUpdate = !0;
1224
+ _cameraTransitionStart = !1;
1225
+ loedTilesSets = /* @__PURE__ */ new Set();
1226
+ /**
1227
+ * 初始化 Cesium Ion 插件
1228
+ */
1229
+ _initCesiumIon(e) {
1230
+ this.tiles.registerPlugin(
1231
+ new L({
1232
+ apiToken: e.apiToken,
1233
+ assetId: e.assetId,
1234
+ autoRefreshToken: e.autoRefreshToken ?? !0
1235
+ })
1236
+ );
1237
+ }
1238
+ /**
1239
+ * 初始化基础插件
1240
+ */
1241
+ _initBasePlugins(e) {
1242
+ if (e._managedByPlugin || (m === null ? m = this.tiles.lruCache : this.tiles.lruCache = m, y === null ? y = this.tiles.parseQueue : this.tiles.parseQueue = y, f === null ? f = this.tiles.downloadQueue : this.tiles.downloadQueue = f, this.tiles.lruCache.maxSize = 600, this.tiles.lruCache.minSize = 300, this.tiles.lruCache.unloadPercent = 0.8), this._setupGLTFLoader(), this.tilesFadePlugin = new O({ maximumFadeOutTiles: 200 }), this.updateOnChangePlugin = new T(), this.tiles.registerPlugin(this.tilesFadePlugin), this.tiles.registerPlugin(this.updateOnChangePlugin), this.tiles.maxDepth = e.maxDepth ?? 20, this.tiles.errorTarget = e.errorTarget ?? 2, this.options.reorientation) {
1243
+ const t = this.options.reorientation || { lon: 120, lat: 30 };
1244
+ this.reorientationPlugin = new w({
1245
+ lon: t.lon,
1246
+ lat: t.lat,
1247
+ height: t.height ?? 0.1
1248
+ }), this.tiles.registerPlugin(this.reorientationPlugin), this.invalidate(
1249
+ t.lon,
1250
+ t.lat,
1251
+ t.height ?? 0.1
1252
+ );
1253
+ }
1254
+ this.tiles.addEventListener("load-model", this.onLoadModel), this.tiles.addEventListener("dispose-model", this.onDisposeModel), e._managedByPlugin || (this.tiles.addEventListener("load-model", this._onNeedsRender), this.tiles.addEventListener("needs-render", this._onNeedsRender), this.tiles.addEventListener("needs-update", this._onNeedsRender), this._setupCameraTransitionEvents());
1255
+ }
1256
+ /**
1257
+ * 设置 GLTF Loader
1258
+ */
1259
+ _setupGLTFLoader() {
1260
+ const e = new C(this.tiles.manager), t = this.ssp.manager?.store?.modelManager;
1261
+ if (t?.gltfLoader) {
1262
+ const { dracoLoader: r, ktx2Loader: i, meshoptDecoder: s } = t.gltfLoader;
1263
+ r && e.setDRACOLoader(r), i && e.setKTX2Loader(i), s && e.setMeshoptDecoder(s);
1264
+ }
1265
+ this.tiles.manager.addHandler(/\.gltf$/, e);
1266
+ }
1267
+ /**
1268
+ * 设置相机过渡事件监听
1269
+ */
1270
+ _setupCameraTransitionEvents() {
1271
+ const { controls: e, viewport: t } = this.ssp;
1272
+ e.addEventListener("transitionstart", () => {
1273
+ this._cameraTransitionStart = !0, t.state.useFreq = 1;
1274
+ }), e.addEventListener("rest", () => {
1275
+ this._cameraTransitionStart = !1, this._needsUpdate = !0, t.state.useFreq = 60;
108
1276
  });
109
1277
  }
1278
+ /**
1279
+ * 按需渲染回调
1280
+ */
1281
+ _onNeedsRender = () => {
1282
+ this._cameraTransitionStart || (this._needsUpdate = !0, this.render());
1283
+ };
1284
+ /**
1285
+ * 获取当前材质类型
1286
+ */
1287
+ get materialType() {
1288
+ return this._materialType;
1289
+ }
1290
+ /**
1291
+ * 设置材质类型
1292
+ */
1293
+ set materialType(e) {
1294
+ this._materialType = e, this.tiles.forEachLoadedModel((t) => {
1295
+ this.updateMaterial(t);
1296
+ }), this.render();
1297
+ }
1298
+ /**
1299
+ * 模型加载时保存原始材质
1300
+ */
1301
+ onLoadModel = ({ scene: e }) => {
1302
+ e.traverse((t) => {
1303
+ t.isMesh && (t.originalMaterial = t.material);
1304
+ }), this._materialType !== h.DEFAULT && this.updateMaterial(e);
1305
+ };
1306
+ /**
1307
+ * 更新场景中所有网格的材质(参考 customMaterial.js)
1308
+ */
1309
+ updateMaterial = (e) => {
1310
+ const t = this._materialType;
1311
+ e.traverse((r) => {
1312
+ if (r.isMesh)
1313
+ switch (r.material && r.material !== r.originalMaterial && r.material.dispose(), t) {
1314
+ case h.DEFAULT:
1315
+ r.material = r.originalMaterial, r.material && (r.material.side = 2), r.receiveShadow = !1, r.castShadow = !1;
1316
+ break;
1317
+ case h.GRADIENT:
1318
+ r.material = new P(Y), r.material.side = 2, r.receiveShadow = !1, r.castShadow = !1;
1319
+ break;
1320
+ case h.TOPOGRAPHIC_LINES: {
1321
+ const i = new P(V);
1322
+ i.extensions = { derivatives: !0 }, i.side = 2, r.material = i, r.receiveShadow = !1, r.castShadow = !1;
1323
+ break;
1324
+ }
1325
+ case h.LIGHTING:
1326
+ r.material = new N(), r.material.side = 2, r.receiveShadow = !0, r.castShadow = !0;
1327
+ break;
1328
+ }
1329
+ });
1330
+ };
1331
+ onDisposeModel = ({ scene: e }) => {
1332
+ e.traverse((t) => {
1333
+ t.isMesh && t.material.dispose();
1334
+ });
1335
+ };
1336
+ /**
1337
+ * 应用自动居中逻辑
1338
+ */
1339
+ applyAutoCenter() {
1340
+ this.options.autoCenter !== !1 && (this.tiles.getBoundingBox(this._box) ? (this._box.getCenter(this.tiles.group.position), this.tiles.group.position.multiplyScalar(-1)) : this.tiles.getBoundingSphere(this._sphere) && (this.tiles.group.position.copy(this._sphere.center), this.tiles.group.position.multiplyScalar(-1)));
1341
+ }
1342
+ /**
1343
+ * 每帧渲染前的处理
1344
+ */
1345
+ beforeRenderHandler = () => {
1346
+ this._needsUpdate && (this._needsUpdate = !1, this.ssp.viewport.camera.updateMatrixWorld(), this.tiles.setCamera(this.ssp.viewport.camera), this.tiles.setResolutionFromRenderer(
1347
+ this.ssp.viewport.camera,
1348
+ this.ssp.viewport.renderer
1349
+ ), this.applyAutoCenter(), this.tiles.group.updateMatrixWorld(), this.tiles.update());
1350
+ };
1351
+ render = () => {
1352
+ this.ssp.render();
1353
+ };
1354
+ enable() {
1355
+ this.ssp.addObject(this.tiles.group), this.ssp.signals.beforeRender.add(this.beforeRenderHandler);
1356
+ }
1357
+ disable() {
1358
+ this.ssp.removeObject(this.tiles.group), this.ssp.signals.beforeRender.remove(this.beforeRenderHandler);
1359
+ }
1360
+ invalidate(e, t, r) {
1361
+ if (!this.reorientationPlugin)
1362
+ return console.warn(
1363
+ "TilesRenderer: reorientationPlugin is not enabled, invalidate() will not work."
1364
+ ), () => {
1365
+ };
1366
+ const i = this.reorientationPlugin;
1367
+ this.options.reorientation = {
1368
+ lon: e,
1369
+ lat: t,
1370
+ height: r
1371
+ };
1372
+ const s = () => {
1373
+ const o = c.degToRad(t), d = c.degToRad(e);
1374
+ i.transformLatLonHeightToOrigin(o, d, r), this.render(), l();
1375
+ }, l = () => {
1376
+ this.tiles.removeEventListener("load-root-tileset", s), this.loedTilesSets.delete(s);
1377
+ };
1378
+ return this.tiles.addEventListener("load-root-tileset", s), this.loedTilesSets.add(s), this.tiles.root && s(), l;
1379
+ }
1380
+ dispose() {
1381
+ this.disable(), this.loedTilesSets.forEach(
1382
+ (e) => this.tiles.removeEventListener("load-root-tileset", e)
1383
+ ), this.loedTilesSets.clear(), this.tiles.removeEventListener("load-model", this.onLoadModel), this.tiles.removeEventListener("dispose-model", this.onDisposeModel), this.options._managedByPlugin || (this.tiles.removeEventListener("load-model", this._onNeedsRender), this.tiles.removeEventListener("needs-render", this._onNeedsRender), this.tiles.removeEventListener("needs-update", this._onNeedsRender)), this.tiles.dispose();
1384
+ }
1385
+ }
1386
+ class oe {
1387
+ constructor(e) {
1388
+ this.ssp = e;
1389
+ const { controls: t, viewport: r } = e;
1390
+ this._tilesCamera = r.camera, t.addEventListener("transitionstart", () => {
1391
+ this.cameraTransitionStart = !0, r.state.useFreq = 1;
1392
+ }), t.addEventListener("rest", () => {
1393
+ this.cameraTransitionStart = !1, this.needsUpdate = !0, r.state.useFreq = 60;
1394
+ }), e.signals.beforeRender.add(this._beforeRenderHandler), e.signals.cameraObjectChange.add(this._onCameraObjectChange);
1395
+ }
1396
+ /** 存储多个 tiles 实例,key 为 url */
110
1397
  tilesMap = /* @__PURE__ */ new Map();
1398
+ /** 按需渲染标志 */
111
1399
  needsUpdate = !0;
112
1400
  cameraTransitionStart = !1;
113
1401
  _tilesCamera;
114
- lruCache = null;
115
- parseQueue = null;
116
- downloadQueue = null;
117
- async loadTiles(t) {
118
- if (this.tilesMap.has(t)) {
119
- c.utils.warn(`${t} already loaded`);
120
- return;
121
- }
122
- const { ssp: s, ssp: { viewport: i } } = this, e = new g(t);
123
- this.lruCache === null ? this.lruCache = e.lruCache : e.lruCache = this.lruCache, this.parseQueue === null ? this.parseQueue = e.parseQueue : e.parseQueue = this.parseQueue, this.downloadQueue === null ? this.downloadQueue = e.downloadQueue : e.downloadQueue = this.downloadQueue;
124
- const r = new p(e.manager);
125
- r.register((o) => new L(o));
126
- const { dracoLoader: a, ktx2Loader: n, meshoptDecoder: d } = s.manager.store.modelManager.gltfLoader;
127
- a && r.setDRACOLoader(a), n && r.setKTX2Loader(n), d && r.setMeshoptDecoder(d), e.manager.addHandler(/\.gltf$/, r), this.tilesMap.set(t, e), e.setCamera(this._tilesCamera), e.setResolutionFromRenderer(this._tilesCamera, i.renderer), e.lruCache.maxSize = 600, e.lruCache.minSize = 300, e.lruCache.unloadPercent = 0.8, s.addObject(e.group);
128
- const u = () => {
129
- this.cameraTransitionStart || (this.needsUpdate = !0, s.render());
1402
+ _lruCache = null;
1403
+ _parseQueue = null;
1404
+ _downloadQueue = null;
1405
+ _beforeRenderHandler = () => {
1406
+ this.needsUpdate && (this.needsUpdate = !1, this.ssp.viewport.camera.updateMatrixWorld(), this.tilesMap.forEach((e) => {
1407
+ e.tiles.setCamera(this.ssp.viewport.camera), e.tiles.setResolutionFromRenderer(this.ssp.viewport.camera, this.ssp.viewport.renderer), e.applyAutoCenter(), e.tiles.group.updateMatrixWorld(), e.tiles.update();
1408
+ }));
1409
+ };
1410
+ _onCameraObjectChange = () => {
1411
+ this.tilesMap.forEach((e) => {
1412
+ e.tiles.deleteCamera(this._tilesCamera), e.tiles.setCamera(this.ssp.viewport.camera), e.tiles.setResolutionFromRenderer(this.ssp.viewport.camera, this.ssp.viewport.renderer);
1413
+ }), this._tilesCamera = this.ssp.viewport.camera;
1414
+ };
1415
+ /**
1416
+ * 加载 3D Tiles
1417
+ * @param url - tileset.json 地址
1418
+ * @param options - 配置项
1419
+ * @returns Promise<ThreeDTilesRenderer>
1420
+ */
1421
+ async loadTiles(e) {
1422
+ const t = "url" in e ? e.url : e.assetId;
1423
+ if (this.tilesMap.has(t))
1424
+ return _.utils.warn(`${t} already loaded`), this.tilesMap.get(t);
1425
+ const { ssp: r } = this, i = new q(r, {
1426
+ ...e,
1427
+ _managedByPlugin: !0
1428
+ }), { tiles: s } = i;
1429
+ this._lruCache === null ? this._lruCache = s.lruCache : s.lruCache = this._lruCache, this._parseQueue === null ? this._parseQueue = s.parseQueue : s.parseQueue = this._parseQueue, this._downloadQueue === null ? this._downloadQueue = s.downloadQueue : s.downloadQueue = this._downloadQueue, s.lruCache.maxSize = 600, s.lruCache.minSize = 300, s.lruCache.unloadPercent = 0.8, this.tilesMap.set(t, i), s.setCamera(this._tilesCamera), s.setResolutionFromRenderer(this._tilesCamera, r.viewport.renderer), r.addObject(s.group);
1430
+ const l = () => {
1431
+ this.cameraTransitionStart || (this.needsUpdate = !0, r.render());
130
1432
  };
131
- return e.addEventListener("load-model", u), new Promise((o) => {
132
- e.addEventListener("load-tile-set", () => {
133
- u(), o(e);
1433
+ return s.addEventListener("load-model", l), new Promise((o) => {
1434
+ s.addEventListener("load-tile-set", () => {
1435
+ l(), o(i);
134
1436
  });
135
1437
  });
136
1438
  }
137
- removeTiles(t) {
138
- const s = this.tilesMap.get(t);
139
- return s ? (s.dispose(), this.tilesMap.delete(t), this.ssp.removeObject(s.group), !0) : !1;
1439
+ /**
1440
+ * 移除 3D Tiles
1441
+ * @param url - tileset.json 地址
1442
+ * @returns boolean
1443
+ */
1444
+ removeTiles(e) {
1445
+ const t = this.tilesMap.get(e);
1446
+ return t ? (t.tiles.dispose(), this.tilesMap.delete(e), this.ssp.removeObject(t.tiles.group), !0) : !1;
1447
+ }
1448
+ /**
1449
+ * 获取指定 url 的 renderer
1450
+ */
1451
+ getTiles(e) {
1452
+ return this.tilesMap.get(e);
1453
+ }
1454
+ /**
1455
+ * 获取所有已加载的 renderer
1456
+ */
1457
+ getAllTiles() {
1458
+ return Array.from(this.tilesMap.values());
1459
+ }
1460
+ /**
1461
+ * 清除所有 tiles
1462
+ */
1463
+ clear() {
1464
+ this.tilesMap.forEach((e) => {
1465
+ e.tiles.dispose(), this.ssp.removeObject(e.tiles.group);
1466
+ }), this.tilesMap.clear();
1467
+ }
1468
+ invalidate(e, t, r) {
1469
+ this.tilesMap.forEach((i) => {
1470
+ i.invalidate(e, t, r);
1471
+ });
1472
+ }
1473
+ /**
1474
+ * 销毁插件
1475
+ */
1476
+ dispose() {
1477
+ this.clear(), this.ssp.signals.beforeRender.remove(this._beforeRenderHandler), this.ssp.signals.cameraObjectChange.remove(this._onCameraObjectChange), this._lruCache = null, this._parseQueue = null, this._downloadQueue = null;
140
1478
  }
141
1479
  }
142
1480
  export {
143
- E as ArcgisTilesRenderer,
144
- Q as default
1481
+ ne as ArcgisTilesRenderer,
1482
+ h as MaterialType,
1483
+ B as OverlayManager,
1484
+ a as OverlayType,
1485
+ le as TerrainTilesRenderer,
1486
+ g as TerrainType,
1487
+ H as TileCustomMaterialPlugin,
1488
+ q as TilesRenderer,
1489
+ oe as TilesRendererManager,
1490
+ se as default
145
1491
  };