gltf-parser-plugin 1.1.7 → 1.1.8

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.
@@ -1,23 +1,68 @@
1
- import { Box2, Box3, BufferAttribute, BufferGeometry, Color, CustomBlending, DataTexture, DoubleSide, EdgesGeometry, EventDispatcher, Float32BufferAttribute, FrontSide, Group, InstancedMesh, LineSegments, Loader, Matrix2, Matrix3, Matrix4, Mesh, MeshBasicMaterial, MeshStandardMaterial, OneFactor, OrthographicCamera, Quaternion, RGBAFormat, SRGBColorSpace, Scene, ShaderMaterial, Texture, Triangle, UnsignedByteType, Vector2, Vector3, Vector4, WebGLRenderTarget, WebGLRenderer, ZeroFactor } from "three";
2
- //#region src/mesh-helper/FeatureIdUniforms.ts
3
- var FeatureIdUniforms = class {
4
- mesh;
5
- plugin;
6
- constructor(mesh, plugin) {
7
- this.mesh = mesh;
8
- this.plugin = plugin;
9
- }
10
- get value() {
11
- const idMap = this.mesh.userData.idMap;
12
- if (!idMap) return new Array(this.plugin.getFeatureIdCount()).fill(-1);
13
- const result = new Array(this.plugin.getFeatureIdCount()).fill(-1);
14
- for (let i = 0; i < this.plugin.oids.length; i++) {
15
- const featureId = idMap[this.plugin.oids[i]];
16
- result[i] = featureId !== void 0 ? featureId : -1;
17
- }
18
- return result;
1
+ import { Box2, Box3, BufferAttribute, BufferGeometry, Color, CustomBlending, DataTexture, DoubleSide, EdgesGeometry, Euler, EventDispatcher, Float32BufferAttribute, FrontSide, Group, InstancedMesh, LineSegments, Loader, Material, Matrix2, Matrix3, Matrix4, Mesh, MeshBasicMaterial, MeshStandardMaterial, OneFactor, OrthographicCamera, Quaternion, RGBAFormat, SRGBColorSpace, Scene, ShaderMaterial, Texture, Triangle, UnsignedByteType, Vector2, Vector3, Vector4, WebGLRenderTarget, WebGLRenderer, ZeroFactor } from "three";
2
+ //#region src/mesh-helper/index-visibility.ts
3
+ /** mesh idMap 和 hiddenOids 构建需要隐藏的 feature ID 集合 */
4
+ function getHiddenFeatureIds(mesh, hiddenOids) {
5
+ const idMap = mesh.userData?.idMap;
6
+ if (!idMap) return /* @__PURE__ */ new Set();
7
+ const hidden = /* @__PURE__ */ new Set();
8
+ for (const oid of hiddenOids) {
9
+ const fid = idMap[oid];
10
+ if (fid !== void 0) hidden.add(fid);
11
+ }
12
+ return hidden;
13
+ }
14
+ /** 对单个 mesh 应用可见性过滤(通过修改 index 排除隐藏的三角形) */
15
+ function applyVisibilityToMesh(mesh, hiddenOids) {
16
+ const { meshFeatures } = mesh.userData;
17
+ if (!meshFeatures) return;
18
+ const geometry = mesh.geometry;
19
+ const index = geometry.index;
20
+ const featureIdAttr = geometry.getAttribute("_feature_id_0");
21
+ if (!index || !featureIdAttr) return;
22
+ const hiddenFeatureIds = getHiddenFeatureIds(mesh, hiddenOids);
23
+ if (hiddenFeatureIds.size === 0) {
24
+ restoreMeshIndex(mesh);
25
+ return;
26
+ }
27
+ if (!mesh.userData._originalIndex) mesh.userData._originalIndex = index.array.slice(0);
28
+ const originalArray = mesh.userData._originalIndex;
29
+ const filtered = originalArray instanceof Uint32Array ? new Uint32Array(originalArray.length) : new Uint16Array(originalArray.length);
30
+ let writeOffset = 0;
31
+ for (let i = 0; i < originalArray.length; i += 3) {
32
+ const fid = featureIdAttr.getX(originalArray[i]);
33
+ if (hiddenFeatureIds.has(fid)) continue;
34
+ filtered[writeOffset++] = originalArray[i];
35
+ filtered[writeOffset++] = originalArray[i + 1];
36
+ filtered[writeOffset++] = originalArray[i + 2];
37
+ }
38
+ const filteredArray = filtered.subarray(0, writeOffset);
39
+ geometry.setIndex(new BufferAttribute(filteredArray, 1));
40
+ geometry.index.needsUpdate = true;
41
+ }
42
+ /** 恢复 mesh 的原始 index */
43
+ function restoreMeshIndex(mesh) {
44
+ const original = mesh.userData?._originalIndex;
45
+ if (!original) return;
46
+ const geometry = mesh.geometry;
47
+ if (!geometry?.index) return;
48
+ geometry.setIndex(new BufferAttribute(original, 1));
49
+ geometry.index.needsUpdate = true;
50
+ }
51
+ /** 遍历 scene 中所有 tile mesh,应用可见性过滤 */
52
+ function applyVisibilityToScene(scene, hiddenOids) {
53
+ const oidSet = hiddenOids;
54
+ if (oidSet.size === 0) {
55
+ scene.traverse((obj) => {
56
+ const mesh = obj;
57
+ if (mesh.userData?.meshFeatures && !mesh.userData?.isSplit) restoreMeshIndex(mesh);
58
+ });
59
+ return;
19
60
  }
20
- };
61
+ scene.traverse((obj) => {
62
+ const mesh = obj;
63
+ if (mesh.userData?.meshFeatures && mesh.userData?.structuralMetadata && !mesh.userData?.isSplit) applyVisibilityToMesh(mesh, oidSet);
64
+ });
65
+ }
21
66
  //#endregion
22
67
  //#region src/mesh-helper/idmap.ts
23
68
  var FEATURE_INDEX = 0;
@@ -108,87 +153,143 @@ function queryFeatureFromIntersection(hit) {
108
153
  //#endregion
109
154
  //#region src/mesh-helper/mesh.ts
110
155
  /**
111
- * 预建featureId到顶点索引的映射表,提高查询性能
156
+ * 合并多个 feature 的三角形为单一 BufferGeometry(共享顶点属性,index 为并集)
112
157
  */
113
- function buildFeatureIdIndexMap(featureIdAttr) {
114
- const featureIdMap = /* @__PURE__ */ new Map();
115
- for (let i = 0; i < featureIdAttr.count; i++) {
116
- const featureId = featureIdAttr.getX(i);
117
- if (!featureIdMap.has(featureId)) featureIdMap.set(featureId, /* @__PURE__ */ new Set());
118
- featureIdMap.get(featureId).add(i);
119
- }
120
- return featureIdMap;
121
- }
122
- /**
123
- * Create a geometry for a specified feature ID
124
- */
125
- function createGeometryForFeatureId(originalGeometry, featureIdMap, targetFeatureId) {
158
+ function createGeometryForFeatureIdSet(originalGeometry, featureIdAttr, targetFids) {
159
+ if (targetFids.size === 0 || !originalGeometry.index) return null;
126
160
  const newGeometry = new BufferGeometry();
127
- const targetVertexIndices = featureIdMap.get(targetFeatureId);
128
- if (!targetVertexIndices || targetVertexIndices.size === 0) return null;
129
161
  const attributes = originalGeometry.attributes;
130
162
  for (const attributeName in attributes) newGeometry.setAttribute(attributeName, attributes[attributeName]);
131
- if (originalGeometry.index) {
132
- const originalIndex = originalGeometry.index.array;
133
- const newIndices = [];
134
- for (let i = 0; i < originalIndex.length; i += 3) {
135
- const a = originalIndex[i];
136
- const b = originalIndex[i + 1];
137
- const c = originalIndex[i + 2];
138
- if (targetVertexIndices.has(a) && targetVertexIndices.has(b) && targetVertexIndices.has(c)) newIndices.push(a, b, c);
139
- }
140
- if (newIndices.length > 0) newGeometry.setIndex(newIndices);
141
- }
163
+ const originalIndex = originalGeometry.index.array;
164
+ const newIndices = [];
165
+ for (let i = 0; i < originalIndex.length; i += 3) {
166
+ const a = originalIndex[i];
167
+ const b = originalIndex[i + 1];
168
+ const c = originalIndex[i + 2];
169
+ const fa = featureIdAttr.getX(a);
170
+ if (fa === featureIdAttr.getX(b) && fa === featureIdAttr.getX(c) && targetFids.has(fa)) newIndices.push(a, b, c);
171
+ }
172
+ if (newIndices.length === 0) return null;
173
+ newGeometry.setIndex(newIndices);
142
174
  return newGeometry;
143
175
  }
144
176
  /**
145
- * Function to split mesh by feature ID
177
+ * 将同一瓦片 mesh 内、属于给定 OID 集合的所有 feature 合并为 **单个** Mesh(每瓦片最多一个)
146
178
  */
147
- function splitMeshByOid(originalMesh, oid) {
179
+ function splitMeshByOidsMerged(originalMesh, oidSet) {
180
+ if (oidSet.size === 0) return null;
181
+ const idMap = originalMesh.userData?.idMap;
182
+ if (!idMap) return null;
148
183
  const { meshFeatures, structuralMetadata } = originalMesh.userData;
149
184
  const { geometry, featureIds } = meshFeatures;
150
185
  const featureId = featureIds[0];
151
186
  const featureIdAttr = geometry.getAttribute(`_feature_id_${featureId.attribute}`);
152
187
  if (!featureIdAttr) {
153
188
  console.warn("No feature ID attribute found");
154
- return [];
155
- }
156
- const featureIdMap = buildFeatureIdIndexMap(featureIdAttr);
157
- const currentBatchMeshes = [];
158
- for (const [fid] of featureIdMap) try {
159
- let _oid = null;
160
- let propertyData = null;
161
- if (structuralMetadata) try {
162
- propertyData = structuralMetadata.getPropertyTableData(featureId.propertyTable, fid);
163
- _oid = propertyData?._oid;
164
- if (_oid === oid) {
165
- const newGeometry = createGeometryForFeatureId(geometry, featureIdMap, fid);
166
- if (newGeometry && newGeometry.attributes.position.count > 0) {
167
- const newMesh = new Mesh(newGeometry, originalMesh.material.clone());
168
- newMesh.parent = originalMesh.parent;
169
- newMesh.position.copy(originalMesh.position);
170
- newMesh.rotation.copy(originalMesh.rotation);
171
- newMesh.scale.copy(originalMesh.scale);
172
- newMesh.matrixWorld.copy(originalMesh.matrixWorld);
173
- newMesh.userData = {
174
- ...originalMesh.userData,
175
- featureId: fid,
176
- oid,
177
- originalMesh,
178
- propertyData,
179
- isSplit: true
180
- };
181
- newMesh.name = `feature_${fid}_${oid || ""}`;
182
- currentBatchMeshes.push(newMesh);
183
- }
184
- }
185
- } catch (e) {
186
- console.warn(`Failed to get property data for feature ${fid}:`, e);
189
+ return null;
190
+ }
191
+ const targetFids = /* @__PURE__ */ new Set();
192
+ const oidsOnMesh = [];
193
+ for (const oid of oidSet) {
194
+ const fid = idMap[oid];
195
+ if (fid !== void 0) {
196
+ targetFids.add(fid);
197
+ oidsOnMesh.push(oid);
187
198
  }
188
- } catch (error) {
189
- console.warn(`Error creating mesh for feature ${fid}:`, error);
190
199
  }
191
- return currentBatchMeshes;
200
+ if (targetFids.size === 0) return null;
201
+ const newGeometry = createGeometryForFeatureIdSet(geometry, featureIdAttr, targetFids);
202
+ if (!newGeometry || newGeometry.attributes.position.count === 0) return null;
203
+ const newMesh = new Mesh(newGeometry, originalMesh.material.clone());
204
+ newMesh.parent = originalMesh.parent;
205
+ newMesh.position.copy(originalMesh.position);
206
+ newMesh.rotation.copy(originalMesh.rotation);
207
+ newMesh.scale.copy(originalMesh.scale);
208
+ newMesh.matrixWorld.copy(originalMesh.matrixWorld);
209
+ oidsOnMesh.sort((a, b) => a - b);
210
+ const primaryOid = oidsOnMesh[0];
211
+ let propertyData = null;
212
+ if (structuralMetadata && idMap[primaryOid] !== void 0) try {
213
+ propertyData = structuralMetadata.getPropertyTableData(featureId.propertyTable, idMap[primaryOid]);
214
+ } catch {}
215
+ newMesh.userData = {
216
+ ...originalMesh.userData,
217
+ featureId: idMap[primaryOid],
218
+ oid: primaryOid,
219
+ collectorOids: oidsOnMesh,
220
+ originalMesh,
221
+ propertyData,
222
+ isSplit: true,
223
+ isMergedSplit: true
224
+ };
225
+ newMesh.name = `merged_features_${oidsOnMesh.length}_${primaryOid}`;
226
+ return newMesh;
227
+ }
228
+ /** 瓦片内原始 feature mesh(非 split 子网格) */
229
+ function isFeatureSourceMesh(mesh) {
230
+ const u = mesh.userData;
231
+ return Boolean(u?.meshFeatures && u?.structuralMetadata && !u?.isSplit);
232
+ }
233
+ /**
234
+ * 从瓦片中获取所有 OID
235
+ */
236
+ function getAllOidsFromTiles(tiles) {
237
+ const oidSet = /* @__PURE__ */ new Set();
238
+ tiles.group.traverse((child) => {
239
+ const mesh = child;
240
+ if (!isFeatureSourceMesh(mesh)) return;
241
+ const idMap = mesh.userData.idMap;
242
+ if (!idMap) return;
243
+ for (const oid of Object.keys(idMap).map(Number)) oidSet.add(oid);
244
+ });
245
+ return Array.from(oidSet);
246
+ }
247
+ /**
248
+ * 根据 OID 获取属性数据(从瓦片 structuralMetadata)
249
+ */
250
+ function getPropertyDataByOid(tiles, oid) {
251
+ let result = null;
252
+ tiles.group.traverse((child) => {
253
+ if (result) return;
254
+ const mesh = child;
255
+ if (!isFeatureSourceMesh(mesh)) return;
256
+ const idMap = mesh.userData.idMap;
257
+ if (!idMap || idMap[oid] === void 0) return;
258
+ const { meshFeatures, structuralMetadata } = mesh.userData;
259
+ const featureId = meshFeatures.featureIds[0];
260
+ const fid = idMap[oid];
261
+ try {
262
+ result = structuralMetadata.getPropertyTableData(featureId.propertyTable, fid);
263
+ } catch {}
264
+ });
265
+ return result;
266
+ }
267
+ /**
268
+ * 单次遍历场景构建 OID → 属性表数据。
269
+ * 批量样式/筛选时使用,避免对每个 OID 重复 traverse(O(n×场景节点))。
270
+ */
271
+ function getPropertyDataMapFromTiles(tiles) {
272
+ const map = /* @__PURE__ */ new Map();
273
+ tiles.group.traverse((child) => {
274
+ const mesh = child;
275
+ if (!isFeatureSourceMesh(mesh)) return;
276
+ const idMap = mesh.userData.idMap;
277
+ if (!idMap) return;
278
+ const { meshFeatures, structuralMetadata } = mesh.userData;
279
+ const propertyTable = meshFeatures.featureIds[0].propertyTable;
280
+ for (const oid of Object.keys(idMap).map(Number)) {
281
+ if (map.has(oid)) continue;
282
+ const fid = idMap[oid];
283
+ if (fid === void 0) continue;
284
+ try {
285
+ const data = structuralMetadata.getPropertyTableData(propertyTable, fid);
286
+ map.set(oid, data);
287
+ } catch {
288
+ map.set(oid, null);
289
+ }
290
+ }
291
+ });
292
+ return map;
192
293
  }
193
294
  /**
194
295
  * 根据OID获取包含该OID的瓦片mesh
@@ -197,9 +298,7 @@ function getTileMeshesByOid(tiles, oid) {
197
298
  const tileMeshes = [];
198
299
  tiles.group.traverse((child) => {
199
300
  const mesh = child;
200
- if (mesh.userData.meshFeatures && mesh.userData.structuralMetadata && !mesh.userData.isSplit) {
201
- if (checkMeshContainsOid(mesh, oid)) tileMeshes.push(mesh);
202
- }
301
+ if (isFeatureSourceMesh(mesh) && checkMeshContainsOid(mesh, oid)) tileMeshes.push(mesh);
203
302
  });
204
303
  return tileMeshes;
205
304
  }
@@ -208,43 +307,74 @@ function checkMeshContainsOid(mesh, oid) {
208
307
  if (!idMap) return false;
209
308
  return idMap[oid] !== void 0;
210
309
  }
310
+ //#endregion
311
+ //#region src/MeshCollector.ts
312
+ /** 去重并排序 OID */
313
+ function normalizeMeshCollectorOids(oids) {
314
+ return [...new Set(oids)].sort((a, b) => a - b);
315
+ }
211
316
  /**
212
- * 获取分割后的mesh
317
+ * 与 MeshCollector.getCacheKey()、插件 collectorCache 键一致
213
318
  */
214
- function getSplitMeshesFromTile(tileMesh, oid) {
215
- let meshes = [];
216
- try {
217
- const splitMeshes = splitMeshByOid(tileMesh, oid);
218
- meshes = [...meshes, ...splitMeshes];
219
- } catch (error) {
220
- console.warn(`拆分mesh失败:`, error);
221
- }
222
- return meshes;
319
+ function meshCollectorQueryCacheKey(query) {
320
+ const oidsNorm = normalizeMeshCollectorOids(query.oids ?? []);
321
+ const oidPart = oidsNorm.length > 0 ? oidsNorm.join(",") : "*";
322
+ const condRaw = query.condition?.trim() ?? "";
323
+ return `${oidPart}@@${condRaw === "" ? "_" : encodeURIComponent(condRaw)}`;
324
+ }
325
+ /** @deprecated 请使用 meshCollectorQueryCacheKey({ oids }) */
326
+ function meshCollectorGroupKey(oids) {
327
+ return meshCollectorQueryCacheKey({ oids });
223
328
  }
224
- //#endregion
225
- //#region src/MeshCollector.ts
226
329
  /**
227
- * MeshCollector - 用于监听和收集特定 oid 对应的 mesh
228
- * 随着瓦片变化,会自动更新 meshes 并触发 mesh-change 事件
330
+ * MeshCollector - 按查询条件监听并收集 split mesh
229
331
  */
230
332
  var MeshCollector = class extends EventDispatcher {
231
- oid;
333
+ queryOids;
334
+ condition;
335
+ cacheKey;
232
336
  plugin;
233
337
  _meshes = [];
234
338
  _disposed = false;
235
- constructor(oid, plugin) {
339
+ constructor(query, plugin) {
236
340
  super();
237
- this.oid = oid;
341
+ const oids = normalizeMeshCollectorOids(query.oids ?? []);
342
+ const condition = query.condition?.trim() || void 0;
343
+ if (oids.length === 0 && !condition) throw new Error("MeshCollector requires at least one OID in oids and/or a non-empty condition");
344
+ this.queryOids = oids;
345
+ this.condition = condition;
346
+ this.cacheKey = meshCollectorQueryCacheKey({
347
+ oids,
348
+ condition
349
+ });
238
350
  this.plugin = plugin;
239
351
  plugin._registerCollector(this);
240
352
  this._updateMeshes();
241
353
  }
354
+ getCacheKey() {
355
+ return this.cacheKey;
356
+ }
357
+ /** 查询里显式传入的 OID(规范化后);仅用 condition 筛选时可能为空数组 */
358
+ getOids() {
359
+ return this.queryOids;
360
+ }
361
+ /** 有显式 OID 时返回第一个;否则无意义(可能为 undefined) */
362
+ getOid() {
363
+ return this.queryOids[0];
364
+ }
242
365
  get meshes() {
243
366
  return this._meshes;
244
367
  }
368
+ /** 与 setStyle 一致的条件表达式(若有) */
369
+ getCondition() {
370
+ return this.condition;
371
+ }
245
372
  _updateMeshes() {
246
373
  if (this._disposed) return;
247
- const newMeshes = this.plugin._getMeshesByOidInternal(this.oid);
374
+ const newMeshes = this.plugin._getMeshesForCollectorQueryInternal({
375
+ oids: this.queryOids,
376
+ condition: this.condition
377
+ });
248
378
  if (newMeshes.length !== this._meshes.length || newMeshes.some((mesh, i) => mesh !== this._meshes[i])) {
249
379
  this._meshes = newMeshes;
250
380
  this.dispatchEvent({
@@ -253,9 +383,6 @@ var MeshCollector = class extends EventDispatcher {
253
383
  });
254
384
  }
255
385
  }
256
- getOid() {
257
- return this.oid;
258
- }
259
386
  dispose() {
260
387
  if (this._disposed) return;
261
388
  this._disposed = true;
@@ -264,6 +391,51 @@ var MeshCollector = class extends EventDispatcher {
264
391
  }
265
392
  };
266
393
  //#endregion
394
+ //#region src/plugin/style-condition-eval.ts
395
+ /**
396
+ * 与 StyleHelper 中 `show`、`conditions` 条件项的表达式求值一致
397
+ * 在 propertyData 的键作为变量名的上下文中执行 `Boolean(expr)`
398
+ *
399
+ * 实现:对每个表达式字符串只编译一次 `new Function('data', 'with(d){...}')`,
400
+ * 避免按「表达式 × 属性键集合」重复编译,也避免每次求值排序/拼接 cacheKey。
401
+ */
402
+ var compiledCache = /* @__PURE__ */ new Map();
403
+ var MAX_CACHE_ENTRIES = 512;
404
+ function getCompiled(expr) {
405
+ let fn = compiledCache.get(expr);
406
+ if (fn) return fn;
407
+ try {
408
+ fn = new Function("data", `var d = data != null && typeof data === "object" ? data : {};
409
+ with (d) { return Boolean(${expr}); }`);
410
+ } catch {
411
+ return null;
412
+ }
413
+ if (compiledCache.size >= MAX_CACHE_ENTRIES) {
414
+ const first = compiledCache.keys().next().value;
415
+ if (first !== void 0) compiledCache.delete(first);
416
+ }
417
+ compiledCache.set(expr, fn);
418
+ return fn;
419
+ }
420
+ /**
421
+ * 清空表达式编译缓存(热更新或单测可调用)
422
+ */
423
+ function clearStyleConditionCache() {
424
+ compiledCache.clear();
425
+ }
426
+ function evaluateStyleCondition(expr, propertyData) {
427
+ if (expr === true) return true;
428
+ if (expr === false) return false;
429
+ if (typeof expr !== "string" || !expr.trim()) return true;
430
+ const fn = getCompiled(expr.trim());
431
+ if (!fn) return false;
432
+ try {
433
+ return fn(propertyData ?? {});
434
+ } catch {
435
+ return false;
436
+ }
437
+ }
438
+ //#endregion
267
439
  //#region src/utils/build-textures.ts
268
440
  /**
269
441
  * Build textures from GLTF data
@@ -566,15 +738,24 @@ function polygonIntersectsRect(polygon, minX, minY, maxX, maxY) {
566
738
  return false;
567
739
  }
568
740
  /**
741
+ * 将 structure 中的 bbox 数组转为 Box3。
742
+ * 约定与 `selectByBox` 一致:`[minX, minY, minZ, maxX, maxY, maxZ]`,至少 6 个数。
743
+ */
744
+ function bboxArrayToBox3(bbox) {
745
+ if (!bbox || bbox.length < 6) return null;
746
+ const box = new Box3();
747
+ box.min.set(bbox[0], bbox[1], bbox[2]);
748
+ box.max.set(bbox[3], bbox[4], bbox[5]);
749
+ return box;
750
+ }
751
+ /**
569
752
  * 从 OID 节点映射中按 Box3 范围筛选构件
570
753
  */
571
754
  function selectByBoxFromOidMap(oidNodeMap, box) {
572
755
  const result = [];
573
- const nodeBox = new Box3();
574
756
  for (const [oid, node] of oidNodeMap) {
575
- if (!node.bbox || node.bbox.length < 6) continue;
576
- nodeBox.min.set(node.bbox[0], node.bbox[1], node.bbox[2]);
577
- nodeBox.max.set(node.bbox[3], node.bbox[4], node.bbox[5]);
757
+ const nodeBox = bboxArrayToBox3(node.bbox);
758
+ if (!nodeBox) continue;
578
759
  if (box.intersectsBox(nodeBox)) result.push(oid);
579
760
  }
580
761
  return result;
@@ -619,7 +800,394 @@ function selectByPolygonFromOidMap(oidNodeMap, polygon, axis = "xz") {
619
800
  return result;
620
801
  }
621
802
  //#endregion
622
- //#region node_modules/.pnpm/3d-tiles-renderer@0.4.22_three@0.183.2/node_modules/3d-tiles-renderer/build/constants-Cj07Qhs1.js
803
+ //#region src/utils/color-input.ts
804
+ function toColor(value) {
805
+ return value instanceof Color ? value : new Color(value);
806
+ }
807
+ //#endregion
808
+ //#region node_modules/.pnpm/fflate@0.8.2/node_modules/fflate/esm/browser.js
809
+ var u8 = Uint8Array, u16 = Uint16Array, i32 = Int32Array;
810
+ var fleb = new u8([
811
+ 0,
812
+ 0,
813
+ 0,
814
+ 0,
815
+ 0,
816
+ 0,
817
+ 0,
818
+ 0,
819
+ 1,
820
+ 1,
821
+ 1,
822
+ 1,
823
+ 2,
824
+ 2,
825
+ 2,
826
+ 2,
827
+ 3,
828
+ 3,
829
+ 3,
830
+ 3,
831
+ 4,
832
+ 4,
833
+ 4,
834
+ 4,
835
+ 5,
836
+ 5,
837
+ 5,
838
+ 5,
839
+ 0,
840
+ 0,
841
+ 0,
842
+ 0
843
+ ]);
844
+ var fdeb = new u8([
845
+ 0,
846
+ 0,
847
+ 0,
848
+ 0,
849
+ 1,
850
+ 1,
851
+ 2,
852
+ 2,
853
+ 3,
854
+ 3,
855
+ 4,
856
+ 4,
857
+ 5,
858
+ 5,
859
+ 6,
860
+ 6,
861
+ 7,
862
+ 7,
863
+ 8,
864
+ 8,
865
+ 9,
866
+ 9,
867
+ 10,
868
+ 10,
869
+ 11,
870
+ 11,
871
+ 12,
872
+ 12,
873
+ 13,
874
+ 13,
875
+ 0,
876
+ 0
877
+ ]);
878
+ var clim = new u8([
879
+ 16,
880
+ 17,
881
+ 18,
882
+ 0,
883
+ 8,
884
+ 7,
885
+ 9,
886
+ 6,
887
+ 10,
888
+ 5,
889
+ 11,
890
+ 4,
891
+ 12,
892
+ 3,
893
+ 13,
894
+ 2,
895
+ 14,
896
+ 1,
897
+ 15
898
+ ]);
899
+ var freb = function(eb, start) {
900
+ var b = new u16(31);
901
+ for (var i = 0; i < 31; ++i) b[i] = start += 1 << eb[i - 1];
902
+ var r = new i32(b[30]);
903
+ for (var i = 1; i < 30; ++i) for (var j = b[i]; j < b[i + 1]; ++j) r[j] = j - b[i] << 5 | i;
904
+ return {
905
+ b,
906
+ r
907
+ };
908
+ };
909
+ var _a = freb(fleb, 2), fl = _a.b, revfl = _a.r;
910
+ fl[28] = 258, revfl[258] = 28;
911
+ var fd = freb(fdeb, 0).b;
912
+ var rev = new u16(32768);
913
+ for (var i = 0; i < 32768; ++i) {
914
+ var x = (i & 43690) >> 1 | (i & 21845) << 1;
915
+ x = (x & 52428) >> 2 | (x & 13107) << 2;
916
+ x = (x & 61680) >> 4 | (x & 3855) << 4;
917
+ rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
918
+ }
919
+ var hMap = (function(cd, mb, r) {
920
+ var s = cd.length;
921
+ var i = 0;
922
+ var l = new u16(mb);
923
+ for (; i < s; ++i) if (cd[i]) ++l[cd[i] - 1];
924
+ var le = new u16(mb);
925
+ for (i = 1; i < mb; ++i) le[i] = le[i - 1] + l[i - 1] << 1;
926
+ var co;
927
+ if (r) {
928
+ co = new u16(1 << mb);
929
+ var rvb = 15 - mb;
930
+ for (i = 0; i < s; ++i) if (cd[i]) {
931
+ var sv = i << 4 | cd[i];
932
+ var r_1 = mb - cd[i];
933
+ var v = le[cd[i] - 1]++ << r_1;
934
+ for (var m = v | (1 << r_1) - 1; v <= m; ++v) co[rev[v] >> rvb] = sv;
935
+ }
936
+ } else {
937
+ co = new u16(s);
938
+ for (i = 0; i < s; ++i) if (cd[i]) co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
939
+ }
940
+ return co;
941
+ });
942
+ var flt = new u8(288);
943
+ for (var i = 0; i < 144; ++i) flt[i] = 8;
944
+ for (var i = 144; i < 256; ++i) flt[i] = 9;
945
+ for (var i = 256; i < 280; ++i) flt[i] = 7;
946
+ for (var i = 280; i < 288; ++i) flt[i] = 8;
947
+ var fdt = new u8(32);
948
+ for (var i = 0; i < 32; ++i) fdt[i] = 5;
949
+ var flrm = /* @__PURE__ */ hMap(flt, 9, 1), fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
950
+ var max = function(a) {
951
+ var m = a[0];
952
+ for (var i = 1; i < a.length; ++i) if (a[i] > m) m = a[i];
953
+ return m;
954
+ };
955
+ var bits = function(d, p, m) {
956
+ var o = p / 8 | 0;
957
+ return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
958
+ };
959
+ var bits16 = function(d, p) {
960
+ var o = p / 8 | 0;
961
+ return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
962
+ };
963
+ var shft = function(p) {
964
+ return (p + 7) / 8 | 0;
965
+ };
966
+ var slc = function(v, s, e) {
967
+ if (s == null || s < 0) s = 0;
968
+ if (e == null || e > v.length) e = v.length;
969
+ return new u8(v.subarray(s, e));
970
+ };
971
+ var ec = [
972
+ "unexpected EOF",
973
+ "invalid block type",
974
+ "invalid length/literal",
975
+ "invalid distance",
976
+ "stream finished",
977
+ "no stream handler",
978
+ ,
979
+ "no callback",
980
+ "invalid UTF-8 data",
981
+ "extra field too long",
982
+ "date not in range 1980-2099",
983
+ "filename too long",
984
+ "stream finishing",
985
+ "invalid zip data"
986
+ ];
987
+ var err = function(ind, msg, nt) {
988
+ var e = new Error(msg || ec[ind]);
989
+ e.code = ind;
990
+ if (Error.captureStackTrace) Error.captureStackTrace(e, err);
991
+ if (!nt) throw e;
992
+ return e;
993
+ };
994
+ var inflt = function(dat, st, buf, dict) {
995
+ var sl = dat.length, dl = dict ? dict.length : 0;
996
+ if (!sl || st.f && !st.l) return buf || new u8(0);
997
+ var noBuf = !buf;
998
+ var resize = noBuf || st.i != 2;
999
+ var noSt = st.i;
1000
+ if (noBuf) buf = new u8(sl * 3);
1001
+ var cbuf = function(l) {
1002
+ var bl = buf.length;
1003
+ if (l > bl) {
1004
+ var nbuf = new u8(Math.max(bl * 2, l));
1005
+ nbuf.set(buf);
1006
+ buf = nbuf;
1007
+ }
1008
+ };
1009
+ var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;
1010
+ var tbts = sl * 8;
1011
+ do {
1012
+ if (!lm) {
1013
+ final = bits(dat, pos, 1);
1014
+ var type = bits(dat, pos + 1, 3);
1015
+ pos += 3;
1016
+ if (!type) {
1017
+ var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
1018
+ if (t > sl) {
1019
+ if (noSt) err(0);
1020
+ break;
1021
+ }
1022
+ if (resize) cbuf(bt + l);
1023
+ buf.set(dat.subarray(s, t), bt);
1024
+ st.b = bt += l, st.p = pos = t * 8, st.f = final;
1025
+ continue;
1026
+ } else if (type == 1) lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
1027
+ else if (type == 2) {
1028
+ var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
1029
+ var tl = hLit + bits(dat, pos + 5, 31) + 1;
1030
+ pos += 14;
1031
+ var ldt = new u8(tl);
1032
+ var clt = new u8(19);
1033
+ for (var i = 0; i < hcLen; ++i) clt[clim[i]] = bits(dat, pos + i * 3, 7);
1034
+ pos += hcLen * 3;
1035
+ var clb = max(clt), clbmsk = (1 << clb) - 1;
1036
+ var clm = hMap(clt, clb, 1);
1037
+ for (var i = 0; i < tl;) {
1038
+ var r = clm[bits(dat, pos, clbmsk)];
1039
+ pos += r & 15;
1040
+ var s = r >> 4;
1041
+ if (s < 16) ldt[i++] = s;
1042
+ else {
1043
+ var c = 0, n = 0;
1044
+ if (s == 16) n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];
1045
+ else if (s == 17) n = 3 + bits(dat, pos, 7), pos += 3;
1046
+ else if (s == 18) n = 11 + bits(dat, pos, 127), pos += 7;
1047
+ while (n--) ldt[i++] = c;
1048
+ }
1049
+ }
1050
+ var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
1051
+ lbt = max(lt);
1052
+ dbt = max(dt);
1053
+ lm = hMap(lt, lbt, 1);
1054
+ dm = hMap(dt, dbt, 1);
1055
+ } else err(1);
1056
+ if (pos > tbts) {
1057
+ if (noSt) err(0);
1058
+ break;
1059
+ }
1060
+ }
1061
+ if (resize) cbuf(bt + 131072);
1062
+ var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
1063
+ var lpos = pos;
1064
+ for (;; lpos = pos) {
1065
+ var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
1066
+ pos += c & 15;
1067
+ if (pos > tbts) {
1068
+ if (noSt) err(0);
1069
+ break;
1070
+ }
1071
+ if (!c) err(2);
1072
+ if (sym < 256) buf[bt++] = sym;
1073
+ else if (sym == 256) {
1074
+ lpos = pos, lm = null;
1075
+ break;
1076
+ } else {
1077
+ var add = sym - 254;
1078
+ if (sym > 264) {
1079
+ var i = sym - 257, b = fleb[i];
1080
+ add = bits(dat, pos, (1 << b) - 1) + fl[i];
1081
+ pos += b;
1082
+ }
1083
+ var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
1084
+ if (!d) err(3);
1085
+ pos += d & 15;
1086
+ var dt = fd[dsym];
1087
+ if (dsym > 3) {
1088
+ var b = fdeb[dsym];
1089
+ dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
1090
+ }
1091
+ if (pos > tbts) {
1092
+ if (noSt) err(0);
1093
+ break;
1094
+ }
1095
+ if (resize) cbuf(bt + 131072);
1096
+ var end = bt + add;
1097
+ if (bt < dt) {
1098
+ var shift = dl - dt, dend = Math.min(dt, end);
1099
+ if (shift + bt < 0) err(3);
1100
+ for (; bt < dend; ++bt) buf[bt] = dict[shift + bt];
1101
+ }
1102
+ for (; bt < end; ++bt) buf[bt] = buf[bt - dt];
1103
+ }
1104
+ }
1105
+ st.l = lm, st.p = lpos, st.b = bt, st.f = final;
1106
+ if (lm) final = 1, st.m = lbt, st.d = dm, st.n = dbt;
1107
+ } while (!final);
1108
+ return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
1109
+ };
1110
+ var et = /* @__PURE__ */ new u8(0);
1111
+ var gzs = function(d) {
1112
+ if (d[0] != 31 || d[1] != 139 || d[2] != 8) err(6, "invalid gzip data");
1113
+ var flg = d[3];
1114
+ var st = 10;
1115
+ if (flg & 4) st += (d[10] | d[11] << 8) + 2;
1116
+ for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++]);
1117
+ return st + (flg & 2);
1118
+ };
1119
+ var gzl = function(d) {
1120
+ var l = d.length;
1121
+ return (d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16 | d[l - 1] << 24) >>> 0;
1122
+ };
1123
+ /**
1124
+ * Expands GZIP data
1125
+ * @param data The data to decompress
1126
+ * @param opts The decompression options
1127
+ * @returns The decompressed version of the data
1128
+ */
1129
+ function gunzipSync(data, opts) {
1130
+ var st = gzs(data);
1131
+ if (st + 8 > data.length) err(6, "invalid gzip data");
1132
+ return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary);
1133
+ }
1134
+ var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
1135
+ try {
1136
+ td.decode(et, { stream: true });
1137
+ } catch (e) {}
1138
+ //#endregion
1139
+ //#region src/utils/tileset-structure-uri.ts
1140
+ /** 从 tileset 取内嵌 structure 的 data URI(优先 MapTalks:`asset.extras.maptalks.structureUri`) */
1141
+ function getStructureDataUriFromTileset(root) {
1142
+ if (!root) return null;
1143
+ const maptalks = (root.asset?.extras)?.maptalks;
1144
+ if (maptalks && typeof maptalks === "object") {
1145
+ const uri = maptalks.structureUri;
1146
+ if (typeof uri === "string" && uri.trim()) return uri.trim();
1147
+ }
1148
+ const legacy = root.structureUri;
1149
+ if (typeof legacy === "string" && legacy.trim()) return legacy.trim();
1150
+ return null;
1151
+ }
1152
+ function base64ToUint8Array(b64) {
1153
+ const clean = b64.replace(/\s/g, "");
1154
+ if (typeof globalThis.atob === "function") {
1155
+ const bin = globalThis.atob(clean);
1156
+ const out = new Uint8Array(bin.length);
1157
+ for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
1158
+ return out;
1159
+ }
1160
+ if (typeof Buffer !== "undefined") return new Uint8Array(Buffer.from(clean, "base64"));
1161
+ throw new Error("[tileset-structure-uri] No base64 decoder available");
1162
+ }
1163
+ /**
1164
+ * 同步解析 `data:application/x-gzip;base64,...`:base64 → 二进制 → gunzip → UTF-8 文本。
1165
+ */
1166
+ function decodeGzipBase64DataUriSync(dataUri) {
1167
+ const comma = dataUri.indexOf(",");
1168
+ if (comma < 0) throw new Error("[tileset-structure-uri] Invalid data URI: missing comma");
1169
+ if (!dataUri.slice(0, comma).toLowerCase().includes("base64")) throw new Error("[tileset-structure-uri] Expected base64 data URI (e.g. data:application/x-gzip;base64,...)");
1170
+ const raw = gunzipSync(base64ToUint8Array(dataUri.slice(comma + 1)));
1171
+ return new TextDecoder("utf-8").decode(raw);
1172
+ }
1173
+ /**
1174
+ * 从已加载的根 tileset 读取内嵌 structure(`asset.extras.maptalks.structureUri`,
1175
+ * 若无则回退根级 `structureUri`),同步解码并解析。
1176
+ * - 无有效 URI 或解析失败时返回 `null`(不抛错)。
1177
+ */
1178
+ function parseEmbeddedStructureDataFromTilesSync(tiles) {
1179
+ const uri = getStructureDataUriFromTileset(tiles.rootTileset);
1180
+ if (!uri) return null;
1181
+ try {
1182
+ const text = decodeGzipBase64DataUriSync(uri);
1183
+ return JSON.parse(text);
1184
+ } catch (e) {
1185
+ console.warn("[GLTFParserPlugin] Failed to decode tileset structureUri:", e);
1186
+ return null;
1187
+ }
1188
+ }
1189
+ //#endregion
1190
+ //#region node_modules/.pnpm/3d-tiles-renderer@0.4.23_three@0.183.2/node_modules/3d-tiles-renderer/build/constants-D7SEibTb.js
623
1191
  var N = 6378137;
624
1192
  //#endregion
625
1193
  //#region node_modules/.pnpm/three@0.183.2/node_modules/three/examples/jsm/postprocessing/Pass.js
@@ -700,22 +1268,22 @@ var FullScreenQuad = class {
700
1268
  function q(a, e, t) {
701
1269
  return a && e in a ? a[e] : t;
702
1270
  }
703
- function bn(a) {
1271
+ function An(a) {
704
1272
  return a !== "BOOLEAN" && a !== "STRING" && a !== "ENUM";
705
1273
  }
706
- function Vi(a) {
1274
+ function qi(a) {
707
1275
  return /^FLOAT/.test(a);
708
1276
  }
709
- function Ve(a) {
1277
+ function He(a) {
710
1278
  return /^VEC/.test(a);
711
1279
  }
712
- function Fe(a) {
1280
+ function qe(a) {
713
1281
  return /^MAT/.test(a);
714
1282
  }
715
- function _n(a, e, t, s = null) {
716
- return Fe(t) || Ve(t) ? s.fromArray(a, e) : a[e];
1283
+ function In(a, e, t, s = null) {
1284
+ return qe(t) || He(t) ? s.fromArray(a, e) : a[e];
717
1285
  }
718
- function Vt(a) {
1286
+ function Gt(a) {
719
1287
  const { type: e, componentType: t } = a;
720
1288
  switch (e) {
721
1289
  case "SCALAR": return t === "INT64" ? 0n : 0;
@@ -730,7 +1298,7 @@ function Vt(a) {
730
1298
  case "ENUM": return 0;
731
1299
  }
732
1300
  }
733
- function ys(a, e) {
1301
+ function Ts(a, e) {
734
1302
  if (e == null) return !1;
735
1303
  switch (a) {
736
1304
  case "SCALAR": return typeof e == "number" || typeof e == "bigint";
@@ -746,7 +1314,7 @@ function ys(a, e) {
746
1314
  }
747
1315
  throw new Error("ClassProperty: invalid type.");
748
1316
  }
749
- function De(a, e = null) {
1317
+ function Fe(a, e = null) {
750
1318
  switch (a) {
751
1319
  case "INT8": return Int8Array;
752
1320
  case "INT16": return Int16Array;
@@ -765,16 +1333,16 @@ function De(a, e = null) {
765
1333
  }
766
1334
  throw new Error("ClassProperty: invalid type.");
767
1335
  }
768
- function Fi(a, e = null) {
1336
+ function Wi(a, e = null) {
769
1337
  if (a.array) {
770
1338
  e = e && Array.isArray(e) ? e : [], e.length = a.count;
771
- for (let s = 0, n = e.length; s < n; s++) e[s] = nt(a, e[s]);
772
- } else e = nt(a, e);
1339
+ for (let s = 0, n = e.length; s < n; s++) e[s] = at(a, e[s]);
1340
+ } else e = at(a, e);
773
1341
  return e;
774
1342
  }
775
- function nt(a, e = null) {
1343
+ function at(a, e = null) {
776
1344
  const t = a.default, s = a.type;
777
- if (e = e || Vt(a), t === null) {
1345
+ if (e = e || Gt(a), t === null) {
778
1346
  switch (s) {
779
1347
  case "SCALAR": return 0;
780
1348
  case "VEC2": return e.set(0, 0);
@@ -788,31 +1356,31 @@ function nt(a, e = null) {
788
1356
  case "ENUM": return "";
789
1357
  }
790
1358
  throw new Error("ClassProperty: invalid type.");
791
- } else if (Fe(s)) e.fromArray(t);
792
- else if (Ve(s)) e.fromArray(t);
1359
+ } else if (qe(s)) e.fromArray(t);
1360
+ else if (He(s)) e.fromArray(t);
793
1361
  else return t;
794
1362
  }
795
- function ki(a, e) {
1363
+ function ji(a, e) {
796
1364
  if (a.noData === null) return e;
797
1365
  const t = a.noData, s = a.type;
798
1366
  if (Array.isArray(e)) for (let r = 0, o = e.length; r < o; r++) e[r] = n(e[r]);
799
1367
  else e = n(e);
800
1368
  return e;
801
1369
  function n(r) {
802
- return i(r) && (r = nt(a, r)), r;
1370
+ return i(r) && (r = at(a, r)), r;
803
1371
  }
804
1372
  function i(r) {
805
- if (Fe(s)) {
1373
+ if (qe(s)) {
806
1374
  const o = r.elements;
807
1375
  for (let l = 0, c = t.length; l < c; l++) if (t[l] !== o[l]) return !1;
808
1376
  return !0;
809
- } else if (Ve(s)) {
1377
+ } else if (He(s)) {
810
1378
  for (let o = 0, l = t.length; o < l; o++) if (t[o] !== r.getComponent(o)) return !1;
811
1379
  return !0;
812
1380
  } else return t === r;
813
1381
  }
814
1382
  }
815
- function Gi(a, e) {
1383
+ function Xi(a, e) {
816
1384
  switch (a) {
817
1385
  case "INT8": return Math.max(e / 127, -1);
818
1386
  case "INT16": return Math.max(e, 32767, -1);
@@ -824,13 +1392,13 @@ function Gi(a, e) {
824
1392
  case "UINT64": return Number(e) / 0x10000000000000000;
825
1393
  }
826
1394
  }
827
- function zi(a, e) {
1395
+ function Yi(a, e) {
828
1396
  const { type: t, componentType: s, scale: n, offset: i, normalized: r } = a;
829
1397
  if (Array.isArray(e)) for (let h = 0, d = e.length; h < d; h++) e[h] = o(e[h]);
830
1398
  else e = o(e);
831
1399
  return e;
832
1400
  function o(h) {
833
- return Fe(t) ? h = c(h) : Ve(t) ? h = l(h) : h = u(h), h;
1401
+ return qe(t) ? h = c(h) : He(t) ? h = l(h) : h = u(h), h;
834
1402
  }
835
1403
  function l(h) {
836
1404
  return h.x = u(h.x), h.y = u(h.y), "z" in h && (h.z = u(h.z)), "w" in h && (h.w = u(h.w)), h;
@@ -841,24 +1409,24 @@ function zi(a, e) {
841
1409
  return h;
842
1410
  }
843
1411
  function u(h) {
844
- return r && (h = Gi(s, h)), (r || Vi(s)) && (h = h * n + i), h;
1412
+ return r && (h = Xi(s, h)), (r || qi(s)) && (h = h * n + i), h;
845
1413
  }
846
1414
  }
847
- function $t(a, e, t = null) {
1415
+ function Zt(a, e, t = null) {
848
1416
  if (a.array) {
849
1417
  Array.isArray(e) || (e = new Array(a.count || 0)), e.length = t !== null ? t : a.count;
850
- for (let s = 0, n = e.length; s < n; s++) ys(a.type, e[s]) || (e[s] = Vt(a));
851
- } else ys(a.type, e) || (e = Vt(a));
1418
+ for (let s = 0, n = e.length; s < n; s++) Ts(a.type, e[s]) || (e[s] = Gt(a));
1419
+ } else Ts(a.type, e) || (e = Gt(a));
852
1420
  return e;
853
1421
  }
854
- function it(a, e) {
1422
+ function lt(a, e) {
855
1423
  for (const t in e) t in a || delete e[t];
856
1424
  for (const t in a) {
857
1425
  const s = a[t];
858
- e[t] = $t(s, e[t]);
1426
+ e[t] = Zt(s, e[t]);
859
1427
  }
860
1428
  }
861
- function Hi(a) {
1429
+ function $i(a) {
862
1430
  switch (a) {
863
1431
  case "ENUM": return 1;
864
1432
  case "SCALAR": return 1;
@@ -873,21 +1441,21 @@ function Hi(a) {
873
1441
  default: return -1;
874
1442
  }
875
1443
  }
876
- var ht = class {
1444
+ var mt = class {
877
1445
  constructor(e, t, s = null) {
878
1446
  this.name = t.name || null, this.description = t.description || null, this.type = t.type, this.componentType = t.componentType || null, this.enumType = t.enumType || null, this.array = t.array || !1, this.count = t.count || 0, this.normalized = t.normalized || !1, this.offset = t.offset || 0, this.scale = q(t, "scale", 1), this.max = q(t, "max", Infinity), this.min = q(t, "min", -Infinity), this.required = t.required || !1, this.noData = q(t, "noData", null), this.default = q(t, "default", null), this.semantic = q(t, "semantic", null), this.enumSet = null, this.accessorProperty = s, s && (this.offset = q(s, "offset", this.offset), this.scale = q(s, "scale", this.scale), this.max = q(s, "max", this.max), this.min = q(s, "min", this.min)), t.type === "ENUM" && (this.enumSet = e[this.enumType], this.componentType === null && (this.componentType = q(this.enumSet, "valueType", "UINT16")));
879
1447
  }
880
1448
  shapeToProperty(e, t = null) {
881
- return $t(this, e, t);
1449
+ return Zt(this, e, t);
882
1450
  }
883
1451
  resolveDefaultElement(e) {
884
- return nt(this, e);
1452
+ return at(this, e);
885
1453
  }
886
1454
  resolveDefault(e) {
887
- return Fi(this, e);
1455
+ return Wi(this, e);
888
1456
  }
889
1457
  resolveNoData(e) {
890
- return ki(this, e);
1458
+ return ji(this, e);
891
1459
  }
892
1460
  resolveEnumsToStrings(e) {
893
1461
  const t = this.enumSet;
@@ -900,10 +1468,10 @@ var ht = class {
900
1468
  }
901
1469
  }
902
1470
  adjustValueScaleOffset(e) {
903
- return bn(this.type) ? zi(this, e) : e;
1471
+ return An(this.type) ? Yi(this, e) : e;
904
1472
  }
905
1473
  };
906
- var Qt = class {
1474
+ var Jt = class {
907
1475
  constructor(e, t = {}, s = {}, n = null) {
908
1476
  this.definition = e, this.class = t[e.class], this.className = e.class, this.enums = s, this.data = n, this.name = "name" in e ? e.name : null, this.properties = null;
909
1477
  }
@@ -914,24 +1482,24 @@ var Qt = class {
914
1482
  return !!this.definition.properties[e];
915
1483
  }
916
1484
  dispose() {}
917
- _initProperties(e = ht) {
1485
+ _initProperties(e = mt) {
918
1486
  const t = {};
919
1487
  for (const s in this.class.properties) t[s] = new e(this.enums, this.class.properties[s], this.definition.properties[s]);
920
1488
  this.properties = t;
921
1489
  }
922
1490
  };
923
- var qi = class extends ht {
1491
+ var Qi = class extends mt {
924
1492
  constructor(e, t, s = null) {
925
1493
  super(e, t, s), this.attribute = (s == null ? void 0 : s.attribute) ?? null;
926
1494
  }
927
1495
  };
928
- var Wi = class extends Qt {
1496
+ var Zi = class extends Jt {
929
1497
  constructor(...e) {
930
- super(...e), this.isPropertyAttributeAccessor = !0, this._initProperties(qi);
1498
+ super(...e), this.isPropertyAttributeAccessor = !0, this._initProperties(Qi);
931
1499
  }
932
1500
  getData(e, t, s = {}) {
933
1501
  const n = this.properties;
934
- it(n, s);
1502
+ lt(n, s);
935
1503
  for (const i in n) s[i] = this.getPropertyValue(i, e, t, s[i]);
936
1504
  return s;
937
1505
  }
@@ -943,23 +1511,23 @@ var Wi = class extends Qt {
943
1511
  } else throw new Error("PropertyAttributeAccessor: Requested class property does not exist.");
944
1512
  n = i.shapeToProperty(n);
945
1513
  const o = s.getAttribute(i.attribute.toLowerCase());
946
- if (Fe(r)) {
1514
+ if (qe(r)) {
947
1515
  const l = n.elements;
948
1516
  for (let c = 0, u = l.length; c < u;) l[c] = o.getComponent(t, c);
949
- } else if (Ve(r)) n.fromBufferAttribute(o, t);
1517
+ } else if (He(r)) n.fromBufferAttribute(o, t);
950
1518
  else if (r === "SCALAR" || r === "ENUM") n = o.getX(t);
951
1519
  else throw new Error("StructuredMetadata.PropertyAttributeAccessor: BOOLEAN and STRING types are not supported by property attributes.");
952
1520
  return n = i.adjustValueScaleOffset(n), n = i.resolveEnumsToStrings(n), n = i.resolveNoData(n), n;
953
1521
  }
954
1522
  };
955
- var ji = class extends ht {
1523
+ var Ji = class extends mt {
956
1524
  constructor(e, t, s = null) {
957
- super(e, t, s), this.values = (s == null ? void 0 : s.values) ?? null, this.valueLength = Hi(this.type), this.arrayOffsets = q(s, "arrayOffsets", null), this.stringOffsets = q(s, "stringOffsets", null), this.arrayOffsetType = q(s, "arrayOffsetType", "UINT32"), this.stringOffsetType = q(s, "stringOffsetType", "UINT32");
1525
+ super(e, t, s), this.values = (s == null ? void 0 : s.values) ?? null, this.valueLength = $i(this.type), this.arrayOffsets = q(s, "arrayOffsets", null), this.stringOffsets = q(s, "stringOffsets", null), this.arrayOffsetType = q(s, "arrayOffsetType", "UINT32"), this.stringOffsetType = q(s, "stringOffsetType", "UINT32");
958
1526
  }
959
1527
  getArrayLengthFromId(e, t) {
960
1528
  let s = this.count;
961
1529
  if (this.arrayOffsets !== null) {
962
- const { arrayOffsets: n, arrayOffsetType: i } = this, o = new (De(i))(e[n]);
1530
+ const { arrayOffsets: n, arrayOffsetType: i } = this, o = new (Fe(i))(e[n]);
963
1531
  s = o[t + 1] - o[t];
964
1532
  }
965
1533
  return s;
@@ -968,29 +1536,29 @@ var ji = class extends ht {
968
1536
  let s = t;
969
1537
  if (this.arrayOffsets) {
970
1538
  const { arrayOffsets: n, arrayOffsetType: i } = this;
971
- s = new (De(i))(e[n])[s];
1539
+ s = new (Fe(i))(e[n])[s];
972
1540
  } else this.array && (s *= this.count);
973
1541
  return s;
974
1542
  }
975
1543
  };
976
- var Yi = class extends Qt {
1544
+ var Ki = class extends Jt {
977
1545
  constructor(...e) {
978
- super(...e), this.isPropertyTableAccessor = !0, this.count = this.definition.count, this._initProperties(ji);
1546
+ super(...e), this.isPropertyTableAccessor = !0, this.count = this.definition.count, this._initProperties(Ji);
979
1547
  }
980
1548
  getData(e, t = {}) {
981
1549
  const s = this.properties;
982
- it(s, t);
1550
+ lt(s, t);
983
1551
  for (const n in s) t[n] = this.getPropertyValue(n, e, t[n]);
984
1552
  return t;
985
1553
  }
986
1554
  _readValueAtIndex(e, t, s, n = null) {
987
- const i = this.properties[e], { componentType: r, type: o } = i, l = this.data, c = l[i.values], h = new (De(r, o))(c), d = i.getIndexOffsetFromId(l, t);
988
- if (bn(o) || o === "ENUM") return _n(h, (d + s) * i.valueLength, o, n);
1555
+ const i = this.properties[e], { componentType: r, type: o } = i, l = this.data, c = l[i.values], h = new (Fe(r, o))(c), d = i.getIndexOffsetFromId(l, t);
1556
+ if (An(o) || o === "ENUM") return In(h, (d + s) * i.valueLength, o, n);
989
1557
  if (o === "STRING") {
990
1558
  let m = d + s, f = 0;
991
1559
  if (i.stringOffsets !== null) {
992
- const { stringOffsets: g, stringOffsetType: y } = i, S = new (De(y))(l[g]);
993
- f = S[m + 1] - S[m], m = S[m];
1560
+ const { stringOffsets: g, stringOffsetType: y } = i, b = new (Fe(y))(l[g]);
1561
+ f = b[m + 1] - b[m], m = b[m];
994
1562
  }
995
1563
  const p = new Uint8Array(h.buffer, m, f);
996
1564
  n = new TextDecoder().decode(p);
@@ -1012,8 +1580,8 @@ var Yi = class extends Qt {
1012
1580
  return s = n.adjustValueScaleOffset(s), s = n.resolveEnumsToStrings(s), s = n.resolveNoData(s), s;
1013
1581
  }
1014
1582
  };
1015
- var ve = /* @__PURE__ */ new Box2();
1016
- var xs = class {
1583
+ var Pe = /* @__PURE__ */ new Box2();
1584
+ var bs = class {
1017
1585
  constructor() {
1018
1586
  this._renderer = new WebGLRenderer(), this._target = new WebGLRenderTarget(1, 1), this._texTarget = new WebGLRenderTarget(), this._quad = new FullScreenQuad(new ShaderMaterial({
1019
1587
  blending: CustomBlending,
@@ -1055,56 +1623,56 @@ var xs = class {
1055
1623
  }
1056
1624
  renderPixelToTarget(e, t, s) {
1057
1625
  const { _renderer: n, _target: i } = this;
1058
- ve.min.copy(t), ve.max.copy(t), ve.max.x += 1, ve.max.y += 1, n.initRenderTarget(i), n.copyTextureToTexture(e, i.texture, ve, s, 0);
1626
+ Pe.min.copy(t), Pe.max.copy(t), Pe.max.x += 1, Pe.max.y += 1, n.initRenderTarget(i), n.copyTextureToTexture(e, i.texture, Pe, s, 0);
1059
1627
  }
1060
1628
  };
1061
- var he = /* @__PURE__ */ new class {
1629
+ var de = /* @__PURE__ */ new class {
1062
1630
  constructor() {
1063
1631
  let a = null;
1064
- Object.getOwnPropertyNames(xs.prototype).forEach((e) => {
1065
- e !== "constructor" && (this[e] = (...t) => (a = a || new xs(), a[e](...t)));
1632
+ Object.getOwnPropertyNames(bs.prototype).forEach((e) => {
1633
+ e !== "constructor" && (this[e] = (...t) => (a = a || new bs(), a[e](...t)));
1066
1634
  });
1067
1635
  }
1068
- }(), Ts = /* @__PURE__ */ new Vector2(), bs = /* @__PURE__ */ new Vector2(), _s = /* @__PURE__ */ new Vector2();
1069
- function Xi(a, e) {
1636
+ }(), _s = /* @__PURE__ */ new Vector2(), Ss = /* @__PURE__ */ new Vector2(), Ms = /* @__PURE__ */ new Vector2();
1637
+ function er(a, e) {
1070
1638
  return e === 0 ? a.getAttribute("uv") : a.getAttribute(`uv${e}`);
1071
1639
  }
1072
- function Sn(a, e, t = new Array(3)) {
1640
+ function vn(a, e, t = new Array(3)) {
1073
1641
  let s = 3 * e, n = 3 * e + 1, i = 3 * e + 2;
1074
1642
  return a.index && (s = a.index.getX(s), n = a.index.getX(n), i = a.index.getX(i)), t[0] = s, t[1] = n, t[2] = i, t;
1075
1643
  }
1076
- function Mn(a, e, t, s, n) {
1077
- const [i, r, o] = s, l = Xi(a, e);
1078
- Ts.fromBufferAttribute(l, i), bs.fromBufferAttribute(l, r), _s.fromBufferAttribute(l, o), n.set(0, 0, 0).addScaledVector(Ts, t.x).addScaledVector(bs, t.y).addScaledVector(_s, t.z);
1644
+ function Ln(a, e, t, s, n) {
1645
+ const [i, r, o] = s, l = er(a, e);
1646
+ _s.fromBufferAttribute(l, i), Ss.fromBufferAttribute(l, r), Ms.fromBufferAttribute(l, o), n.set(0, 0, 0).addScaledVector(_s, t.x).addScaledVector(Ss, t.y).addScaledVector(Ms, t.z);
1079
1647
  }
1080
- function Cn(a, e, t, s) {
1648
+ function En(a, e, t, s) {
1081
1649
  const n = a.x - Math.floor(a.x), i = a.y - Math.floor(a.y), r = Math.floor(n * e % e), o = Math.floor(i * t % t);
1082
1650
  return s.set(r, o), s;
1083
1651
  }
1084
- var Ss = /* @__PURE__ */ new Vector2(), Ms = /* @__PURE__ */ new Vector2(), Cs = /* @__PURE__ */ new Vector2();
1085
- var $i = class extends ht {
1652
+ var Cs = /* @__PURE__ */ new Vector2(), As = /* @__PURE__ */ new Vector2(), Is = /* @__PURE__ */ new Vector2();
1653
+ var tr = class extends mt {
1086
1654
  constructor(e, t, s = null) {
1087
1655
  super(e, t, s), this.channels = q(s, "channels", [0]), this.index = q(s, "index", null), this.texCoord = q(s, "texCoord", null), this.valueLength = parseInt(this.type.replace(/[^0-9]/g, "")) || 1;
1088
1656
  }
1089
1657
  readDataFromBuffer(e, t, s = null) {
1090
1658
  const n = this.type;
1091
1659
  if (n === "BOOLEAN" || n === "STRING") throw new Error("PropertyTextureAccessor: BOOLEAN and STRING types not supported.");
1092
- return _n(e, t * this.valueLength, n, s);
1660
+ return In(e, t * this.valueLength, n, s);
1093
1661
  }
1094
1662
  };
1095
- var Qi = class extends Qt {
1663
+ var sr = class extends Jt {
1096
1664
  constructor(...e) {
1097
- super(...e), this.isPropertyTextureAccessor = !0, this._asyncRead = !1, this._initProperties($i);
1665
+ super(...e), this.isPropertyTextureAccessor = !0, this._asyncRead = !1, this._initProperties(tr);
1098
1666
  }
1099
1667
  getData(e, t, s, n = {}) {
1100
1668
  const i = this.properties;
1101
- it(i, n);
1669
+ lt(i, n);
1102
1670
  const r = Object.keys(i), o = r.map((l) => n[l]);
1103
1671
  return this.getPropertyValuesAtTexel(r, e, t, s, o), r.forEach((l, c) => n[l] = o[c]), n;
1104
1672
  }
1105
1673
  async getDataAsync(e, t, s, n = {}) {
1106
1674
  const i = this.properties;
1107
- it(i, n);
1675
+ lt(i, n);
1108
1676
  const r = Object.keys(i), o = r.map((l) => n[l]);
1109
1677
  return await this.getPropertyValuesAtTexelAsync(r, e, t, s, o), r.forEach((l, c) => n[l] = o[c]), n;
1110
1678
  }
@@ -1115,30 +1683,30 @@ var Qi = class extends Qt {
1115
1683
  }
1116
1684
  getPropertyValuesAtTexel(e, t, s, n, i = []) {
1117
1685
  for (; i.length < e.length;) i.push(null);
1118
- i.length = e.length, he.increaseSizeTo(i.length);
1119
- const r = this.data, o = this.definition.properties, l = this.properties, c = Sn(n, t);
1686
+ i.length = e.length, de.increaseSizeTo(i.length);
1687
+ const r = this.data, o = this.definition.properties, l = this.properties, c = vn(n, t);
1120
1688
  for (let d = 0, m = e.length; d < m; d++) {
1121
1689
  const f = e[d];
1122
1690
  if (!o[f]) continue;
1123
1691
  const p = l[f], g = r[p.index];
1124
- Mn(n, p.texCoord, s, c, Ss), Cn(Ss, g.image.width, g.image.height, Ms), Cs.set(d, 0), he.renderPixelToTarget(g, Ms, Cs);
1692
+ Ln(n, p.texCoord, s, c, Cs), En(Cs, g.image.width, g.image.height, As), Is.set(d, 0), de.renderPixelToTarget(g, As, Is);
1125
1693
  }
1126
1694
  const u = new Uint8Array(e.length * 4);
1127
- if (this._asyncRead) return he.readDataAsync(u).then(() => (h.call(this), i));
1128
- return he.readData(u), h.call(this), i;
1695
+ if (this._asyncRead) return de.readDataAsync(u).then(() => (h.call(this), i));
1696
+ return de.readData(u), h.call(this), i;
1129
1697
  function h() {
1130
1698
  for (let d = 0, m = e.length; d < m; d++) {
1131
1699
  const f = e[d], p = l[f], g = p.type;
1132
- if (i[d] = $t(p, i[d]), p) {
1700
+ if (i[d] = Zt(p, i[d]), p) {
1133
1701
  if (!o[f]) {
1134
1702
  i[d] = p.resolveDefault(i);
1135
1703
  continue;
1136
1704
  }
1137
1705
  } else throw new Error("PropertyTextureAccessor: Requested property does not exist.");
1138
- const y = p.valueLength * (p.count || 1), x = p.channels.map((_) => u[4 * d + _]), S = p.componentType, M = new (De(S, g))(y);
1706
+ const y = p.valueLength * (p.count || 1), x = p.channels.map((S) => u[4 * d + S]), b = p.componentType, M = new (Fe(b, g))(y);
1139
1707
  if (new Uint8Array(M.buffer).set(x), p.array) {
1140
- const _ = i[d];
1141
- for (let C = 0, v = _.length; C < v; C++) _[C] = p.readDataFromBuffer(M, C, _[C]);
1708
+ const S = i[d];
1709
+ for (let C = 0, v = S.length; C < v; C++) S[C] = p.readDataFromBuffer(M, C, S[C]);
1142
1710
  } else i[d] = p.readDataFromBuffer(M, 0, i[d]);
1143
1711
  i[d] = p.adjustValueScaleOffset(i[d]), i[d] = p.resolveEnumsToStrings(i[d]), i[d] = p.resolveNoData(i[d]);
1144
1712
  }
@@ -1150,25 +1718,37 @@ var Qi = class extends Qt {
1150
1718
  });
1151
1719
  }
1152
1720
  };
1153
- var As = class {
1721
+ var vs = class {
1154
1722
  constructor(e, t, s, n = null, i = null) {
1155
- const { schema: r, propertyTables: o = [], propertyTextures: l = [], propertyAttributes: c = [] } = e, { enums: u, classes: h } = r, d = o.map((p) => new Yi(p, h, u, s));
1723
+ const { schema: r, propertyTables: o = [], propertyTextures: l = [], propertyAttributes: c = [] } = e, { enums: u, classes: h } = r, d = o.map((p) => new Ki(p, h, u, s));
1156
1724
  let m = [], f = [];
1157
- n && (n.propertyTextures && (m = n.propertyTextures.map((p) => new Qi(l[p], h, u, t))), n.propertyAttributes && (f = n.propertyAttributes.map((p) => new Wi(c[p], h, u)))), this.schema = r, this.tableAccessors = d, this.textureAccessors = m, this.attributeAccessors = f, this.object = i, this.textures = t, this.nodeMetadata = n;
1725
+ n && (n.propertyTextures && (m = n.propertyTextures.map((p) => new sr(l[p], h, u, t))), n.propertyAttributes && (f = n.propertyAttributes.map((p) => new Zi(c[p], h, u)))), this.schema = r, this.tableAccessors = d, this.textureAccessors = m, this.attributeAccessors = f, this.object = i, this.textures = t, this.nodeMetadata = n;
1158
1726
  }
1727
+ /**
1728
+ * Returns data from one or more property tables. Pass a single table index and row ID to
1729
+ * get one object, or parallel arrays of table indices and row IDs to get an array of
1730
+ * results. Each returned object conforms to the structure class referenced in the schema.
1731
+ * @param {number|Array<number>} tableIndices Table index or array of table indices.
1732
+ * @param {number|Array<number>} ids Row ID or array of row IDs.
1733
+ * @param {Object|Array|null} [target=null] Optional target object or array to write into.
1734
+ * @returns {Object|Array}
1735
+ */
1159
1736
  getPropertyTableData(e, t, s = null) {
1160
1737
  if (!Array.isArray(e) || !Array.isArray(t)) s = s || {}, s = this.tableAccessors[e].getData(t, s);
1161
1738
  else {
1162
1739
  s = s || [];
1163
1740
  const n = Math.min(e.length, t.length);
1164
1741
  s.length = n;
1165
- for (let i = 0; i < n; i++) {
1166
- const r = this.tableAccessors[e[i]];
1167
- s[i] = r.getData(t[i], s[i]);
1168
- }
1742
+ for (let i = 0; i < n; i++) s[i] = this.tableAccessors[e[i]].getData(t[i], s[i]);
1169
1743
  }
1170
1744
  return s;
1171
1745
  }
1746
+ /**
1747
+ * Returns name and class information for one or more property tables. Defaults to all
1748
+ * tables when `tableIndices` is `null`.
1749
+ * @param {Array<number>|null} [tableIndices=null]
1750
+ * @returns {Array<{name: string, className: string}>|{name: string, className: string}}
1751
+ */
1172
1752
  getPropertyTableInfo(e = null) {
1173
1753
  if (e === null && (e = this.tableAccessors.map((t, s) => s)), Array.isArray(e)) return e.map((t) => {
1174
1754
  const s = this.tableAccessors[t];
@@ -1185,12 +1765,29 @@ var As = class {
1185
1765
  };
1186
1766
  }
1187
1767
  }
1768
+ /**
1769
+ * Returns data from property textures at the given point on the mesh. Takes the triangle
1770
+ * index and barycentric coordinate from a raycast result. See `MeshFeatures.getFeatures`
1771
+ * for how to obtain these values.
1772
+ * @param {number} triangle Triangle index from a raycast hit.
1773
+ * @param {Vector3} barycoord Barycentric coordinate of the hit point.
1774
+ * @param {Array} [target=[]] Optional target array to write into.
1775
+ * @returns {Array}
1776
+ */
1188
1777
  getPropertyTextureData(e, t, s = []) {
1189
1778
  const n = this.textureAccessors;
1190
1779
  s.length = n.length;
1191
1780
  for (let i = 0; i < n.length; i++) s[i] = n[i].getData(e, t, this.object.geometry, s[i]);
1192
1781
  return s;
1193
1782
  }
1783
+ /**
1784
+ * Returns the same data as `getPropertyTextureData` but performs texture reads
1785
+ * asynchronously.
1786
+ * @param {number} triangle Triangle index from a raycast hit.
1787
+ * @param {Vector3} barycoord Barycentric coordinate of the hit point.
1788
+ * @param {Array} [target=[]] Optional target array to write into.
1789
+ * @returns {Promise<Array>}
1790
+ */
1194
1791
  async getPropertyTextureDataAsync(e, t, s = []) {
1195
1792
  const n = this.textureAccessors;
1196
1793
  s.length = n.length;
@@ -1203,30 +1800,48 @@ var As = class {
1203
1800
  }
1204
1801
  return await Promise.all(i), s;
1205
1802
  }
1803
+ /**
1804
+ * Returns information about the property texture accessors, including their class names
1805
+ * and per-property channel/texcoord mappings.
1806
+ * @returns {Array<{name: string, className: string, properties: Object}>}
1807
+ */
1206
1808
  getPropertyTextureInfo() {
1207
1809
  return this.textureAccessors;
1208
1810
  }
1811
+ /**
1812
+ * Returns data stored as property attributes for the given vertex index.
1813
+ * @param {number} attributeIndex Vertex index.
1814
+ * @param {Array} [target=[]] Optional target array to write into.
1815
+ * @returns {Array}
1816
+ */
1209
1817
  getPropertyAttributeData(e, t = []) {
1210
1818
  const s = this.attributeAccessors;
1211
1819
  t.length = s.length;
1212
1820
  for (let n = 0; n < s.length; n++) t[n] = s[n].getData(e, this.object.geometry, t[n]);
1213
1821
  return t;
1214
1822
  }
1823
+ /**
1824
+ * Returns name and class information for all property attribute accessors.
1825
+ * @returns {Array<{name: string, className: string}>}
1826
+ */
1215
1827
  getPropertyAttributeInfo() {
1216
1828
  return this.attributeAccessors.map((e) => ({
1217
1829
  name: e.name,
1218
1830
  className: e.definition.class
1219
1831
  }));
1220
1832
  }
1833
+ /**
1834
+ * Disposes all texture, table, and attribute accessors.
1835
+ */
1221
1836
  dispose() {
1222
1837
  this.textureAccessors.forEach((e) => e.dispose()), this.tableAccessors.forEach((e) => e.dispose()), this.attributeAccessors.forEach((e) => e.dispose());
1223
1838
  }
1224
1839
  };
1225
- var Is = /* @__PURE__ */ new Vector2(), vs = /* @__PURE__ */ new Vector2(), Ls = /* @__PURE__ */ new Vector2();
1226
- function er(a) {
1840
+ var Ls = /* @__PURE__ */ new Vector2(), Es = /* @__PURE__ */ new Vector2(), ws = /* @__PURE__ */ new Vector2();
1841
+ function or(a) {
1227
1842
  return a.x > a.y && a.x > a.z ? 0 : a.y > a.z ? 1 : 2;
1228
1843
  }
1229
- var tr = class {
1844
+ var ar = class {
1230
1845
  constructor(e, t, s) {
1231
1846
  this.geometry = e, this.textures = t, this.data = s, this._asyncRead = !1, this.featureIds = s.featureIds.map((n) => {
1232
1847
  const { texture: i, ...r } = n, o = {
@@ -1242,26 +1857,48 @@ var tr = class {
1242
1857
  }), o;
1243
1858
  });
1244
1859
  }
1860
+ /**
1861
+ * Returns an indexed list of all textures used by features in the extension.
1862
+ * @returns {Array<Texture>}
1863
+ */
1245
1864
  getTextures() {
1246
1865
  return this.textures;
1247
1866
  }
1867
+ /**
1868
+ * Returns the feature ID info for each feature set defined on this primitive.
1869
+ * @returns {Array<FeatureInfo>}
1870
+ */
1248
1871
  getFeatureInfo() {
1249
1872
  return this.featureIds;
1250
1873
  }
1874
+ /**
1875
+ * Performs the same function as `getFeatures` but reads texture data asynchronously.
1876
+ * @param {number} triangle Triangle index from a raycast hit.
1877
+ * @param {Vector3} barycoord Barycentric coordinate of the hit point.
1878
+ * @returns {Promise<Array<number|null>>}
1879
+ */
1251
1880
  getFeaturesAsync(...e) {
1252
1881
  this._asyncRead = !0;
1253
1882
  const t = this.getFeatures(...e);
1254
1883
  return this._asyncRead = !1, t;
1255
1884
  }
1885
+ /**
1886
+ * Returns the list of feature IDs at the given point on the mesh. Takes the triangle
1887
+ * index from a raycast result and a barycentric coordinate. Results are indexed in the
1888
+ * same order as the feature info returned by `getFeatureInfo()`.
1889
+ * @param {number} triangle Triangle index from a raycast hit.
1890
+ * @param {Vector3} barycoord Barycentric coordinate of the hit point.
1891
+ * @returns {Array<number|null>}
1892
+ */
1256
1893
  getFeatures(e, t) {
1257
1894
  const { geometry: s, textures: n, featureIds: i } = this, r = new Array(i.length).fill(null), o = i.length;
1258
- he.increaseSizeTo(o);
1259
- const l = Sn(s, e), c = l[er(t)];
1895
+ de.increaseSizeTo(o);
1896
+ const l = vn(s, e), c = l[or(t)];
1260
1897
  for (let d = 0, m = i.length; d < m; d++) {
1261
1898
  const f = i[d], p = "nullFeatureId" in f ? f.nullFeatureId : null;
1262
1899
  if ("texture" in f) {
1263
1900
  const g = n[f.texture.index];
1264
- Mn(s, f.texture.texCoord, t, l, Is), Cn(Is, g.image.width, g.image.height, vs), Ls.set(d, 0), he.renderPixelToTarget(n[f.texture.index], vs, Ls);
1901
+ Ln(s, f.texture.texCoord, t, l, Ls), En(Ls, g.image.width, g.image.height, Es), ws.set(d, 0), de.renderPixelToTarget(n[f.texture.index], Es, ws);
1265
1902
  } else if ("attribute" in f) {
1266
1903
  const y = s.getAttribute(`_feature_id_${f.attribute}`).getX(c);
1267
1904
  y !== p && (r[d] = y);
@@ -1271,8 +1908,8 @@ var tr = class {
1271
1908
  }
1272
1909
  }
1273
1910
  const u = new Uint8Array(o * 4);
1274
- if (this._asyncRead) return he.readDataAsync(u).then(() => (h(), r));
1275
- return he.readData(u), h(), r;
1911
+ if (this._asyncRead) return de.readDataAsync(u).then(() => (h(), r));
1912
+ return de.readData(u), h(), r;
1276
1913
  function h() {
1277
1914
  const d = new Uint32Array(1);
1278
1915
  for (let m = 0, f = i.length; m < f; m++) {
@@ -1280,12 +1917,15 @@ var tr = class {
1280
1917
  if ("texture" in p) {
1281
1918
  const { channels: y } = p.texture, x = y.map((T) => u[4 * m + T]);
1282
1919
  new Uint8Array(d.buffer).set(x);
1283
- const S = d[0];
1284
- S !== g && (r[m] = S);
1920
+ const b = d[0];
1921
+ b !== g && (r[m] = b);
1285
1922
  }
1286
1923
  }
1287
1924
  }
1288
1925
  }
1926
+ /**
1927
+ * Disposes all textures used by this instance.
1928
+ */
1289
1929
  dispose() {
1290
1930
  this.textures.forEach((e) => {
1291
1931
  e && (e.dispose(), e.image instanceof ImageBitmap && e.image.close());
@@ -1293,13 +1933,13 @@ var tr = class {
1293
1933
  }
1294
1934
  };
1295
1935
  new FullScreenQuad(new MeshBasicMaterial());
1296
- var Ft = new DataTexture(new Uint8Array([
1936
+ var zt = new DataTexture(new Uint8Array([
1297
1937
  255,
1298
1938
  255,
1299
1939
  255,
1300
1940
  255
1301
1941
  ]), 1, 1);
1302
- Ft.needsUpdate = !0;
1942
+ zt.needsUpdate = !0;
1303
1943
  Object.freeze({
1304
1944
  NONE: 0,
1305
1945
  SCREEN_ERROR: 1,
@@ -1472,7 +2112,7 @@ var GLTFWorkerLoader = class extends Loader {
1472
2112
  if (hasStructuralMetadata && data.structuralMetadata) {
1473
2113
  const rootExtension = data.json?.extensions?.[EXT_STRUCTURAL_METADATA];
1474
2114
  if (rootExtension) {
1475
- rootMetadata = new As({
2115
+ rootMetadata = new vs({
1476
2116
  schema: data.structuralMetadata.schema,
1477
2117
  propertyTables: data.structuralMetadata.propertyTables || [],
1478
2118
  propertyTextures: rootExtension.propertyTextures || [],
@@ -1495,7 +2135,7 @@ var GLTFWorkerLoader = class extends Loader {
1495
2135
  const primMetadataExt = extensions?.[EXT_STRUCTURAL_METADATA];
1496
2136
  if (primMetadataExt) {
1497
2137
  const rootExtension = data.json?.extensions?.[EXT_STRUCTURAL_METADATA];
1498
- if (rootExtension) child.userData.structuralMetadata = new As({
2138
+ if (rootExtension) child.userData.structuralMetadata = new vs({
1499
2139
  schema: data.structuralMetadata.schema,
1500
2140
  propertyTables: data.structuralMetadata.propertyTables || [],
1501
2141
  propertyTextures: rootExtension.propertyTextures || [],
@@ -1505,17 +2145,13 @@ var GLTFWorkerLoader = class extends Loader {
1505
2145
  }
1506
2146
  if (hasMeshFeatures) {
1507
2147
  const meshFeaturesExt = extensions?.[EXT_MESH_FEATURES];
1508
- if (meshFeaturesExt) child.userData.meshFeatures = new tr(child.geometry, textures, meshFeaturesExt);
2148
+ if (meshFeaturesExt) child.userData.meshFeatures = new ar(child.geometry, textures, meshFeaturesExt);
1509
2149
  }
1510
2150
  });
1511
2151
  }
1512
2152
  };
1513
2153
  //#endregion
1514
2154
  //#region src/plugin/PartColorHelper.ts
1515
- function ensureColor$2(color) {
1516
- if (color instanceof Color) return color;
1517
- return new Color(color);
1518
- }
1519
2155
  function getMaterials(mesh) {
1520
2156
  const mat = mesh.material;
1521
2157
  if (!mat) return [];
@@ -1573,7 +2209,7 @@ var PartColorHelper = class {
1573
2209
  setPartColorByOids(oids, color) {
1574
2210
  const scene = this.context.getScene();
1575
2211
  if (!scene) return;
1576
- const material = getMaterialForColor(ensureColor$2(color));
2212
+ const material = getMaterialForColor(toColor(color));
1577
2213
  for (const oid of oids) {
1578
2214
  this.coloredOids.add(oid);
1579
2215
  this.materialByOid.set(oid, material);
@@ -1699,10 +2335,6 @@ var PartColorHelper = class {
1699
2335
  };
1700
2336
  //#endregion
1701
2337
  //#region src/plugin/PartBlinkHelper.ts
1702
- function ensureColor$1(color) {
1703
- if (color instanceof Color) return color;
1704
- return new Color(color);
1705
- }
1706
2338
  /**
1707
2339
  * 构件闪烁强调辅助器
1708
2340
  * 通过 hidePartsByOids + split mesh + emissive 动画实现闪烁效果
@@ -1786,7 +2418,7 @@ var PartBlinkHelper = class {
1786
2418
  * @param color 颜色值,支持 hex 数字、颜色字符串(如 "#ff0000")、THREE.Color 对象
1787
2419
  */
1788
2420
  setBlinkColor(color) {
1789
- const c = ensureColor$1(color);
2421
+ const c = toColor(color);
1790
2422
  this.blinkColor.copy(c);
1791
2423
  this.blinkMaterial.color.copy(c);
1792
2424
  this.blinkMaterial.emissive.copy(c);
@@ -1831,10 +2463,6 @@ var PartBlinkHelper = class {
1831
2463
  };
1832
2464
  //#endregion
1833
2465
  //#region src/plugin/PartFrameHelper.ts
1834
- function ensureColor(color) {
1835
- if (color instanceof Color) return color;
1836
- return new Color(color);
1837
- }
1838
2466
  /**
1839
2467
  * 构件线框显示辅助器
1840
2468
  * 通过 hidePartsByOids + split mesh + 填充材质 + EdgesGeometry 实现线框效果
@@ -1967,7 +2595,7 @@ var PartFrameHelper = class {
1967
2595
  * @param color 颜色值,支持 hex 数字、颜色字符串(如 "#ff0000")、THREE.Color 对象
1968
2596
  */
1969
2597
  setFrameFillColor(oids, color) {
1970
- const hex = ensureColor(color).getHex();
2598
+ const hex = toColor(color).getHex();
1971
2599
  for (const oid of oids) {
1972
2600
  if (!this.frameOids.has(oid)) continue;
1973
2601
  this.fillColorByOid.set(oid, hex);
@@ -1980,7 +2608,7 @@ var PartFrameHelper = class {
1980
2608
  * @param color 颜色值,支持 hex 数字、颜色字符串(如 "#ff0000")、THREE.Color 对象
1981
2609
  */
1982
2610
  setFrameEdgeColor(oids, color) {
1983
- const hex = ensureColor(color).getHex();
2611
+ const hex = toColor(color).getHex();
1984
2612
  for (const oid of oids) {
1985
2613
  if (!this.frameOids.has(oid)) continue;
1986
2614
  this.edgeColorByOid.set(oid, hex);
@@ -1996,13 +2624,445 @@ var PartFrameHelper = class {
1996
2624
  }
1997
2625
  };
1998
2626
  //#endregion
2627
+ //#region src/plugin/style-appearance-shared.ts
2628
+ function vec3Key(v) {
2629
+ if (v === void 0) return "";
2630
+ if (Array.isArray(v)) return `${v[0] ?? 0},${v[1] ?? 0},${v[2] ?? 0}`;
2631
+ const p = v;
2632
+ return `${p.x},${p.y},${p.z}`;
2633
+ }
2634
+ function eulerKey(r) {
2635
+ if (r === void 0) return "";
2636
+ if (Array.isArray(r)) return `${r[0] ?? 0},${r[1] ?? 0},${r[2] ?? 0},${r.length >= 4 && typeof r[3] === "string" ? r[3] : "XYZ"}`;
2637
+ const e = r;
2638
+ return `${e.x},${e.y},${e.z},${e.order}`;
2639
+ }
2640
+ function applyVec3(target, input) {
2641
+ if (Array.isArray(input)) target.set(input[0] ?? 0, input[1] ?? 0, input[2] ?? 0);
2642
+ else target.copy(input);
2643
+ }
2644
+ function applyEuler(target, input) {
2645
+ if (Array.isArray(input)) if (input.length >= 4 && typeof input[3] === "string") target.set(input[0] ?? 0, input[1] ?? 0, input[2] ?? 0, input[3]);
2646
+ else target.set(input[0] ?? 0, input[1] ?? 0, input[2] ?? 0, "XYZ");
2647
+ else target.copy(input);
2648
+ }
2649
+ function appearanceGroupKey(a) {
2650
+ return `${a.material.uuid}|${vec3Key(a.translation)}|${vec3Key(a.scale)}|${eulerKey(a.rotation)}|${vec3Key(a.origin)}`;
2651
+ }
2652
+ function buildPivotStyleMatrix(pivot, sx, sy, sz, euler) {
2653
+ const m = new Matrix4().makeTranslation(-pivot.x, -pivot.y, -pivot.z);
2654
+ m.premultiply(new Matrix4().makeScale(sx, sy, sz));
2655
+ m.premultiply(new Matrix4().makeRotationFromEuler(euler));
2656
+ m.premultiply(new Matrix4().makeTranslation(pivot.x, pivot.y, pivot.z));
2657
+ return m;
2658
+ }
2659
+ function resolveConditionsAppearance(conditions, propertyData) {
2660
+ if (!conditions?.length) return null;
2661
+ for (const [cond, value] of conditions) if (evaluateStyleCondition(cond, propertyData)) return value;
2662
+ return null;
2663
+ }
2664
+ function resolveStyleAppearance(conditions, propertyData) {
2665
+ return resolveConditionsAppearance(conditions, propertyData);
2666
+ }
2667
+ /** 与 setStyle 相同的 OID 分组逻辑(show + conditions → 外观分组 + 被 show 隐藏的 OID) */
2668
+ function buildAppearanceGroupsFromPropertyMap(propertyByOid, config) {
2669
+ const hiddenOidsList = [];
2670
+ const groups = /* @__PURE__ */ new Map();
2671
+ const conditions = config.conditions ?? [];
2672
+ for (const [oid, propertyData] of propertyByOid) {
2673
+ if (propertyData == null) continue;
2674
+ if (config.show) {
2675
+ if (!evaluateStyleCondition(config.show, propertyData)) {
2676
+ hiddenOidsList.push(oid);
2677
+ continue;
2678
+ }
2679
+ }
2680
+ const appearance = resolveStyleAppearance(conditions, propertyData);
2681
+ if (!appearance) continue;
2682
+ const gkey = appearanceGroupKey(appearance);
2683
+ let g = groups.get(gkey);
2684
+ if (!g) {
2685
+ g = {
2686
+ appearance,
2687
+ oids: []
2688
+ };
2689
+ groups.set(gkey, g);
2690
+ }
2691
+ g.oids.push(oid);
2692
+ }
2693
+ return {
2694
+ hiddenOidsList,
2695
+ groups
2696
+ };
2697
+ }
2698
+ function restoreMeshAppearanceMaps(mesh, maps) {
2699
+ const original = maps.originalMaterialByMesh.get(mesh.uuid);
2700
+ if (original) {
2701
+ mesh.material = original;
2702
+ maps.originalMaterialByMesh.delete(mesh.uuid);
2703
+ }
2704
+ const origT = maps.originalTransformByMesh.get(mesh.uuid);
2705
+ if (origT) {
2706
+ mesh.position.copy(origT.position);
2707
+ mesh.scale.copy(origT.scale);
2708
+ mesh.rotation.copy(origT.rotation);
2709
+ maps.originalTransformByMesh.delete(mesh.uuid);
2710
+ }
2711
+ }
2712
+ /**
2713
+ * 将 StyleAppearance 应用到 mesh(与 StyleHelper.applyAppearanceToCollector 一致)
2714
+ */
2715
+ function applyStyleAppearanceToMesh(mesh, appearance, scene, maps) {
2716
+ if (!maps.originalMaterialByMesh.has(mesh.uuid)) maps.originalMaterialByMesh.set(mesh.uuid, mesh.material);
2717
+ mesh.material = appearance.material;
2718
+ if (appearance.translation !== void 0 || appearance.scale !== void 0 || appearance.rotation !== void 0) {
2719
+ if (!maps.originalTransformByMesh.has(mesh.uuid)) maps.originalTransformByMesh.set(mesh.uuid, {
2720
+ position: mesh.position.clone(),
2721
+ scale: mesh.scale.clone(),
2722
+ rotation: mesh.rotation.clone()
2723
+ });
2724
+ const bt = maps.originalTransformByMesh.get(mesh.uuid);
2725
+ mesh.position.copy(bt.position);
2726
+ mesh.scale.copy(bt.scale);
2727
+ mesh.rotation.copy(bt.rotation);
2728
+ if (appearance.scale !== void 0 || appearance.rotation !== void 0) {
2729
+ const pivot = new Vector3();
2730
+ if (appearance.origin !== void 0) applyVec3(pivot, appearance.origin);
2731
+ else pivot.set(0, 0, 0);
2732
+ let sx = 1;
2733
+ let sy = 1;
2734
+ let sz = 1;
2735
+ if (appearance.scale !== void 0) if (Array.isArray(appearance.scale)) {
2736
+ sx = appearance.scale[0] ?? 1;
2737
+ sy = appearance.scale[1] ?? 1;
2738
+ sz = appearance.scale[2] ?? 1;
2739
+ } else {
2740
+ const sc = appearance.scale;
2741
+ sx = sc.x;
2742
+ sy = sc.y;
2743
+ sz = sc.z;
2744
+ }
2745
+ const euler = new Euler();
2746
+ if (appearance.rotation !== void 0) applyEuler(euler, appearance.rotation);
2747
+ else euler.set(0, 0, 0);
2748
+ const styleM = buildPivotStyleMatrix(pivot, sx, sy, sz, euler);
2749
+ mesh.updateMatrix();
2750
+ mesh.matrix.multiply(styleM);
2751
+ mesh.matrix.decompose(mesh.position, mesh.quaternion, mesh.scale);
2752
+ }
2753
+ if (appearance.translation !== void 0) applyVec3(mesh.position, appearance.translation);
2754
+ }
2755
+ mesh.updateMatrixWorld();
2756
+ scene.add(mesh);
2757
+ }
2758
+ //#endregion
2759
+ //#region src/plugin/StyleHelper.ts
2760
+ /**
2761
+ * 构件样式辅助器
2762
+ * 通过 show 表达式控制可见性,通过 conditions 应用条件材质与可选位姿
2763
+ */
2764
+ var StyleHelper = class {
2765
+ /** 当前样式配置,可通过 plugin.style 获取 */
2766
+ style = null;
2767
+ styledOids = /* @__PURE__ */ new Set();
2768
+ hiddenOids = /* @__PURE__ */ new Set();
2769
+ originalMaterialByMesh = /* @__PURE__ */ new Map();
2770
+ originalTransformByMesh = /* @__PURE__ */ new Map();
2771
+ /** 按材质分组后的收集器,key 与 collector.getCacheKey() 一致 */
2772
+ meshChangeHandlers = /* @__PURE__ */ new Map();
2773
+ /** 当前样式占用的收集器(用于 clearStyle / 下次 applyStyle 前卸载监听) */
2774
+ styleCollectors = [];
2775
+ constructor(context) {
2776
+ this.context = context;
2777
+ }
2778
+ /**
2779
+ * 设置样式
2780
+ * @param style 样式配置,传 null 或空对象清除样式
2781
+ */
2782
+ setStyle(style) {
2783
+ this.clearStyle();
2784
+ this.style = style;
2785
+ if (!style || !style.show && (!style.conditions || style.conditions.length === 0)) return;
2786
+ this.applyStyle();
2787
+ }
2788
+ /**
2789
+ * 清除样式,恢复默认显示
2790
+ */
2791
+ clearStyle() {
2792
+ const styledOidsList = Array.from(this.styledOids);
2793
+ const hiddenOidsList = Array.from(this.hiddenOids);
2794
+ for (const collector of this.styleCollectors) {
2795
+ collector.meshes.forEach((mesh) => {
2796
+ const original = this.originalMaterialByMesh.get(mesh.uuid);
2797
+ if (original) {
2798
+ mesh.material = original;
2799
+ this.originalMaterialByMesh.delete(mesh.uuid);
2800
+ }
2801
+ const origT = this.originalTransformByMesh.get(mesh.uuid);
2802
+ if (origT) {
2803
+ mesh.position.copy(origT.position);
2804
+ mesh.scale.copy(origT.scale);
2805
+ mesh.rotation.copy(origT.rotation);
2806
+ this.originalTransformByMesh.delete(mesh.uuid);
2807
+ }
2808
+ mesh.removeFromParent();
2809
+ });
2810
+ const handler = this.meshChangeHandlers.get(collector.getCacheKey());
2811
+ if (handler) collector.removeEventListener("mesh-change", handler);
2812
+ }
2813
+ this.meshChangeHandlers.clear();
2814
+ this.styleCollectors = [];
2815
+ this.style = null;
2816
+ this.styledOids.clear();
2817
+ this.hiddenOids.clear();
2818
+ this.context.showPartsByOids([...styledOidsList, ...hiddenOidsList]);
2819
+ }
2820
+ applyStyle() {
2821
+ const style = this.style;
2822
+ if (!style) return;
2823
+ if (!this.context.getScene()) return;
2824
+ const tiles = this.context.getTiles();
2825
+ if (!tiles) return;
2826
+ const propertyByOid = getPropertyDataMapFromTiles(tiles);
2827
+ for (const collector of this.styleCollectors) {
2828
+ const h = this.meshChangeHandlers.get(collector.getCacheKey());
2829
+ if (h) collector.removeEventListener("mesh-change", h);
2830
+ }
2831
+ this.styleCollectors = [];
2832
+ this.meshChangeHandlers.clear();
2833
+ const { hiddenOidsList, groups } = buildAppearanceGroupsFromPropertyMap(propertyByOid, {
2834
+ show: style.show,
2835
+ conditions: style.conditions ?? []
2836
+ });
2837
+ for (const { oids } of groups.values()) for (const oid of oids) this.styledOids.add(oid);
2838
+ this.hiddenOids = new Set(hiddenOidsList);
2839
+ const oidsToHide = [...hiddenOidsList];
2840
+ for (const { oids } of groups.values()) oidsToHide.push(...oids);
2841
+ const maps = {
2842
+ originalMaterialByMesh: this.originalMaterialByMesh,
2843
+ originalTransformByMesh: this.originalTransformByMesh
2844
+ };
2845
+ for (const { appearance, oids } of groups.values()) {
2846
+ const sortedOids = normalizeMeshCollectorOids(oids);
2847
+ const collector = this.context.getMeshCollectorByCondition({ oids: sortedOids });
2848
+ this.styleCollectors.push(collector);
2849
+ const cacheKey = collector.getCacheKey();
2850
+ const handler = () => {
2851
+ const s = this.context.getScene();
2852
+ if (!s) return;
2853
+ collector.meshes.forEach((mesh) => {
2854
+ applyStyleAppearanceToMesh(mesh, appearance, s, maps);
2855
+ });
2856
+ };
2857
+ this.meshChangeHandlers.set(cacheKey, handler);
2858
+ collector.addEventListener("mesh-change", handler);
2859
+ handler();
2860
+ }
2861
+ this.context.hidePartsByOids(oidsToHide);
2862
+ }
2863
+ /**
2864
+ * 瓦片加载完成后重新应用样式(由插件调用)
2865
+ */
2866
+ onTilesLoadEnd() {
2867
+ if (this.style) this.applyStyle();
2868
+ }
2869
+ dispose() {
2870
+ this.clearStyle();
2871
+ }
2872
+ };
2873
+ //#endregion
2874
+ //#region src/plugin/PartHighlightHelper.ts
2875
+ var highlightMaterialCache = /* @__PURE__ */ new Map();
2876
+ function getMaterialForHighlight(style) {
2877
+ const color = style.color != null ? toColor(style.color) : new Color(16776960);
2878
+ const opacity = style.opacity != null ? Math.max(0, Math.min(1, style.opacity)) : 1;
2879
+ const key = `${color.getHex()}_${opacity}`;
2880
+ if (!highlightMaterialCache.has(key)) {
2881
+ const mat = new MeshStandardMaterial({
2882
+ color: color.clone(),
2883
+ roughness: .5,
2884
+ metalness: .1,
2885
+ opacity,
2886
+ transparent: opacity < 1
2887
+ });
2888
+ highlightMaterialCache.set(key, mat);
2889
+ }
2890
+ return highlightMaterialCache.get(key);
2891
+ }
2892
+ function toMaterial(value) {
2893
+ if (value instanceof Material) return value;
2894
+ return getMaterialForHighlight(value);
2895
+ }
2896
+ function toStyleAppearance(ha) {
2897
+ return {
2898
+ material: toMaterial(ha.material),
2899
+ translation: ha.translation,
2900
+ scale: ha.scale,
2901
+ rotation: ha.rotation,
2902
+ origin: ha.origin
2903
+ };
2904
+ }
2905
+ /**
2906
+ * 构件高亮辅助器
2907
+ * 与 setStyle 相同的 show / conditions / 位姿语义,多组命名高亮;底层通过 hidePartsByOids + split mesh 实现
2908
+ */
2909
+ var PartHighlightHelper = class {
2910
+ highlightGroups = /* @__PURE__ */ new Map();
2911
+ originalMaterialByMesh = /* @__PURE__ */ new Map();
2912
+ originalTransformByMesh = /* @__PURE__ */ new Map();
2913
+ meshChangeHandlers = /* @__PURE__ */ new Map();
2914
+ highlightCollectors = [];
2915
+ /** 上次 hidePartsByOids 传入的 OID 列表,用于重新应用前 showParts */
2916
+ lastHiddenOids = [];
2917
+ constructor(context) {
2918
+ this.context = context;
2919
+ }
2920
+ getMaps() {
2921
+ return {
2922
+ originalMaterialByMesh: this.originalMaterialByMesh,
2923
+ originalTransformByMesh: this.originalTransformByMesh
2924
+ };
2925
+ }
2926
+ /**
2927
+ * 合并多组命名高亮:按 Map 插入顺序,后写入的组覆盖同一 OID 的外观
2928
+ */
2929
+ mergeAppearanceByOid(propertyByOid) {
2930
+ const appearanceByOid = /* @__PURE__ */ new Map();
2931
+ for (const [, hl] of this.highlightGroups) {
2932
+ const conditions = (hl.conditions ?? []).map(([c, h]) => [c, toStyleAppearance(h)]);
2933
+ for (const [oid, propertyData] of propertyByOid) {
2934
+ if (propertyData == null) continue;
2935
+ if (hl.oids && !hl.oids.includes(oid)) continue;
2936
+ if (hl.show && !evaluateStyleCondition(hl.show, propertyData)) continue;
2937
+ const app = resolveConditionsAppearance(conditions, propertyData);
2938
+ if (!app) continue;
2939
+ appearanceByOid.set(oid, app);
2940
+ }
2941
+ }
2942
+ return appearanceByOid;
2943
+ }
2944
+ /** 各组 show 失败需隐藏的 OID(与 setStyle 一致:show 不满足则隐藏原片) */
2945
+ collectUnionShowHide(propertyByOid) {
2946
+ const unionHide = /* @__PURE__ */ new Set();
2947
+ for (const [, hl] of this.highlightGroups) for (const [oid, propertyData] of propertyByOid) {
2948
+ if (propertyData == null) continue;
2949
+ if (hl.oids && !hl.oids.includes(oid)) continue;
2950
+ if (hl.show && !evaluateStyleCondition(hl.show, propertyData)) unionHide.add(oid);
2951
+ }
2952
+ return unionHide;
2953
+ }
2954
+ clearCollectorsAndRestoreMeshes() {
2955
+ const maps = this.getMaps();
2956
+ for (const collector of this.highlightCollectors) {
2957
+ collector.meshes.forEach((mesh) => {
2958
+ restoreMeshAppearanceMaps(mesh, maps);
2959
+ mesh.removeFromParent();
2960
+ });
2961
+ const handler = this.meshChangeHandlers.get(collector.getCacheKey());
2962
+ if (handler) collector.removeEventListener("mesh-change", handler);
2963
+ }
2964
+ this.meshChangeHandlers.clear();
2965
+ this.highlightCollectors = [];
2966
+ }
2967
+ reapplyAll() {
2968
+ this.clearCollectorsAndRestoreMeshes();
2969
+ if (this.lastHiddenOids.length > 0) this.context.showPartsByOids(this.lastHiddenOids);
2970
+ if (this.highlightGroups.size === 0) {
2971
+ this.lastHiddenOids = [];
2972
+ return;
2973
+ }
2974
+ const tiles = this.context.getTiles();
2975
+ const scene = this.context.getScene();
2976
+ if (!tiles || !scene) return;
2977
+ const propertyByOid = getPropertyDataMapFromTiles(tiles);
2978
+ const appearanceByOid = this.mergeAppearanceByOid(propertyByOid);
2979
+ const unionHide = this.collectUnionShowHide(propertyByOid);
2980
+ const oidsToHide = [...new Set([...appearanceByOid.keys(), ...unionHide])];
2981
+ this.lastHiddenOids = oidsToHide;
2982
+ const groups = /* @__PURE__ */ new Map();
2983
+ for (const [oid, app] of appearanceByOid) {
2984
+ const gkey = appearanceGroupKey(app);
2985
+ let g = groups.get(gkey);
2986
+ if (!g) {
2987
+ g = {
2988
+ appearance: app,
2989
+ oids: []
2990
+ };
2991
+ groups.set(gkey, g);
2992
+ }
2993
+ g.oids.push(oid);
2994
+ }
2995
+ const maps = this.getMaps();
2996
+ for (const { appearance, oids } of groups.values()) {
2997
+ const sortedOids = normalizeMeshCollectorOids(oids);
2998
+ const collector = this.context.getMeshCollectorByCondition({ oids: sortedOids });
2999
+ this.highlightCollectors.push(collector);
3000
+ const cacheKey = collector.getCacheKey();
3001
+ const handler = () => {
3002
+ const s = this.context.getScene();
3003
+ if (!s) return;
3004
+ collector.meshes.forEach((mesh) => {
3005
+ applyStyleAppearanceToMesh(mesh, appearance, s, maps);
3006
+ });
3007
+ };
3008
+ this.meshChangeHandlers.set(cacheKey, handler);
3009
+ collector.addEventListener("mesh-change", handler);
3010
+ handler();
3011
+ }
3012
+ this.context.hidePartsByOids(oidsToHide);
3013
+ }
3014
+ /**
3015
+ * 高亮指定构件(语义与 setStyle 一致,多 name 参数)
3016
+ */
3017
+ highlight(options) {
3018
+ const { name, show, conditions, oids } = options;
3019
+ if (!show && (!conditions || conditions.length === 0)) {
3020
+ this.cancelHighlight(name);
3021
+ return;
3022
+ }
3023
+ this.highlightGroups.set(name, {
3024
+ show,
3025
+ conditions,
3026
+ oids
3027
+ });
3028
+ this.reapplyAll();
3029
+ }
3030
+ /**
3031
+ * 取消指定名称的高亮
3032
+ */
3033
+ cancelHighlight(name) {
3034
+ if (!this.highlightGroups.has(name)) return;
3035
+ this.highlightGroups.delete(name);
3036
+ this.reapplyAll();
3037
+ }
3038
+ /**
3039
+ * 取消所有高亮
3040
+ */
3041
+ cancelAllHighlight() {
3042
+ this.highlightGroups.clear();
3043
+ this.reapplyAll();
3044
+ }
3045
+ /**
3046
+ * 瓦片加载完成后重新应用高亮(由插件调用)
3047
+ */
3048
+ onTilesLoadEnd() {
3049
+ if (this.highlightGroups.size === 0) return;
3050
+ this.reapplyAll();
3051
+ }
3052
+ dispose() {
3053
+ this.cancelAllHighlight();
3054
+ }
3055
+ };
3056
+ //#endregion
1999
3057
  //#region src/plugin/InteractionFilter.ts
2000
3058
  /**
2001
- * 冻结与隔离逻辑:管理构件的交互过滤及 getMeshCollectorByOid 获取的 mesh 在场景中的显隐
3059
+ * 冻结与隔离逻辑:管理构件的交互过滤及 MeshCollector 获取的 mesh 在场景中的显隐
3060
+ * split mesh 使用 userData.oid(单 feature)或 userData.collectorOids(合并 mesh):任一相关 OID 被冻结/隔离规则命中则整 mesh 脱离场景
2002
3061
  */
2003
3062
  var InteractionFilter = class {
2004
3063
  frozenOids = /* @__PURE__ */ new Set();
2005
3064
  isolatedOids = /* @__PURE__ */ new Set();
3065
+ /** 按 collector 分组键追踪 mesh */
2006
3066
  trackedMeshes = /* @__PURE__ */ new Map();
2007
3067
  meshListeners = /* @__PURE__ */ new Map();
2008
3068
  isPluginRemoving = false;
@@ -2014,12 +3074,19 @@ var InteractionFilter = class {
2014
3074
  if (this.isolatedOids.size > 0 && !this.isolatedOids.has(oid)) return true;
2015
3075
  return false;
2016
3076
  }
2017
- trackMesh(mesh, oid) {
3077
+ /** 合并 split:任一 collector OID 被 block 则整 mesh 视为应隐藏 */
3078
+ isMeshInteractionBlocked(mesh) {
3079
+ const coids = mesh.userData?.collectorOids;
3080
+ if (coids && coids.length > 0) return coids.some((oid) => this.isOidBlocked(oid));
3081
+ const oid = mesh.userData?.oid;
3082
+ return oid !== void 0 && this.isOidBlocked(oid);
3083
+ }
3084
+ trackMesh(mesh) {
2018
3085
  if (this.meshListeners.has(mesh)) return;
2019
3086
  const onAdded = () => {
2020
3087
  if (this.isPluginRemoving) return;
2021
3088
  mesh.userData._detachedParent = null;
2022
- if (this.isOidBlocked(oid) && mesh.parent) {
3089
+ if (this.isMeshInteractionBlocked(mesh) && mesh.parent) {
2023
3090
  const parent = mesh.parent;
2024
3091
  this.isPluginRemoving = true;
2025
3092
  mesh.userData._detachedParent = parent;
@@ -2047,8 +3114,8 @@ var InteractionFilter = class {
2047
3114
  }
2048
3115
  mesh.userData._detachedParent = null;
2049
3116
  }
2050
- onCollectorMeshChange(oid, newMeshes) {
2051
- const tracked = this.trackedMeshes.get(oid);
3117
+ onCollectorMeshChange(groupKey, newMeshes) {
3118
+ const tracked = this.trackedMeshes.get(groupKey);
2052
3119
  const newSet = new Set(newMeshes);
2053
3120
  if (tracked) {
2054
3121
  for (const mesh of tracked) if (!newSet.has(mesh)) {
@@ -2058,39 +3125,36 @@ var InteractionFilter = class {
2058
3125
  }
2059
3126
  const trackSet = tracked || /* @__PURE__ */ new Set();
2060
3127
  for (const mesh of newMeshes) if (!trackSet.has(mesh)) {
2061
- this.trackMesh(mesh, oid);
3128
+ this.trackMesh(mesh);
2062
3129
  trackSet.add(mesh);
2063
3130
  }
2064
- this.trackedMeshes.set(oid, trackSet);
3131
+ this.trackedMeshes.set(groupKey, trackSet);
2065
3132
  }
2066
3133
  syncCollectorMeshes() {
2067
3134
  this.isPluginRemoving = true;
2068
- for (const [oid, collector] of this.context.getCollectorCache()) {
2069
- const blocked = this.isOidBlocked(oid);
2070
- for (const mesh of collector.meshes) {
2071
- if (!this.meshListeners.has(mesh)) continue;
2072
- if (blocked) {
2073
- if (mesh.parent && !mesh.userData._detachedParent) {
2074
- const parent = mesh.parent;
2075
- mesh.userData._detachedParent = parent;
2076
- parent.remove(mesh);
2077
- }
2078
- } else {
2079
- const storedParent = mesh.userData._detachedParent;
2080
- if (storedParent && !mesh.parent) {
2081
- storedParent.add(mesh);
2082
- mesh.userData._detachedParent = null;
2083
- }
3135
+ for (const [, collector] of this.context.getCollectorCache()) for (const mesh of collector.meshes) {
3136
+ if (!this.meshListeners.has(mesh)) continue;
3137
+ if (this.isMeshInteractionBlocked(mesh)) {
3138
+ if (mesh.parent && !mesh.userData._detachedParent) {
3139
+ const parent = mesh.parent;
3140
+ mesh.userData._detachedParent = parent;
3141
+ parent.remove(mesh);
3142
+ }
3143
+ } else {
3144
+ const storedParent = mesh.userData._detachedParent;
3145
+ if (storedParent && !mesh.parent) {
3146
+ storedParent.add(mesh);
3147
+ mesh.userData._detachedParent = null;
2084
3148
  }
2085
3149
  }
2086
3150
  }
2087
3151
  this.isPluginRemoving = false;
2088
3152
  }
2089
- onUnregisterCollector(oid) {
2090
- const tracked = this.trackedMeshes.get(oid);
3153
+ onUnregisterCollector(groupKey) {
3154
+ const tracked = this.trackedMeshes.get(groupKey);
2091
3155
  if (tracked) {
2092
3156
  for (const mesh of tracked) this.untrackMesh(mesh);
2093
- this.trackedMeshes.delete(oid);
3157
+ this.trackedMeshes.delete(groupKey);
2094
3158
  }
2095
3159
  }
2096
3160
  freezeByOids(oids) {
@@ -2098,16 +3162,14 @@ var InteractionFilter = class {
2098
3162
  this.syncCollectorMeshes();
2099
3163
  }
2100
3164
  freezeByOid(oid) {
2101
- this.frozenOids.add(oid);
2102
- this.syncCollectorMeshes();
3165
+ this.freezeByOids([oid]);
2103
3166
  }
2104
3167
  unfreezeByOids(oids) {
2105
3168
  for (const oid of oids) this.frozenOids.delete(oid);
2106
3169
  this.syncCollectorMeshes();
2107
3170
  }
2108
3171
  unfreezeByOid(oid) {
2109
- this.frozenOids.delete(oid);
2110
- this.syncCollectorMeshes();
3172
+ this.unfreezeByOids([oid]);
2111
3173
  }
2112
3174
  unfreeze() {
2113
3175
  this.frozenOids.clear();
@@ -2129,8 +3191,7 @@ var InteractionFilter = class {
2129
3191
  this.syncCollectorMeshes();
2130
3192
  }
2131
3193
  unisolateByOid(oid) {
2132
- this.isolatedOids.delete(oid);
2133
- this.syncCollectorMeshes();
3194
+ this.unisolateByOids([oid]);
2134
3195
  }
2135
3196
  unisolate() {
2136
3197
  this.isolatedOids.clear();
@@ -2242,18 +3303,23 @@ var GLTFParserPlugin = class {
2242
3303
  _options;
2243
3304
  _structureData = null;
2244
3305
  _oidNodeMap = /* @__PURE__ */ new Map();
2245
- _structurePromise = null;
3306
+ /** rootTileset 已存在且已尝试过内嵌解析后仍为 null,则不再重复 gunzip */
3307
+ _structureEmbedResolved = false;
2246
3308
  _modelInfo = null;
2247
3309
  _modelInfoPromise = null;
2248
3310
  _interactionFilter;
2249
3311
  _partColorHelper = null;
2250
3312
  _partBlinkHelper = null;
2251
3313
  _partFrameHelper = null;
3314
+ _styleHelper = null;
3315
+ _partHighlightHelper = null;
2252
3316
  oids = [];
2253
- renderer = null;
3317
+ /** WebGLRenderer 实例,用于 mesh helper 等扩展 */
3318
+ get renderer() {
3319
+ return this._renderer;
3320
+ }
3321
+ _renderer = null;
2254
3322
  splitMeshCache = /* @__PURE__ */ new Map();
2255
- maxUniformVectors = 1024;
2256
- featureIdCount = 32;
2257
3323
  collectors = /* @__PURE__ */ new Set();
2258
3324
  collectorCache = /* @__PURE__ */ new Map();
2259
3325
  /**
@@ -2267,7 +3333,7 @@ var GLTFParserPlugin = class {
2267
3333
  useIndexedDB: false,
2268
3334
  ...options
2269
3335
  };
2270
- if (options?.renderer) this.renderer = options.renderer;
3336
+ if (options?.renderer) this._renderer = options.renderer;
2271
3337
  this._interactionFilter = new InteractionFilter({ getCollectorCache: () => this.collectorCache });
2272
3338
  setMaxWorkers(this._options.maxWorkers);
2273
3339
  }
@@ -2276,38 +3342,43 @@ var GLTFParserPlugin = class {
2276
3342
  */
2277
3343
  init(tiles) {
2278
3344
  this.tiles = tiles;
2279
- this._partColorHelper = new PartColorHelper({
2280
- hidePartsByOids: (oids) => this.hidePartsByOids(oids),
2281
- showPartsByOids: (oids) => this.showPartsByOids(oids),
2282
- getMeshCollectorByOid: (oid) => this.getMeshCollectorByOid(oid),
2283
- getScene: () => this.tiles?.group ?? null
2284
- });
2285
- this._partBlinkHelper = new PartBlinkHelper({
2286
- hidePartsByOids: (oids) => this.hidePartsByOids(oids),
2287
- showPartsByOids: (oids) => this.showPartsByOids(oids),
2288
- getMeshCollectorByOid: (oid) => this.getMeshCollectorByOid(oid),
2289
- getScene: () => this.tiles?.group ?? null
2290
- });
2291
- this._partFrameHelper = new PartFrameHelper({
2292
- hidePartsByOids: (oids) => this.hidePartsByOids(oids),
2293
- showPartsByOids: (oids) => this.showPartsByOids(oids),
2294
- getMeshCollectorByOid: (oid) => this.getMeshCollectorByOid(oid),
2295
- getScene: () => this.tiles?.group ?? null
3345
+ const partFx = this._createPartEffectHost();
3346
+ this._partColorHelper = new PartColorHelper(partFx);
3347
+ this._partBlinkHelper = new PartBlinkHelper(partFx);
3348
+ this._partFrameHelper = new PartFrameHelper(partFx);
3349
+ this._styleHelper = new StyleHelper({
3350
+ getTiles: () => this.tiles,
3351
+ hidePartsByOids: partFx.hidePartsByOids,
3352
+ showPartsByOids: partFx.showPartsByOids,
3353
+ getMeshCollectorByCondition: partFx.getMeshCollectorByCondition,
3354
+ getScene: partFx.getScene
2296
3355
  });
3356
+ this._partHighlightHelper = new PartHighlightHelper(partFx);
2297
3357
  this._loader = new GLTFWorkerLoader(tiles.manager, {
2298
3358
  metadata: this._options.metadata,
2299
3359
  materialBuilder: this._options.materialBuilder
2300
3360
  });
2301
3361
  tiles.manager.addHandler(this._gltfRegex, this._loader);
2302
- if (this.renderer) this._updateWebGLLimits();
2303
3362
  tiles.addEventListener("load-model", this._onLoadModelCB);
2304
3363
  tiles.addEventListener("tiles-load-end", this._onTilesLoadEndCB);
3364
+ tiles.addEventListener("load-root-tileset", this._onLoadRootTilesetCB);
3365
+ this._syncStructureFromTileset();
2305
3366
  tiles.traverse((tile) => {
2306
3367
  const tileWithCache = tile;
2307
- if (tileWithCache.cached?.scene) this._onLoadModel(tileWithCache.cached.scene);
3368
+ if (tileWithCache.engineData?.scene) this._onLoadModel(tileWithCache.engineData.scene);
2308
3369
  return true;
2309
3370
  }, null);
2310
3371
  }
3372
+ _createPartEffectHost() {
3373
+ return {
3374
+ getTiles: () => this.tiles ?? null,
3375
+ hidePartsByOids: (oids) => this.hidePartsByOids(oids),
3376
+ showPartsByOids: (oids) => this.showPartsByOids(oids),
3377
+ getMeshCollectorByOid: (oid) => this.getMeshCollectorByOid(oid),
3378
+ getMeshCollectorByCondition: (q) => this.getMeshCollectorByCondition(q),
3379
+ getScene: () => this.tiles?.group ?? null
3380
+ };
3381
+ }
2311
3382
  /**
2312
3383
  * Fetch tile data with IndexedDB caching support
2313
3384
  */
@@ -2339,56 +3410,51 @@ var GLTFParserPlugin = class {
2339
3410
  if (this._options.beforeParseTile) buffer = await this._options.beforeParseTile(buffer, tile, extension, uri, abortSignal);
2340
3411
  return this.tiles.parseTile(buffer, tile, extension, uri, abortSignal);
2341
3412
  }
2342
- _getStructureUrl() {
3413
+ /** 与 tileset 同目录的侧车 JSON,如 structure.json / modelInfo.json */
3414
+ _sidecarJsonUrl(fileName) {
2343
3415
  const rootURL = this.tiles?.rootURL;
2344
3416
  if (!rootURL) return null;
2345
- return rootURL.replace(/[^/]+$/, "structure.json");
3417
+ return rootURL.replace(/[^/]+$/, fileName);
2346
3418
  }
2347
3419
  _buildOidNodeMap(node, map) {
2348
3420
  if (node.id !== void 0) map.set(node.id, node);
2349
3421
  if (node.children) for (const child of node.children) this._buildOidNodeMap(child, map);
2350
3422
  }
2351
- async _fetchStructureData() {
2352
- const url = this._getStructureUrl();
2353
- if (!url) {
2354
- console.warn("[GLTFParserPlugin] Cannot derive structure.json URL: tiles not initialized");
2355
- return null;
2356
- }
2357
- try {
2358
- const response = await fetch(url);
2359
- if (!response.ok) {
2360
- console.warn(`[GLTFParserPlugin] Failed to fetch structure.json: ${response.status}`);
2361
- return null;
2362
- }
2363
- const data = await response.json();
2364
- this._structureData = data;
2365
- this._oidNodeMap.clear();
2366
- if (data.trees) for (const tree of data.trees) this._buildOidNodeMap(tree, this._oidNodeMap);
2367
- return data;
2368
- } catch (error) {
2369
- console.error("[GLTFParserPlugin] Error loading structure.json:", error);
2370
- return null;
2371
- }
2372
- }
2373
- async _ensureStructureLoaded() {
3423
+ /** 仅根 tileset 变化时重解析 structureUri(子 tileset 的 load-tileset 不会触发) */
3424
+ _onLoadRootTilesetCB = () => {
3425
+ this._structureData = null;
3426
+ this._oidNodeMap.clear();
3427
+ this._structureEmbedResolved = false;
3428
+ this._syncStructureFromTileset();
3429
+ };
3430
+ /**
3431
+ * 从已加载根 tileset 的内嵌 structure(优先 asset.extras.maptalks.structureUri)同步解压并建索引。
3432
+ * rootTileset 尚未就绪时返回 null,可稍后再次调用;已成功或已判定无内嵌数据后见 _structureEmbedResolved。
3433
+ */
3434
+ _syncStructureFromTileset() {
2374
3435
  if (this._structureData) return this._structureData;
2375
- if (!this._structurePromise) this._structurePromise = this._fetchStructureData();
2376
- return this._structurePromise;
3436
+ if (this._structureEmbedResolved) return null;
3437
+ if (!this.tiles?.rootTileset) return null;
3438
+ const embedded = parseEmbeddedStructureDataFromTilesSync(this.tiles);
3439
+ this._structureEmbedResolved = true;
3440
+ if (!embedded) return null;
3441
+ this._structureData = embedded;
3442
+ this._oidNodeMap.clear();
3443
+ if (embedded.trees) for (const tree of embedded.trees) this._buildOidNodeMap(tree, this._oidNodeMap);
3444
+ return embedded;
2377
3445
  }
2378
3446
  /**
2379
- * 根据 oid 获取 structure.json 中对应的节点树数据
2380
- * 包含 bbox、children、name 等完整结构信息
2381
- * 首次调用时会自动从 tileset URL 推导并请求 structure.json
3447
+ * 根据 oid 获取结构树节点(数据来自 tileset 内嵌 structureUri 同步解压)
2382
3448
  */
2383
- async getNodeTreeByOid(oid) {
2384
- await this._ensureStructureLoaded();
3449
+ getNodeTreeByOid(oid) {
3450
+ this._syncStructureFromTileset();
2385
3451
  return this._oidNodeMap.get(oid) ?? null;
2386
3452
  }
2387
3453
  /**
2388
- * 根据 oid 数组批量获取 structure.json 中对应的节点树数据
3454
+ * 根据 oid 数组批量获取结构树节点
2389
3455
  */
2390
- async getNodeTreeByOids(oids) {
2391
- await this._ensureStructureLoaded();
3456
+ getNodeTreeByOids(oids) {
3457
+ this._syncStructureFromTileset();
2392
3458
  const result = /* @__PURE__ */ new Map();
2393
3459
  for (const oid of oids) {
2394
3460
  const node = this._oidNodeMap.get(oid);
@@ -2397,41 +3463,58 @@ var GLTFParserPlugin = class {
2397
3463
  return result;
2398
3464
  }
2399
3465
  /**
2400
- * 获取完整的 structure.json 数据
2401
- * 首次调用时会自动请求
3466
+ * 根据 oid 从结构数据取轴对齐包围盒(`bbox` 为 `[minX,minY,minZ,maxX,maxY,maxZ]`,与 `selectByBox` 一致)
3467
+ * @returns 无对应节点或缺少有效 bbox 时返回 `null`
2402
3468
  */
2403
- async getStructureData() {
2404
- return this._ensureStructureLoaded();
3469
+ getBoundingBoxByOid(oid) {
3470
+ this._syncStructureFromTileset();
3471
+ return bboxArrayToBox3(this._oidNodeMap.get(oid)?.bbox);
2405
3472
  }
2406
3473
  /**
2407
- * 选择包围盒范围内的构件(包含相交和包含两种情况)
2408
- * @param box 查询用的 Box3 范围,坐标系与 structure.json 中 bbox 一致
2409
- * @returns 范围内所有构件的 oid 数组
3474
+ * 计算给定 OID 集合的几何中心(世界坐标系与结构 bbox / 瓦片 mesh 一致)。
3475
+ * 优先合并结构树中的轴对齐 bbox;若无有效 bbox 则合并对应 split mesh 的世界包围盒。
2410
3476
  */
2411
- async selectByBox(box) {
2412
- await this._ensureStructureLoaded();
3477
+ getCenterByOids(oids) {
3478
+ if (!this.tiles || oids.length === 0) return null;
3479
+ const unique = [...new Set(oids)];
3480
+ if (unique.length === 0) return null;
3481
+ return this._getCenterFromOidList(unique);
3482
+ }
3483
+ /**
3484
+ * 按属性条件筛选构件(语义同 `setStyle` 的 `show` / conditions 中的表达式字符串),
3485
+ * 返回筛选结果的整体中心点;合并方式同 {@link getCenterByOids}。
3486
+ */
3487
+ getCenterByCondition(condition) {
3488
+ if (!this.tiles) return null;
3489
+ const cond = condition.trim();
3490
+ if (!cond) return null;
3491
+ const targetOids = [];
3492
+ for (const oid of getAllOidsFromTiles(this.tiles)) if (evaluateStyleCondition(cond, getPropertyDataByOid(this.tiles, oid))) targetOids.push(oid);
3493
+ if (targetOids.length === 0) return null;
3494
+ return this._getCenterFromOidList(targetOids);
3495
+ }
3496
+ /**
3497
+ * 完整结构数据(与内嵌 structure JSON 一致)
3498
+ */
3499
+ getStructureData() {
3500
+ return this._syncStructureFromTileset();
3501
+ }
3502
+ /**
3503
+ * 选择包围盒范围内的构件(坐标系与结构 bbox 一致)
3504
+ */
3505
+ selectByBox(box) {
3506
+ this._syncStructureFromTileset();
2413
3507
  return selectByBoxFromOidMap(this._oidNodeMap, box);
2414
3508
  }
2415
3509
  /**
2416
- * 选择多边形(平面投影)范围内的构件(包含相交和包含两种情况)
2417
- * @param polygon 多边形顶点数组(Vector3),按顺序连接构成闭合多边形
2418
- * @param axis 投影平面,决定使用 bbox 的哪两个轴做 2D 判定
2419
- * - 'xz'(默认):俯视图,取 bbox 的 x/z 坐标
2420
- * - 'xy':正视图,取 bbox 的 x/y 坐标
2421
- * - 'yz':侧视图,取 bbox 的 y/z 坐标
2422
- * @returns 范围内所有构件的 oid 数组
3510
+ * 选择多边形(平面投影)范围内的构件
2423
3511
  */
2424
- async selectByPolygon(polygon, axis = "xz") {
2425
- await this._ensureStructureLoaded();
3512
+ selectByPolygon(polygon, axis = "xz") {
3513
+ this._syncStructureFromTileset();
2426
3514
  return selectByPolygonFromOidMap(this._oidNodeMap, polygon, axis);
2427
3515
  }
2428
- _getModelInfoUrl() {
2429
- const rootURL = this.tiles?.rootURL;
2430
- if (!rootURL) return null;
2431
- return rootURL.replace(/[^/]+$/, "modelInfo.json");
2432
- }
2433
3516
  async _fetchModelInfo() {
2434
- const url = this._getModelInfoUrl();
3517
+ const url = this._sidecarJsonUrl("modelInfo.json");
2435
3518
  if (!url) {
2436
3519
  console.warn("[GLTFParserPlugin] Cannot derive modelInfo.json URL: tiles not initialized");
2437
3520
  return null;
@@ -2481,83 +3564,41 @@ var GLTFParserPlugin = class {
2481
3564
  scene.traverse((c) => {
2482
3565
  if (c.material) this._setupMaterial(c);
2483
3566
  });
3567
+ applyVisibilityToScene(scene, new Set(this.oids));
2484
3568
  }
2485
3569
  _notifyCollectors() {
2486
3570
  for (const collector of this.collectors) collector._updateMeshes();
3571
+ this._styleHelper?.onTilesLoadEnd();
2487
3572
  }
2488
3573
  _registerCollector(collector) {
2489
3574
  this.collectors.add(collector);
2490
3575
  }
2491
3576
  _unregisterCollector(collector) {
2492
- const oid = collector.getOid();
3577
+ const key = collector.getCacheKey();
2493
3578
  this.collectors.delete(collector);
2494
- this.collectorCache.delete(oid);
2495
- this._interactionFilter.onUnregisterCollector(oid);
2496
- }
2497
- _updateWebGLLimits() {
2498
- const gl = this.renderer.getContext();
2499
- this.maxUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
3579
+ this.collectorCache.delete(key);
3580
+ this._interactionFilter.onUnregisterCollector(key);
2500
3581
  }
2501
3582
  /**
2502
- * Dynamically calculate FEATURE_ID_COUNT based on WebGL limits and current oid count
3583
+ * 遍历所有已加载瓦片,应用可见性过滤
2503
3584
  */
2504
- _calculateFeatureIdCount() {
2505
- const maxUniformVectors = this.maxUniformVectors;
2506
- const currentOidCount = this.oids.length;
2507
- if (currentOidCount > maxUniformVectors) throw new Error(`The number of OIDs to hide (${currentOidCount}) exceeds the WebGL MAX_FRAGMENT_UNIFORM_VECTORS limit (${maxUniformVectors}).`);
2508
- const minFeatureIdCount = 32;
2509
- if (currentOidCount <= minFeatureIdCount) return minFeatureIdCount;
2510
- const powerOf2 = Math.ceil(Math.log2(currentOidCount));
2511
- return Math.pow(2, powerOf2);
3585
+ _applyVisibilityToAllTiles() {
3586
+ if (!this.tiles) return;
3587
+ const hiddenSet = new Set(this.oids);
3588
+ this.tiles.traverse((tile) => {
3589
+ const tileWithCache = tile;
3590
+ if (tileWithCache.engineData?.scene) applyVisibilityToScene(tileWithCache.engineData.scene, hiddenSet);
3591
+ return true;
3592
+ }, null);
2512
3593
  }
2513
3594
  /**
2514
- * Set up shader modification for hiding specific features
3595
+ * 设置材质(DoubleSide 等基础配置)
2515
3596
  */
2516
3597
  _setupMaterial(mesh) {
2517
3598
  const material = mesh.material;
2518
3599
  if (material.userData._meshHelperSetup) return;
2519
3600
  material.userData._meshHelperSetup = true;
2520
3601
  material.side = DoubleSide;
2521
- const previousOnBeforeCompile = material.onBeforeCompile;
2522
- if (!material.defines) material.defines = {};
2523
- material.userData._materialFeatureIdCount = this.featureIdCount;
2524
- Object.defineProperty(material.defines, "FEATURE_ID_COUNT", {
2525
- get: () => {
2526
- if (material.userData._materialFeatureIdCount !== this.featureIdCount) {
2527
- material.userData._materialFeatureIdCount = this.featureIdCount;
2528
- material.needsUpdate = true;
2529
- }
2530
- return material.userData._materialFeatureIdCount;
2531
- },
2532
- enumerable: true,
2533
- configurable: true
2534
- });
2535
- material.onBeforeCompile = (shader, renderer) => {
2536
- previousOnBeforeCompile?.call(material, shader, renderer);
2537
- if (shader.vertexShader.includes("varying float vFeatureId;")) return;
2538
- shader.uniforms.hiddenFeatureIds = new FeatureIdUniforms(mesh, this);
2539
- shader.vertexShader = shader.vertexShader.replace("#include <common>", `#include <common>
2540
- attribute float _feature_id_0;
2541
- varying float vFeatureId;`);
2542
- shader.vertexShader = shader.vertexShader.replace("#include <begin_vertex>", `#include <begin_vertex>
2543
- vFeatureId = _feature_id_0;`);
2544
- shader.fragmentShader = shader.fragmentShader.replace("#include <common>", `#include <common>
2545
- uniform float hiddenFeatureIds[FEATURE_ID_COUNT];
2546
- varying float vFeatureId;
2547
-
2548
- bool shouldHideFeature(float featureId) {
2549
- for(int i = 0; i < FEATURE_ID_COUNT; i++) {
2550
- if(abs(hiddenFeatureIds[i] - featureId) < 0.001) {
2551
- return true;
2552
- }
2553
- }
2554
- return false;
2555
- }`);
2556
- shader.fragmentShader = shader.fragmentShader.replace("void main() {", `void main() {
2557
- if(shouldHideFeature(vFeatureId)) {
2558
- discard;
2559
- }`);
2560
- };
2561
3602
  }
2562
3603
  /**
2563
3604
  * Query feature information from intersection
@@ -2610,44 +3651,112 @@ var GLTFParserPlugin = class {
2610
3651
  return this._interactionFilter.getIsolatedOids();
2611
3652
  }
2612
3653
  /**
2613
- * 内部方法:根据 oid 获取 mesh 数组
3654
+ * 合并 OID 列表对应的结构 bbox;若无可用 bbox 则使用 split mesh 世界包围盒并求中心。
2614
3655
  */
2615
- _getMeshesByOidInternal(oid) {
2616
- const tileMeshes = getTileMeshesByOid(this.tiles, oid);
2617
- const allSplitMeshes = [];
2618
- for (const tileMesh of tileMeshes) {
2619
- const cacheKey = `${oid}_${tileMesh.uuid}`;
2620
- let splitMeshes = this.splitMeshCache.get(cacheKey);
2621
- if (!splitMeshes) {
2622
- splitMeshes = getSplitMeshesFromTile(tileMesh, oid);
2623
- this.splitMeshCache.set(cacheKey, splitMeshes);
3656
+ _getCenterFromOidList(oids) {
3657
+ this._syncStructureFromTileset();
3658
+ const union = new Box3();
3659
+ let hasStructureBox = false;
3660
+ for (const oid of oids) {
3661
+ const b = this.getBoundingBoxByOid(oid);
3662
+ if (b && !b.isEmpty()) if (!hasStructureBox) {
3663
+ union.copy(b);
3664
+ hasStructureBox = true;
3665
+ } else union.union(b);
3666
+ }
3667
+ if (hasStructureBox && !union.isEmpty()) return union.getCenter(new Vector3());
3668
+ const meshes = this._getMeshesByOidsInternal(oids);
3669
+ if (meshes.length === 0) return null;
3670
+ const meshBox = new Box3();
3671
+ for (const mesh of meshes) {
3672
+ mesh.updateMatrixWorld(true);
3673
+ meshBox.expandByObject(mesh);
3674
+ }
3675
+ if (meshBox.isEmpty()) return null;
3676
+ return meshBox.getCenter(new Vector3());
3677
+ }
3678
+ /**
3679
+ * 按 OID 集合:每个瓦片 mesh 只生成 **一个** 合并后的 split mesh(同一组 oid / condition 一条几何)
3680
+ */
3681
+ _getMergedSplitMeshesForOidSet(oidSet) {
3682
+ if (!this.tiles || oidSet.size === 0) return [];
3683
+ const sortedKey = [...oidSet].sort((a, b) => a - b).join(",");
3684
+ const result = [];
3685
+ const candidateTiles = /* @__PURE__ */ new Set();
3686
+ for (const oid of oidSet) for (const tm of getTileMeshesByOid(this.tiles, oid)) candidateTiles.add(tm);
3687
+ for (const tileMesh of candidateTiles) {
3688
+ const cacheKey = `merged|${tileMesh.uuid}|${sortedKey}`;
3689
+ let cached = this.splitMeshCache.get(cacheKey);
3690
+ if (!cached) {
3691
+ const m = splitMeshByOidsMerged(tileMesh, oidSet);
3692
+ cached = m ? [m] : [];
3693
+ this.splitMeshCache.set(cacheKey, cached);
2624
3694
  }
2625
- allSplitMeshes.push(...splitMeshes);
3695
+ result.push(...cached);
2626
3696
  }
2627
- return allSplitMeshes;
3697
+ return result;
2628
3698
  }
2629
3699
  /**
2630
- * 根据 oid 获取 MeshCollector
2631
- * MeshCollector 会监听瓦片变化,自动更新 meshes 并触发 mesh-change 事件
2632
- * 内部缓存:相同 oid 多次调用会返回同一个 collector 实例
3700
+ * 内部方法:根据单个 oid 获取 split mesh(每瓦片合并为一条)
2633
3701
  */
2634
- getMeshCollectorByOid(oid) {
2635
- const existing = this.collectorCache.get(oid);
3702
+ _getMeshesByOidInternal(oid) {
3703
+ return this._getMergedSplitMeshesForOidSet(new Set([oid]));
3704
+ }
3705
+ /**
3706
+ * 内部方法:根据多个 oid 获取合并 split mesh(每瓦片一条,而非每 oid 一条)
3707
+ */
3708
+ _getMeshesByOidsInternal(oids) {
3709
+ return this._getMergedSplitMeshesForOidSet(new Set(oids));
3710
+ }
3711
+ /**
3712
+ * 按查询收集 mesh:可只传 oids、只传 condition(全场景 OID 上筛选)、或两者组合
3713
+ * condition 与 setStyle 的 show / conditions 中字符串表达式语义一致
3714
+ */
3715
+ _getMeshesForCollectorQueryInternal(params) {
3716
+ if (!this.tiles) return [];
3717
+ const cond = params.condition?.trim();
3718
+ let targetOids;
3719
+ if (!cond) {
3720
+ if (params.oids.length === 0) return [];
3721
+ targetOids = [...new Set(params.oids)].sort((a, b) => a - b);
3722
+ } else {
3723
+ const candidate = params.oids.length === 0 ? getAllOidsFromTiles(this.tiles) : [...new Set(params.oids)];
3724
+ targetOids = [];
3725
+ for (const oid of candidate) if (evaluateStyleCondition(cond, getPropertyDataByOid(this.tiles, oid))) targetOids.push(oid);
3726
+ targetOids.sort((a, b) => a - b);
3727
+ }
3728
+ return this._getMeshesByOidsInternal(targetOids);
3729
+ }
3730
+ /**
3731
+ * 根据查询获取 MeshCollector(oids + 可选 condition,缓存键相同则复用实例)
3732
+ */
3733
+ getMeshCollectorByCondition(query) {
3734
+ const hasOids = normalizeMeshCollectorOids(query.oids ?? []).length > 0;
3735
+ const hasCond = Boolean(query.condition?.trim());
3736
+ if (!hasOids && !hasCond) throw new Error("getMeshCollectorByCondition requires non-empty oids and/or a condition string");
3737
+ const key = meshCollectorQueryCacheKey(query);
3738
+ const existing = this.collectorCache.get(key);
2636
3739
  if (existing) return existing;
2637
- const collector = new MeshCollector(oid, this);
2638
- this.collectorCache.set(oid, collector);
2639
- this._interactionFilter.onCollectorMeshChange(oid, collector.meshes);
3740
+ const collector = new MeshCollector(query, this);
3741
+ this.collectorCache.set(key, collector);
3742
+ this._interactionFilter.onCollectorMeshChange(key, collector.meshes);
2640
3743
  collector.addEventListener("mesh-change", (event) => {
2641
- this._interactionFilter.onCollectorMeshChange(oid, event.meshes);
3744
+ this._interactionFilter.onCollectorMeshChange(key, event.meshes);
2642
3745
  });
2643
3746
  return collector;
2644
3747
  }
2645
3748
  /**
3749
+ * 根据单个 oid 获取 MeshCollector(等价于 getMeshCollectorByCondition({ oids: [oid] }))
3750
+ */
3751
+ getMeshCollectorByOid(oid) {
3752
+ return this.getMeshCollectorByCondition({ oids: [oid] });
3753
+ }
3754
+ /**
2646
3755
  * Hide the corresponding part of the original mesh according to the OID array
2647
3756
  */
2648
3757
  hidePartsByOids(oids) {
2649
3758
  this.oids = oids;
2650
- this.featureIdCount = this._calculateFeatureIdCount();
3759
+ this._applyVisibilityToAllTiles();
2651
3760
  }
2652
3761
  /**
2653
3762
  * Restore the display of the corresponding mesh according to the OID array
@@ -2655,7 +3764,7 @@ var GLTFParserPlugin = class {
2655
3764
  showPartsByOids(oids) {
2656
3765
  const oidSet = new Set(oids);
2657
3766
  this.oids = this.oids.filter((existingOid) => !oidSet.has(existingOid));
2658
- this.featureIdCount = this._calculateFeatureIdCount();
3767
+ this._applyVisibilityToAllTiles();
2659
3768
  }
2660
3769
  /**
2661
3770
  * 根据 oid 数组设置构件颜色
@@ -2746,17 +3855,56 @@ var GLTFParserPlugin = class {
2746
3855
  this._partFrameHelper?.setFrameEdgeColor(oids, color);
2747
3856
  }
2748
3857
  /**
3858
+ * 设置构件样式(条件可见性 + 条件材质)
3859
+ * @param style 样式配置,传 null 清除样式
3860
+ */
3861
+ setStyle(style) {
3862
+ this._styleHelper?.setStyle(style);
3863
+ }
3864
+ /**
3865
+ * 当前样式配置,只读
3866
+ */
3867
+ get style() {
3868
+ return this._styleHelper?.style ?? null;
3869
+ }
3870
+ /**
3871
+ * 清除构件样式
3872
+ */
3873
+ clearStyle() {
3874
+ this._styleHelper?.clearStyle();
3875
+ }
3876
+ /**
3877
+ * 高亮指定构件(语义与 setStyle 一致:show、conditions、可选 oids,另需 name 标识分组)
3878
+ * @param options 高亮配置
3879
+ */
3880
+ highlight(options) {
3881
+ this._partHighlightHelper?.highlight(options);
3882
+ }
3883
+ /**
3884
+ * 取消指定名称的高亮
3885
+ * @param name 高亮组名称
3886
+ */
3887
+ cancelHighlight(name) {
3888
+ this._partHighlightHelper?.cancelHighlight(name);
3889
+ }
3890
+ /**
3891
+ * 取消所有高亮
3892
+ */
3893
+ cancelAllHighlight() {
3894
+ this._partHighlightHelper?.cancelAllHighlight();
3895
+ }
3896
+ /**
2749
3897
  * Restore the original materials of the mesh
2750
3898
  */
2751
3899
  showAllParts() {
2752
3900
  this.oids = [];
2753
- this.featureIdCount = this._calculateFeatureIdCount();
3901
+ this._applyVisibilityToAllTiles();
2754
3902
  }
2755
3903
  /**
2756
- * Get the current feature ID count
3904
+ * 获取当前隐藏的 OID 数量(兼容旧 API)
2757
3905
  */
2758
3906
  getFeatureIdCount() {
2759
- return this.featureIdCount;
3907
+ return this.oids.length;
2760
3908
  }
2761
3909
  /**
2762
3910
  * Plugin disposal
@@ -2766,6 +3914,7 @@ var GLTFParserPlugin = class {
2766
3914
  this.tiles.manager.removeHandler(this._gltfRegex);
2767
3915
  this.tiles.removeEventListener("load-model", this._onLoadModelCB);
2768
3916
  this.tiles.removeEventListener("tiles-load-end", this._onTilesLoadEndCB);
3917
+ this.tiles.removeEventListener("load-root-tileset", this._onLoadRootTilesetCB);
2769
3918
  }
2770
3919
  if (this._loader) this._loader.removeListeners();
2771
3920
  for (const collector of this.collectors) collector.dispose();
@@ -2774,7 +3923,7 @@ var GLTFParserPlugin = class {
2774
3923
  this.splitMeshCache.clear();
2775
3924
  this._structureData = null;
2776
3925
  this._oidNodeMap.clear();
2777
- this._structurePromise = null;
3926
+ this._structureEmbedResolved = false;
2778
3927
  this._modelInfo = null;
2779
3928
  this._modelInfoPromise = null;
2780
3929
  this._interactionFilter.dispose();
@@ -2783,11 +3932,15 @@ var GLTFParserPlugin = class {
2783
3932
  this._partBlinkHelper = null;
2784
3933
  this._partFrameHelper?.dispose();
2785
3934
  this._partFrameHelper = null;
3935
+ this._styleHelper?.dispose();
3936
+ this._styleHelper = null;
3937
+ this._partHighlightHelper?.dispose();
3938
+ this._partHighlightHelper = null;
2786
3939
  this._loader = null;
2787
3940
  this.tiles = null;
2788
3941
  }
2789
3942
  };
2790
3943
  //#endregion
2791
- export { GLTFParserPlugin, MeshCollector };
3944
+ export { GLTFParserPlugin, MeshCollector, clearStyleConditionCache, decodeGzipBase64DataUriSync, evaluateStyleCondition, getStructureDataUriFromTileset, meshCollectorGroupKey, meshCollectorQueryCacheKey, normalizeMeshCollectorOids, parseEmbeddedStructureDataFromTilesSync };
2792
3945
 
2793
3946
  //# sourceMappingURL=gltf-parser-plugin.module.js.map