gltf-parser-plugin 1.1.6 → 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$1(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 [];
@@ -1533,7 +2169,7 @@ function getMaterialForColor(color) {
1533
2169
  }
1534
2170
  var materialCache = /* @__PURE__ */ new Map();
1535
2171
  /**
1536
- * 构件着色/透明度辅助器,参考 example 逻辑:hideByOids -> 修改材质 -> scene.add -> mesh-change 监听
2172
+ * 构件着色/透明度辅助器,参考 example 逻辑:hidePartsByOids -> 修改材质 -> scene.add -> mesh-change 监听
1537
2173
  * 由 GLTFParserPlugin 内部使用,scene 通过 tiles.group 获取
1538
2174
  */
1539
2175
  var PartColorHelper = class {
@@ -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$1(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);
@@ -1589,7 +2225,7 @@ var PartColorHelper = class {
1589
2225
  collector.addEventListener("mesh-change", handler);
1590
2226
  }
1591
2227
  }
1592
- this.context.hideByOids(this.getAllModifiedOids());
2228
+ this.context.hidePartsByOids(this.getAllModifiedOids());
1593
2229
  }
1594
2230
  /**
1595
2231
  * 恢复指定构件的颜色
@@ -1624,7 +2260,7 @@ var PartColorHelper = class {
1624
2260
  }
1625
2261
  }
1626
2262
  }
1627
- this.context.unhideByOids(oids);
2263
+ this.context.showPartsByOids(oids);
1628
2264
  }
1629
2265
  /**
1630
2266
  * 根据 oid 数组设置构件透明度
@@ -1662,7 +2298,7 @@ var PartColorHelper = class {
1662
2298
  collector.addEventListener("mesh-change", handler);
1663
2299
  }
1664
2300
  }
1665
- this.context.hideByOids(this.getAllModifiedOids());
2301
+ this.context.hidePartsByOids(this.getAllModifiedOids());
1666
2302
  }
1667
2303
  /**
1668
2304
  * 恢复指定构件的透明度
@@ -1694,18 +2330,14 @@ var PartColorHelper = class {
1694
2330
  }
1695
2331
  }
1696
2332
  }
1697
- this.context.unhideByOids(oids);
2333
+ this.context.showPartsByOids(oids);
1698
2334
  }
1699
2335
  };
1700
2336
  //#endregion
1701
2337
  //#region src/plugin/PartBlinkHelper.ts
1702
- function ensureColor(color) {
1703
- if (color instanceof Color) return color;
1704
- return new Color(color);
1705
- }
1706
2338
  /**
1707
2339
  * 构件闪烁强调辅助器
1708
- * 通过 hideByOids + split mesh + emissive 动画实现闪烁效果
2340
+ * 通过 hidePartsByOids + split mesh + emissive 动画实现闪烁效果
1709
2341
  */
1710
2342
  var PartBlinkHelper = class {
1711
2343
  blinkOids = /* @__PURE__ */ new Set();
@@ -1778,7 +2410,7 @@ var PartBlinkHelper = class {
1778
2410
  this.meshChangeHandlers.set(oid, handler);
1779
2411
  collector.addEventListener("mesh-change", handler);
1780
2412
  }
1781
- this.context.hideByOids(Array.from(this.blinkOids));
2413
+ this.context.hidePartsByOids(Array.from(this.blinkOids));
1782
2414
  if (this.blinkOids.size > 0) this.startAnimation();
1783
2415
  }
1784
2416
  /**
@@ -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(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);
@@ -1823,7 +2455,7 @@ var PartBlinkHelper = class {
1823
2455
  }
1824
2456
  }
1825
2457
  this.blinkOids.clear();
1826
- this.context.unhideByOids(oidsToUnhide);
2458
+ this.context.showPartsByOids(oidsToUnhide);
1827
2459
  }
1828
2460
  dispose() {
1829
2461
  this.clearAllBlinkParts();
@@ -1833,41 +2465,54 @@ var PartBlinkHelper = class {
1833
2465
  //#region src/plugin/PartFrameHelper.ts
1834
2466
  /**
1835
2467
  * 构件线框显示辅助器
1836
- * 通过 hideByOids + split mesh + 填充材质 + EdgesGeometry 实现线框效果
2468
+ * 通过 hidePartsByOids + split mesh + 填充材质 + EdgesGeometry 实现线框效果
1837
2469
  */
2470
+ var DEFAULT_FRAME_COLOR = 54442;
1838
2471
  var PartFrameHelper = class {
1839
2472
  frameOids = /* @__PURE__ */ new Set();
1840
2473
  originalMaterialByMesh = /* @__PURE__ */ new Map();
1841
2474
  frameDataByOid = /* @__PURE__ */ new Map();
1842
2475
  meshChangeHandlers = /* @__PURE__ */ new Map();
1843
- fillMaterial;
1844
- edgeMaterial;
2476
+ fillColorByOid = /* @__PURE__ */ new Map();
2477
+ edgeColorByOid = /* @__PURE__ */ new Map();
2478
+ fillMaterialCache = /* @__PURE__ */ new Map();
2479
+ edgeMaterialCache = /* @__PURE__ */ new Map();
1845
2480
  edgeThreshold;
1846
2481
  constructor(context) {
1847
2482
  this.context = context;
1848
- this.fillMaterial = new MeshBasicMaterial({
1849
- color: 54442,
2483
+ this.edgeThreshold = 15;
2484
+ }
2485
+ getFillMaterial(hex) {
2486
+ if (!this.fillMaterialCache.has(hex)) this.fillMaterialCache.set(hex, new MeshBasicMaterial({
2487
+ color: hex,
1850
2488
  transparent: true,
1851
2489
  opacity: .3,
1852
2490
  side: DoubleSide,
1853
2491
  depthWrite: false
1854
- });
1855
- this.edgeMaterial = new MeshBasicMaterial({
1856
- color: 54442,
2492
+ }));
2493
+ return this.fillMaterialCache.get(hex);
2494
+ }
2495
+ getEdgeMaterial(hex) {
2496
+ if (!this.edgeMaterialCache.has(hex)) this.edgeMaterialCache.set(hex, new MeshBasicMaterial({
2497
+ color: hex,
1857
2498
  transparent: true,
1858
2499
  opacity: .8
1859
- });
1860
- this.edgeThreshold = 15;
2500
+ }));
2501
+ return this.edgeMaterialCache.get(hex);
1861
2502
  }
1862
- createWireframeForMeshes(meshes, scene) {
2503
+ createWireframeForMeshes(meshes, scene, oid) {
2504
+ const fillHex = this.fillColorByOid.get(oid) ?? DEFAULT_FRAME_COLOR;
2505
+ const edgeHex = this.edgeColorByOid.get(oid) ?? DEFAULT_FRAME_COLOR;
2506
+ const fillMaterial = this.getFillMaterial(fillHex);
2507
+ const edgeMaterial = this.getEdgeMaterial(edgeHex);
1863
2508
  const frameMeshes = [];
1864
2509
  const lines = [];
1865
2510
  for (const mesh of meshes) {
1866
2511
  if (!this.originalMaterialByMesh.has(mesh.uuid)) this.originalMaterialByMesh.set(mesh.uuid, mesh.material);
1867
- mesh.material = this.fillMaterial;
2512
+ mesh.material = fillMaterial;
1868
2513
  scene.add(mesh);
1869
2514
  frameMeshes.push(mesh);
1870
- const line = new LineSegments(new EdgesGeometry(mesh.geometry, this.edgeThreshold), this.edgeMaterial);
2515
+ const line = new LineSegments(new EdgesGeometry(mesh.geometry, this.edgeThreshold), edgeMaterial);
1871
2516
  line.matrix.copy(mesh.matrixWorld);
1872
2517
  line.matrixAutoUpdate = false;
1873
2518
  scene.add(line);
@@ -1898,7 +2543,7 @@ var PartFrameHelper = class {
1898
2543
  const collector = this.context.getMeshCollectorByOid(oid);
1899
2544
  const oldData = this.frameDataByOid.get(oid);
1900
2545
  if (oldData) this.removeFrameData(oldData, scene);
1901
- const newData = this.createWireframeForMeshes(collector.meshes, scene);
2546
+ const newData = this.createWireframeForMeshes(collector.meshes, scene, oid);
1902
2547
  this.frameDataByOid.set(oid, newData);
1903
2548
  }
1904
2549
  /**
@@ -1912,13 +2557,13 @@ var PartFrameHelper = class {
1912
2557
  for (const oid of oids) {
1913
2558
  this.frameOids.add(oid);
1914
2559
  const collector = this.context.getMeshCollectorByOid(oid);
1915
- const data = this.createWireframeForMeshes(collector.meshes, scene);
2560
+ const data = this.createWireframeForMeshes(collector.meshes, scene, oid);
1916
2561
  this.frameDataByOid.set(oid, data);
1917
2562
  const handler = () => this.applyFrameToOid(oid);
1918
2563
  this.meshChangeHandlers.set(oid, handler);
1919
2564
  collector.addEventListener("mesh-change", handler);
1920
2565
  }
1921
- this.context.hideByOids(Array.from(this.frameOids));
2566
+ this.context.hidePartsByOids(Array.from(this.frameOids));
1922
2567
  }
1923
2568
  /**
1924
2569
  * 清除所有线框显示构件
@@ -1940,20 +2585,484 @@ var PartFrameHelper = class {
1940
2585
  }
1941
2586
  }
1942
2587
  this.frameOids.clear();
1943
- this.context.unhideByOids(oidsToUnhide);
2588
+ this.fillColorByOid.clear();
2589
+ this.edgeColorByOid.clear();
2590
+ this.context.showPartsByOids(oidsToUnhide);
2591
+ }
2592
+ /**
2593
+ * 设置指定构件的线框填充颜色
2594
+ * @param oids 构件 OID 数组
2595
+ * @param color 颜色值,支持 hex 数字、颜色字符串(如 "#ff0000")、THREE.Color 对象
2596
+ */
2597
+ setFrameFillColor(oids, color) {
2598
+ const hex = toColor(color).getHex();
2599
+ for (const oid of oids) {
2600
+ if (!this.frameOids.has(oid)) continue;
2601
+ this.fillColorByOid.set(oid, hex);
2602
+ this.applyFrameToOid(oid);
2603
+ }
2604
+ }
2605
+ /**
2606
+ * 设置指定构件的线框边框颜色
2607
+ * @param oids 构件 OID 数组
2608
+ * @param color 颜色值,支持 hex 数字、颜色字符串(如 "#ff0000")、THREE.Color 对象
2609
+ */
2610
+ setFrameEdgeColor(oids, color) {
2611
+ const hex = toColor(color).getHex();
2612
+ for (const oid of oids) {
2613
+ if (!this.frameOids.has(oid)) continue;
2614
+ this.edgeColorByOid.set(oid, hex);
2615
+ this.applyFrameToOid(oid);
2616
+ }
1944
2617
  }
1945
2618
  dispose() {
1946
2619
  this.clearAllFrameParts();
2620
+ this.fillMaterialCache.forEach((m) => m.dispose());
2621
+ this.fillMaterialCache.clear();
2622
+ this.edgeMaterialCache.forEach((m) => m.dispose());
2623
+ this.edgeMaterialCache.clear();
2624
+ }
2625
+ };
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();
1947
3054
  }
1948
3055
  };
1949
3056
  //#endregion
1950
3057
  //#region src/plugin/InteractionFilter.ts
1951
3058
  /**
1952
- * 冻结与隔离逻辑:管理构件的交互过滤及 getMeshCollectorByOid 获取的 mesh 在场景中的显隐
3059
+ * 冻结与隔离逻辑:管理构件的交互过滤及 MeshCollector 获取的 mesh 在场景中的显隐
3060
+ * split mesh 使用 userData.oid(单 feature)或 userData.collectorOids(合并 mesh):任一相关 OID 被冻结/隔离规则命中则整 mesh 脱离场景
1953
3061
  */
1954
3062
  var InteractionFilter = class {
1955
3063
  frozenOids = /* @__PURE__ */ new Set();
1956
3064
  isolatedOids = /* @__PURE__ */ new Set();
3065
+ /** 按 collector 分组键追踪 mesh */
1957
3066
  trackedMeshes = /* @__PURE__ */ new Map();
1958
3067
  meshListeners = /* @__PURE__ */ new Map();
1959
3068
  isPluginRemoving = false;
@@ -1965,12 +3074,19 @@ var InteractionFilter = class {
1965
3074
  if (this.isolatedOids.size > 0 && !this.isolatedOids.has(oid)) return true;
1966
3075
  return false;
1967
3076
  }
1968
- 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) {
1969
3085
  if (this.meshListeners.has(mesh)) return;
1970
3086
  const onAdded = () => {
1971
3087
  if (this.isPluginRemoving) return;
1972
3088
  mesh.userData._detachedParent = null;
1973
- if (this.isOidBlocked(oid) && mesh.parent) {
3089
+ if (this.isMeshInteractionBlocked(mesh) && mesh.parent) {
1974
3090
  const parent = mesh.parent;
1975
3091
  this.isPluginRemoving = true;
1976
3092
  mesh.userData._detachedParent = parent;
@@ -1998,8 +3114,8 @@ var InteractionFilter = class {
1998
3114
  }
1999
3115
  mesh.userData._detachedParent = null;
2000
3116
  }
2001
- onCollectorMeshChange(oid, newMeshes) {
2002
- const tracked = this.trackedMeshes.get(oid);
3117
+ onCollectorMeshChange(groupKey, newMeshes) {
3118
+ const tracked = this.trackedMeshes.get(groupKey);
2003
3119
  const newSet = new Set(newMeshes);
2004
3120
  if (tracked) {
2005
3121
  for (const mesh of tracked) if (!newSet.has(mesh)) {
@@ -2009,39 +3125,36 @@ var InteractionFilter = class {
2009
3125
  }
2010
3126
  const trackSet = tracked || /* @__PURE__ */ new Set();
2011
3127
  for (const mesh of newMeshes) if (!trackSet.has(mesh)) {
2012
- this.trackMesh(mesh, oid);
3128
+ this.trackMesh(mesh);
2013
3129
  trackSet.add(mesh);
2014
3130
  }
2015
- this.trackedMeshes.set(oid, trackSet);
3131
+ this.trackedMeshes.set(groupKey, trackSet);
2016
3132
  }
2017
3133
  syncCollectorMeshes() {
2018
3134
  this.isPluginRemoving = true;
2019
- for (const [oid, collector] of this.context.getCollectorCache()) {
2020
- const blocked = this.isOidBlocked(oid);
2021
- for (const mesh of collector.meshes) {
2022
- if (!this.meshListeners.has(mesh)) continue;
2023
- if (blocked) {
2024
- if (mesh.parent && !mesh.userData._detachedParent) {
2025
- const parent = mesh.parent;
2026
- mesh.userData._detachedParent = parent;
2027
- parent.remove(mesh);
2028
- }
2029
- } else {
2030
- const storedParent = mesh.userData._detachedParent;
2031
- if (storedParent && !mesh.parent) {
2032
- storedParent.add(mesh);
2033
- mesh.userData._detachedParent = null;
2034
- }
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;
2035
3148
  }
2036
3149
  }
2037
3150
  }
2038
3151
  this.isPluginRemoving = false;
2039
3152
  }
2040
- onUnregisterCollector(oid) {
2041
- const tracked = this.trackedMeshes.get(oid);
3153
+ onUnregisterCollector(groupKey) {
3154
+ const tracked = this.trackedMeshes.get(groupKey);
2042
3155
  if (tracked) {
2043
3156
  for (const mesh of tracked) this.untrackMesh(mesh);
2044
- this.trackedMeshes.delete(oid);
3157
+ this.trackedMeshes.delete(groupKey);
2045
3158
  }
2046
3159
  }
2047
3160
  freezeByOids(oids) {
@@ -2049,16 +3162,14 @@ var InteractionFilter = class {
2049
3162
  this.syncCollectorMeshes();
2050
3163
  }
2051
3164
  freezeByOid(oid) {
2052
- this.frozenOids.add(oid);
2053
- this.syncCollectorMeshes();
3165
+ this.freezeByOids([oid]);
2054
3166
  }
2055
3167
  unfreezeByOids(oids) {
2056
3168
  for (const oid of oids) this.frozenOids.delete(oid);
2057
3169
  this.syncCollectorMeshes();
2058
3170
  }
2059
3171
  unfreezeByOid(oid) {
2060
- this.frozenOids.delete(oid);
2061
- this.syncCollectorMeshes();
3172
+ this.unfreezeByOids([oid]);
2062
3173
  }
2063
3174
  unfreeze() {
2064
3175
  this.frozenOids.clear();
@@ -2080,8 +3191,7 @@ var InteractionFilter = class {
2080
3191
  this.syncCollectorMeshes();
2081
3192
  }
2082
3193
  unisolateByOid(oid) {
2083
- this.isolatedOids.delete(oid);
2084
- this.syncCollectorMeshes();
3194
+ this.unisolateByOids([oid]);
2085
3195
  }
2086
3196
  unisolate() {
2087
3197
  this.isolatedOids.clear();
@@ -2193,18 +3303,23 @@ var GLTFParserPlugin = class {
2193
3303
  _options;
2194
3304
  _structureData = null;
2195
3305
  _oidNodeMap = /* @__PURE__ */ new Map();
2196
- _structurePromise = null;
3306
+ /** rootTileset 已存在且已尝试过内嵌解析后仍为 null,则不再重复 gunzip */
3307
+ _structureEmbedResolved = false;
2197
3308
  _modelInfo = null;
2198
3309
  _modelInfoPromise = null;
2199
3310
  _interactionFilter;
2200
3311
  _partColorHelper = null;
2201
3312
  _partBlinkHelper = null;
2202
3313
  _partFrameHelper = null;
3314
+ _styleHelper = null;
3315
+ _partHighlightHelper = null;
2203
3316
  oids = [];
2204
- renderer = null;
3317
+ /** WebGLRenderer 实例,用于 mesh helper 等扩展 */
3318
+ get renderer() {
3319
+ return this._renderer;
3320
+ }
3321
+ _renderer = null;
2205
3322
  splitMeshCache = /* @__PURE__ */ new Map();
2206
- maxUniformVectors = 1024;
2207
- featureIdCount = 32;
2208
3323
  collectors = /* @__PURE__ */ new Set();
2209
3324
  collectorCache = /* @__PURE__ */ new Map();
2210
3325
  /**
@@ -2218,7 +3333,7 @@ var GLTFParserPlugin = class {
2218
3333
  useIndexedDB: false,
2219
3334
  ...options
2220
3335
  };
2221
- if (options?.renderer) this.renderer = options.renderer;
3336
+ if (options?.renderer) this._renderer = options.renderer;
2222
3337
  this._interactionFilter = new InteractionFilter({ getCollectorCache: () => this.collectorCache });
2223
3338
  setMaxWorkers(this._options.maxWorkers);
2224
3339
  }
@@ -2227,38 +3342,43 @@ var GLTFParserPlugin = class {
2227
3342
  */
2228
3343
  init(tiles) {
2229
3344
  this.tiles = tiles;
2230
- this._partColorHelper = new PartColorHelper({
2231
- hideByOids: (oids) => this.hideByOids(oids),
2232
- unhideByOids: (oids) => this.unhideByOids(oids),
2233
- getMeshCollectorByOid: (oid) => this.getMeshCollectorByOid(oid),
2234
- getScene: () => this.tiles?.group ?? null
2235
- });
2236
- this._partBlinkHelper = new PartBlinkHelper({
2237
- hideByOids: (oids) => this.hideByOids(oids),
2238
- unhideByOids: (oids) => this.unhideByOids(oids),
2239
- getMeshCollectorByOid: (oid) => this.getMeshCollectorByOid(oid),
2240
- getScene: () => this.tiles?.group ?? null
2241
- });
2242
- this._partFrameHelper = new PartFrameHelper({
2243
- hideByOids: (oids) => this.hideByOids(oids),
2244
- unhideByOids: (oids) => this.unhideByOids(oids),
2245
- getMeshCollectorByOid: (oid) => this.getMeshCollectorByOid(oid),
2246
- 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
2247
3355
  });
3356
+ this._partHighlightHelper = new PartHighlightHelper(partFx);
2248
3357
  this._loader = new GLTFWorkerLoader(tiles.manager, {
2249
3358
  metadata: this._options.metadata,
2250
3359
  materialBuilder: this._options.materialBuilder
2251
3360
  });
2252
3361
  tiles.manager.addHandler(this._gltfRegex, this._loader);
2253
- if (this.renderer) this._updateWebGLLimits();
2254
3362
  tiles.addEventListener("load-model", this._onLoadModelCB);
2255
3363
  tiles.addEventListener("tiles-load-end", this._onTilesLoadEndCB);
3364
+ tiles.addEventListener("load-root-tileset", this._onLoadRootTilesetCB);
3365
+ this._syncStructureFromTileset();
2256
3366
  tiles.traverse((tile) => {
2257
3367
  const tileWithCache = tile;
2258
- if (tileWithCache.cached?.scene) this._onLoadModel(tileWithCache.cached.scene);
3368
+ if (tileWithCache.engineData?.scene) this._onLoadModel(tileWithCache.engineData.scene);
2259
3369
  return true;
2260
3370
  }, null);
2261
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
+ }
2262
3382
  /**
2263
3383
  * Fetch tile data with IndexedDB caching support
2264
3384
  */
@@ -2290,56 +3410,51 @@ var GLTFParserPlugin = class {
2290
3410
  if (this._options.beforeParseTile) buffer = await this._options.beforeParseTile(buffer, tile, extension, uri, abortSignal);
2291
3411
  return this.tiles.parseTile(buffer, tile, extension, uri, abortSignal);
2292
3412
  }
2293
- _getStructureUrl() {
3413
+ /** 与 tileset 同目录的侧车 JSON,如 structure.json / modelInfo.json */
3414
+ _sidecarJsonUrl(fileName) {
2294
3415
  const rootURL = this.tiles?.rootURL;
2295
3416
  if (!rootURL) return null;
2296
- return rootURL.replace(/[^/]+$/, "structure.json");
3417
+ return rootURL.replace(/[^/]+$/, fileName);
2297
3418
  }
2298
3419
  _buildOidNodeMap(node, map) {
2299
3420
  if (node.id !== void 0) map.set(node.id, node);
2300
3421
  if (node.children) for (const child of node.children) this._buildOidNodeMap(child, map);
2301
3422
  }
2302
- async _fetchStructureData() {
2303
- const url = this._getStructureUrl();
2304
- if (!url) {
2305
- console.warn("[GLTFParserPlugin] Cannot derive structure.json URL: tiles not initialized");
2306
- return null;
2307
- }
2308
- try {
2309
- const response = await fetch(url);
2310
- if (!response.ok) {
2311
- console.warn(`[GLTFParserPlugin] Failed to fetch structure.json: ${response.status}`);
2312
- return null;
2313
- }
2314
- const data = await response.json();
2315
- this._structureData = data;
2316
- this._oidNodeMap.clear();
2317
- if (data.trees) for (const tree of data.trees) this._buildOidNodeMap(tree, this._oidNodeMap);
2318
- return data;
2319
- } catch (error) {
2320
- console.error("[GLTFParserPlugin] Error loading structure.json:", error);
2321
- return null;
2322
- }
2323
- }
2324
- 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() {
2325
3435
  if (this._structureData) return this._structureData;
2326
- if (!this._structurePromise) this._structurePromise = this._fetchStructureData();
2327
- 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;
2328
3445
  }
2329
3446
  /**
2330
- * 根据 oid 获取 structure.json 中对应的节点树数据
2331
- * 包含 bbox、children、name 等完整结构信息
2332
- * 首次调用时会自动从 tileset URL 推导并请求 structure.json
3447
+ * 根据 oid 获取结构树节点(数据来自 tileset 内嵌 structureUri 同步解压)
2333
3448
  */
2334
- async getNodeTreeByOid(oid) {
2335
- await this._ensureStructureLoaded();
3449
+ getNodeTreeByOid(oid) {
3450
+ this._syncStructureFromTileset();
2336
3451
  return this._oidNodeMap.get(oid) ?? null;
2337
3452
  }
2338
3453
  /**
2339
- * 根据 oid 数组批量获取 structure.json 中对应的节点树数据
3454
+ * 根据 oid 数组批量获取结构树节点
2340
3455
  */
2341
- async getNodeTreeByOids(oids) {
2342
- await this._ensureStructureLoaded();
3456
+ getNodeTreeByOids(oids) {
3457
+ this._syncStructureFromTileset();
2343
3458
  const result = /* @__PURE__ */ new Map();
2344
3459
  for (const oid of oids) {
2345
3460
  const node = this._oidNodeMap.get(oid);
@@ -2348,41 +3463,58 @@ var GLTFParserPlugin = class {
2348
3463
  return result;
2349
3464
  }
2350
3465
  /**
2351
- * 获取完整的 structure.json 数据
2352
- * 首次调用时会自动请求
3466
+ * 根据 oid 从结构数据取轴对齐包围盒(`bbox` 为 `[minX,minY,minZ,maxX,maxY,maxZ]`,与 `selectByBox` 一致)
3467
+ * @returns 无对应节点或缺少有效 bbox 时返回 `null`
3468
+ */
3469
+ getBoundingBoxByOid(oid) {
3470
+ this._syncStructureFromTileset();
3471
+ return bboxArrayToBox3(this._oidNodeMap.get(oid)?.bbox);
3472
+ }
3473
+ /**
3474
+ * 计算给定 OID 集合的几何中心(世界坐标系与结构 bbox / 瓦片 mesh 一致)。
3475
+ * 优先合并结构树中的轴对齐 bbox;若无有效 bbox 则合并对应 split mesh 的世界包围盒。
3476
+ */
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 一致)
2353
3498
  */
2354
- async getStructureData() {
2355
- return this._ensureStructureLoaded();
3499
+ getStructureData() {
3500
+ return this._syncStructureFromTileset();
2356
3501
  }
2357
3502
  /**
2358
- * 选择包围盒范围内的构件(包含相交和包含两种情况)
2359
- * @param box 查询用的 Box3 范围,坐标系与 structure.json 中 bbox 一致
2360
- * @returns 范围内所有构件的 oid 数组
3503
+ * 选择包围盒范围内的构件(坐标系与结构 bbox 一致)
2361
3504
  */
2362
- async selectByBox(box) {
2363
- await this._ensureStructureLoaded();
3505
+ selectByBox(box) {
3506
+ this._syncStructureFromTileset();
2364
3507
  return selectByBoxFromOidMap(this._oidNodeMap, box);
2365
3508
  }
2366
3509
  /**
2367
- * 选择多边形(平面投影)范围内的构件(包含相交和包含两种情况)
2368
- * @param polygon 多边形顶点数组(Vector3),按顺序连接构成闭合多边形
2369
- * @param axis 投影平面,决定使用 bbox 的哪两个轴做 2D 判定
2370
- * - 'xz'(默认):俯视图,取 bbox 的 x/z 坐标
2371
- * - 'xy':正视图,取 bbox 的 x/y 坐标
2372
- * - 'yz':侧视图,取 bbox 的 y/z 坐标
2373
- * @returns 范围内所有构件的 oid 数组
3510
+ * 选择多边形(平面投影)范围内的构件
2374
3511
  */
2375
- async selectByPolygon(polygon, axis = "xz") {
2376
- await this._ensureStructureLoaded();
3512
+ selectByPolygon(polygon, axis = "xz") {
3513
+ this._syncStructureFromTileset();
2377
3514
  return selectByPolygonFromOidMap(this._oidNodeMap, polygon, axis);
2378
3515
  }
2379
- _getModelInfoUrl() {
2380
- const rootURL = this.tiles?.rootURL;
2381
- if (!rootURL) return null;
2382
- return rootURL.replace(/[^/]+$/, "modelInfo.json");
2383
- }
2384
3516
  async _fetchModelInfo() {
2385
- const url = this._getModelInfoUrl();
3517
+ const url = this._sidecarJsonUrl("modelInfo.json");
2386
3518
  if (!url) {
2387
3519
  console.warn("[GLTFParserPlugin] Cannot derive modelInfo.json URL: tiles not initialized");
2388
3520
  return null;
@@ -2432,83 +3564,41 @@ var GLTFParserPlugin = class {
2432
3564
  scene.traverse((c) => {
2433
3565
  if (c.material) this._setupMaterial(c);
2434
3566
  });
3567
+ applyVisibilityToScene(scene, new Set(this.oids));
2435
3568
  }
2436
3569
  _notifyCollectors() {
2437
3570
  for (const collector of this.collectors) collector._updateMeshes();
3571
+ this._styleHelper?.onTilesLoadEnd();
2438
3572
  }
2439
3573
  _registerCollector(collector) {
2440
3574
  this.collectors.add(collector);
2441
3575
  }
2442
3576
  _unregisterCollector(collector) {
2443
- const oid = collector.getOid();
3577
+ const key = collector.getCacheKey();
2444
3578
  this.collectors.delete(collector);
2445
- this.collectorCache.delete(oid);
2446
- this._interactionFilter.onUnregisterCollector(oid);
2447
- }
2448
- _updateWebGLLimits() {
2449
- const gl = this.renderer.getContext();
2450
- this.maxUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS);
3579
+ this.collectorCache.delete(key);
3580
+ this._interactionFilter.onUnregisterCollector(key);
2451
3581
  }
2452
3582
  /**
2453
- * Dynamically calculate FEATURE_ID_COUNT based on WebGL limits and current oid count
3583
+ * 遍历所有已加载瓦片,应用可见性过滤
2454
3584
  */
2455
- _calculateFeatureIdCount() {
2456
- const maxUniformVectors = this.maxUniformVectors;
2457
- const currentOidCount = this.oids.length;
2458
- if (currentOidCount > maxUniformVectors) throw new Error(`The number of OIDs to hide (${currentOidCount}) exceeds the WebGL MAX_FRAGMENT_UNIFORM_VECTORS limit (${maxUniformVectors}).`);
2459
- const minFeatureIdCount = 32;
2460
- if (currentOidCount <= minFeatureIdCount) return minFeatureIdCount;
2461
- const powerOf2 = Math.ceil(Math.log2(currentOidCount));
2462
- 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);
2463
3593
  }
2464
3594
  /**
2465
- * Set up shader modification for hiding specific features
3595
+ * 设置材质(DoubleSide 等基础配置)
2466
3596
  */
2467
3597
  _setupMaterial(mesh) {
2468
3598
  const material = mesh.material;
2469
3599
  if (material.userData._meshHelperSetup) return;
2470
3600
  material.userData._meshHelperSetup = true;
2471
3601
  material.side = DoubleSide;
2472
- const previousOnBeforeCompile = material.onBeforeCompile;
2473
- if (!material.defines) material.defines = {};
2474
- material.userData._materialFeatureIdCount = this.featureIdCount;
2475
- Object.defineProperty(material.defines, "FEATURE_ID_COUNT", {
2476
- get: () => {
2477
- if (material.userData._materialFeatureIdCount !== this.featureIdCount) {
2478
- material.userData._materialFeatureIdCount = this.featureIdCount;
2479
- material.needsUpdate = true;
2480
- }
2481
- return material.userData._materialFeatureIdCount;
2482
- },
2483
- enumerable: true,
2484
- configurable: true
2485
- });
2486
- material.onBeforeCompile = (shader, renderer) => {
2487
- previousOnBeforeCompile?.call(material, shader, renderer);
2488
- if (shader.vertexShader.includes("varying float vFeatureId;")) return;
2489
- shader.uniforms.hiddenFeatureIds = new FeatureIdUniforms(mesh, this);
2490
- shader.vertexShader = shader.vertexShader.replace("#include <common>", `#include <common>
2491
- attribute float _feature_id_0;
2492
- varying float vFeatureId;`);
2493
- shader.vertexShader = shader.vertexShader.replace("#include <begin_vertex>", `#include <begin_vertex>
2494
- vFeatureId = _feature_id_0;`);
2495
- shader.fragmentShader = shader.fragmentShader.replace("#include <common>", `#include <common>
2496
- uniform float hiddenFeatureIds[FEATURE_ID_COUNT];
2497
- varying float vFeatureId;
2498
-
2499
- bool shouldHideFeature(float featureId) {
2500
- for(int i = 0; i < FEATURE_ID_COUNT; i++) {
2501
- if(abs(hiddenFeatureIds[i] - featureId) < 0.001) {
2502
- return true;
2503
- }
2504
- }
2505
- return false;
2506
- }`);
2507
- shader.fragmentShader = shader.fragmentShader.replace("void main() {", `void main() {
2508
- if(shouldHideFeature(vFeatureId)) {
2509
- discard;
2510
- }`);
2511
- };
2512
3602
  }
2513
3603
  /**
2514
3604
  * Query feature information from intersection
@@ -2561,52 +3651,120 @@ var GLTFParserPlugin = class {
2561
3651
  return this._interactionFilter.getIsolatedOids();
2562
3652
  }
2563
3653
  /**
2564
- * 内部方法:根据 oid 获取 mesh 数组
3654
+ * 合并 OID 列表对应的结构 bbox;若无可用 bbox 则使用 split mesh 世界包围盒并求中心。
2565
3655
  */
2566
- _getMeshesByOidInternal(oid) {
2567
- const tileMeshes = getTileMeshesByOid(this.tiles, oid);
2568
- const allSplitMeshes = [];
2569
- for (const tileMesh of tileMeshes) {
2570
- const cacheKey = `${oid}_${tileMesh.uuid}`;
2571
- let splitMeshes = this.splitMeshCache.get(cacheKey);
2572
- if (!splitMeshes) {
2573
- splitMeshes = getSplitMeshesFromTile(tileMesh, oid);
2574
- 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);
2575
3694
  }
2576
- allSplitMeshes.push(...splitMeshes);
3695
+ result.push(...cached);
2577
3696
  }
2578
- return allSplitMeshes;
3697
+ return result;
2579
3698
  }
2580
3699
  /**
2581
- * 根据 oid 获取 MeshCollector
2582
- * MeshCollector 会监听瓦片变化,自动更新 meshes 并触发 mesh-change 事件
2583
- * 内部缓存:相同 oid 多次调用会返回同一个 collector 实例
3700
+ * 内部方法:根据单个 oid 获取 split mesh(每瓦片合并为一条)
2584
3701
  */
2585
- getMeshCollectorByOid(oid) {
2586
- 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);
2587
3739
  if (existing) return existing;
2588
- const collector = new MeshCollector(oid, this);
2589
- this.collectorCache.set(oid, collector);
2590
- 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);
2591
3743
  collector.addEventListener("mesh-change", (event) => {
2592
- this._interactionFilter.onCollectorMeshChange(oid, event.meshes);
3744
+ this._interactionFilter.onCollectorMeshChange(key, event.meshes);
2593
3745
  });
2594
3746
  return collector;
2595
3747
  }
2596
3748
  /**
3749
+ * 根据单个 oid 获取 MeshCollector(等价于 getMeshCollectorByCondition({ oids: [oid] }))
3750
+ */
3751
+ getMeshCollectorByOid(oid) {
3752
+ return this.getMeshCollectorByCondition({ oids: [oid] });
3753
+ }
3754
+ /**
2597
3755
  * Hide the corresponding part of the original mesh according to the OID array
2598
3756
  */
2599
- hideByOids(oids) {
3757
+ hidePartsByOids(oids) {
2600
3758
  this.oids = oids;
2601
- this.featureIdCount = this._calculateFeatureIdCount();
3759
+ this._applyVisibilityToAllTiles();
2602
3760
  }
2603
3761
  /**
2604
3762
  * Restore the display of the corresponding mesh according to the OID array
2605
3763
  */
2606
- unhideByOids(oids) {
3764
+ showPartsByOids(oids) {
2607
3765
  const oidSet = new Set(oids);
2608
3766
  this.oids = this.oids.filter((existingOid) => !oidSet.has(existingOid));
2609
- this.featureIdCount = this._calculateFeatureIdCount();
3767
+ this._applyVisibilityToAllTiles();
2610
3768
  }
2611
3769
  /**
2612
3770
  * 根据 oid 数组设置构件颜色
@@ -2619,7 +3777,7 @@ var GLTFParserPlugin = class {
2619
3777
  }
2620
3778
  /**
2621
3779
  * 恢复指定构件的颜色
2622
- * 从场景移除 split mesh,unhide mesh
3780
+ * 从场景移除 split mesh,恢复原 mesh 显示
2623
3781
  * @param oids 构件 OID 数组
2624
3782
  */
2625
3783
  restorePartColorByOids(oids) {
@@ -2681,17 +3839,72 @@ var GLTFParserPlugin = class {
2681
3839
  this._partFrameHelper?.clearAllFrameParts();
2682
3840
  }
2683
3841
  /**
3842
+ * 设置指定构件的线框填充颜色
3843
+ * @param oids 构件 OID 数组
3844
+ * @param color 颜色值,支持 hex 数字、颜色字符串(如 "#ff0000")、THREE.Color 对象
3845
+ */
3846
+ setFrameFillColor(oids, color) {
3847
+ this._partFrameHelper?.setFrameFillColor(oids, color);
3848
+ }
3849
+ /**
3850
+ * 设置指定构件的线框边框颜色
3851
+ * @param oids 构件 OID 数组
3852
+ * @param color 颜色值,支持 hex 数字、颜色字符串(如 "#ff0000")、THREE.Color 对象
3853
+ */
3854
+ setFrameEdgeColor(oids, color) {
3855
+ this._partFrameHelper?.setFrameEdgeColor(oids, color);
3856
+ }
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
+ /**
2684
3897
  * Restore the original materials of the mesh
2685
3898
  */
2686
- unhide() {
3899
+ showAllParts() {
2687
3900
  this.oids = [];
2688
- this.featureIdCount = this._calculateFeatureIdCount();
3901
+ this._applyVisibilityToAllTiles();
2689
3902
  }
2690
3903
  /**
2691
- * Get the current feature ID count
3904
+ * 获取当前隐藏的 OID 数量(兼容旧 API)
2692
3905
  */
2693
3906
  getFeatureIdCount() {
2694
- return this.featureIdCount;
3907
+ return this.oids.length;
2695
3908
  }
2696
3909
  /**
2697
3910
  * Plugin disposal
@@ -2701,6 +3914,7 @@ var GLTFParserPlugin = class {
2701
3914
  this.tiles.manager.removeHandler(this._gltfRegex);
2702
3915
  this.tiles.removeEventListener("load-model", this._onLoadModelCB);
2703
3916
  this.tiles.removeEventListener("tiles-load-end", this._onTilesLoadEndCB);
3917
+ this.tiles.removeEventListener("load-root-tileset", this._onLoadRootTilesetCB);
2704
3918
  }
2705
3919
  if (this._loader) this._loader.removeListeners();
2706
3920
  for (const collector of this.collectors) collector.dispose();
@@ -2709,7 +3923,7 @@ var GLTFParserPlugin = class {
2709
3923
  this.splitMeshCache.clear();
2710
3924
  this._structureData = null;
2711
3925
  this._oidNodeMap.clear();
2712
- this._structurePromise = null;
3926
+ this._structureEmbedResolved = false;
2713
3927
  this._modelInfo = null;
2714
3928
  this._modelInfoPromise = null;
2715
3929
  this._interactionFilter.dispose();
@@ -2718,11 +3932,15 @@ var GLTFParserPlugin = class {
2718
3932
  this._partBlinkHelper = null;
2719
3933
  this._partFrameHelper?.dispose();
2720
3934
  this._partFrameHelper = null;
3935
+ this._styleHelper?.dispose();
3936
+ this._styleHelper = null;
3937
+ this._partHighlightHelper?.dispose();
3938
+ this._partHighlightHelper = null;
2721
3939
  this._loader = null;
2722
3940
  this.tiles = null;
2723
3941
  }
2724
3942
  };
2725
3943
  //#endregion
2726
- export { GLTFParserPlugin, MeshCollector };
3944
+ export { GLTFParserPlugin, MeshCollector, clearStyleConditionCache, decodeGzipBase64DataUriSync, evaluateStyleCondition, getStructureDataUriFromTileset, meshCollectorGroupKey, meshCollectorQueryCacheKey, normalizeMeshCollectorOids, parseEmbeddedStructureDataFromTilesSync };
2727
3945
 
2728
3946
  //# sourceMappingURL=gltf-parser-plugin.module.js.map