gltf-parser-plugin 1.1.1 → 1.1.3

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,4 +1,4 @@
1
- import { Mesh, Vector3, Triangle, BufferGeometry, EventDispatcher, DataTexture, RGBAFormat, UnsignedByteType, SRGBColorSpace, Texture, MeshStandardMaterial, DoubleSide, FrontSide, BufferAttribute, OrthographicCamera, Float32BufferAttribute, Vector2, WebGLRenderer, WebGLRenderTarget, ShaderMaterial, OneFactor, ZeroFactor, CustomBlending, Box2, Matrix4, Matrix3, Matrix2, Vector4, MeshBasicMaterial, Loader, Scene, Group, InstancedMesh, Quaternion } from "three";
1
+ import { Mesh, Vector3, Triangle, BufferGeometry, EventDispatcher, DataTexture, RGBAFormat, UnsignedByteType, SRGBColorSpace, Texture, MeshStandardMaterial, DoubleSide, FrontSide, BufferAttribute, OrthographicCamera, Float32BufferAttribute, Vector2, WebGLRenderer, WebGLRenderTarget, ShaderMaterial, OneFactor, ZeroFactor, CustomBlending, Box2, Matrix4, Matrix3, Matrix2, Vector4, MeshBasicMaterial, Loader, Scene, Group, InstancedMesh, Quaternion, Box3 } from "three";
2
2
  class FeatureIdUniforms {
3
3
  mesh;
4
4
  plugin;
@@ -1871,13 +1871,17 @@ class GLTFParserPlugin {
1871
1871
  async _fetchStructureData() {
1872
1872
  const url = this._getStructureUrl();
1873
1873
  if (!url) {
1874
- console.warn("[GLTFParserPlugin] Cannot derive structure.json URL: tiles not initialized");
1874
+ console.warn(
1875
+ "[GLTFParserPlugin] Cannot derive structure.json URL: tiles not initialized"
1876
+ );
1875
1877
  return null;
1876
1878
  }
1877
1879
  try {
1878
1880
  const response = await fetch(url);
1879
1881
  if (!response.ok) {
1880
- console.warn(`[GLTFParserPlugin] Failed to fetch structure.json: ${response.status}`);
1882
+ console.warn(
1883
+ `[GLTFParserPlugin] Failed to fetch structure.json: ${response.status}`
1884
+ );
1881
1885
  return null;
1882
1886
  }
1883
1887
  const data = await response.json();
@@ -1932,6 +1936,142 @@ class GLTFParserPlugin {
1932
1936
  return this._ensureStructureLoaded();
1933
1937
  }
1934
1938
  // =============================================
1939
+ // Spatial Query Methods
1940
+ // =============================================
1941
+ _pointInPolygon(px, py, polygon) {
1942
+ let inside = false;
1943
+ const n = polygon.length;
1944
+ for (let i = 0, j = n - 1; i < n; j = i++) {
1945
+ const xi = polygon[i].x, yi = polygon[i].y;
1946
+ const xj = polygon[j].x, yj = polygon[j].y;
1947
+ if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi) {
1948
+ inside = !inside;
1949
+ }
1950
+ }
1951
+ return inside;
1952
+ }
1953
+ _segmentsIntersect(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2) {
1954
+ const cross = (ox, oy, ax, ay, bx, by) => (ax - ox) * (by - oy) - (ay - oy) * (bx - ox);
1955
+ const d1 = cross(bx1, by1, bx2, by2, ax1, ay1);
1956
+ const d2 = cross(bx1, by1, bx2, by2, ax2, ay2);
1957
+ const d3 = cross(ax1, ay1, ax2, ay2, bx1, by1);
1958
+ const d4 = cross(ax1, ay1, ax2, ay2, bx2, by2);
1959
+ if ((d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d3 > 0 && d4 < 0 || d3 < 0 && d4 > 0)) {
1960
+ return true;
1961
+ }
1962
+ const onSeg = (px, py, qx, qy, rx, ry) => Math.min(px, qx) <= rx && rx <= Math.max(px, qx) && Math.min(py, qy) <= ry && ry <= Math.max(py, qy);
1963
+ if (d1 === 0 && onSeg(bx1, by1, bx2, by2, ax1, ay1)) return true;
1964
+ if (d2 === 0 && onSeg(bx1, by1, bx2, by2, ax2, ay2)) return true;
1965
+ if (d3 === 0 && onSeg(ax1, ay1, ax2, ay2, bx1, by1)) return true;
1966
+ if (d4 === 0 && onSeg(ax1, ay1, ax2, ay2, bx2, by2)) return true;
1967
+ return false;
1968
+ }
1969
+ _polygonIntersectsRect(polygon, minX, minY, maxX, maxY) {
1970
+ const n = polygon.length;
1971
+ for (let i = 0; i < n; i++) {
1972
+ const p = polygon[i];
1973
+ if (p.x >= minX && p.x <= maxX && p.y >= minY && p.y <= maxY) {
1974
+ return true;
1975
+ }
1976
+ }
1977
+ if (this._pointInPolygon(minX, minY, polygon) || this._pointInPolygon(maxX, minY, polygon) || this._pointInPolygon(maxX, maxY, polygon) || this._pointInPolygon(minX, maxY, polygon)) {
1978
+ return true;
1979
+ }
1980
+ const rx = [minX, maxX, maxX, minX];
1981
+ const ry = [minY, minY, maxY, maxY];
1982
+ for (let i = 0; i < n; i++) {
1983
+ const a = polygon[i];
1984
+ const b = polygon[(i + 1) % n];
1985
+ for (let j = 0; j < 4; j++) {
1986
+ const k = (j + 1) % 4;
1987
+ if (this._segmentsIntersect(
1988
+ a.x,
1989
+ a.y,
1990
+ b.x,
1991
+ b.y,
1992
+ rx[j],
1993
+ ry[j],
1994
+ rx[k],
1995
+ ry[k]
1996
+ )) {
1997
+ return true;
1998
+ }
1999
+ }
2000
+ }
2001
+ return false;
2002
+ }
2003
+ /**
2004
+ * 选择包围盒范围内的构件(包含相交和包含两种情况)
2005
+ * @param box 查询用的 Box3 范围,坐标系与 structure.json 中 bbox 一致
2006
+ * @returns 范围内所有构件的 oid 数组
2007
+ */
2008
+ async selectByBox(box) {
2009
+ await this._ensureStructureLoaded();
2010
+ const result = [];
2011
+ const nodeBox = new Box3();
2012
+ for (const [oid, node] of this._oidNodeMap) {
2013
+ if (!node.bbox || node.bbox.length < 6) continue;
2014
+ nodeBox.min.set(node.bbox[0], node.bbox[1], node.bbox[2]);
2015
+ nodeBox.max.set(node.bbox[3], node.bbox[4], node.bbox[5]);
2016
+ if (box.intersectsBox(nodeBox)) {
2017
+ result.push(oid);
2018
+ }
2019
+ }
2020
+ return result;
2021
+ }
2022
+ /**
2023
+ * 选择多边形(平面投影)范围内的构件(包含相交和包含两种情况)
2024
+ * @param polygon 多边形顶点数组(Vector3),按顺序连接构成闭合多边形
2025
+ * @param axis 投影平面,决定使用 bbox 的哪两个轴做 2D 判定
2026
+ * - 'xz'(默认):俯视图,取 bbox 的 x/z 坐标
2027
+ * - 'xy':正视图,取 bbox 的 x/y 坐标
2028
+ * - 'yz':侧视图,取 bbox 的 y/z 坐标
2029
+ * @returns 范围内所有构件的 oid 数组
2030
+ */
2031
+ async selectByPolygon(polygon, axis = "xz") {
2032
+ await this._ensureStructureLoaded();
2033
+ const result = [];
2034
+ const polygon2D = polygon.map((p) => {
2035
+ switch (axis) {
2036
+ case "xy":
2037
+ return new Vector2(p.x, p.y);
2038
+ case "yz":
2039
+ return new Vector2(p.y, p.z);
2040
+ case "xz":
2041
+ default:
2042
+ return new Vector2(p.x, p.z);
2043
+ }
2044
+ });
2045
+ for (const [oid, node] of this._oidNodeMap) {
2046
+ if (!node.bbox || node.bbox.length < 6) continue;
2047
+ let minU, minV, maxU, maxV;
2048
+ switch (axis) {
2049
+ case "xy":
2050
+ minU = node.bbox[0];
2051
+ minV = node.bbox[1];
2052
+ maxU = node.bbox[3];
2053
+ maxV = node.bbox[4];
2054
+ break;
2055
+ case "xz":
2056
+ minU = node.bbox[0];
2057
+ minV = node.bbox[2];
2058
+ maxU = node.bbox[3];
2059
+ maxV = node.bbox[5];
2060
+ break;
2061
+ case "yz":
2062
+ minU = node.bbox[1];
2063
+ minV = node.bbox[2];
2064
+ maxU = node.bbox[4];
2065
+ maxV = node.bbox[5];
2066
+ break;
2067
+ }
2068
+ if (this._polygonIntersectsRect(polygon2D, minU, minV, maxU, maxV)) {
2069
+ result.push(oid);
2070
+ }
2071
+ }
2072
+ return result;
2073
+ }
2074
+ // =============================================
1935
2075
  // Model Info Methods
1936
2076
  // =============================================
1937
2077
  _getModelInfoUrl() {
@@ -1942,13 +2082,17 @@ class GLTFParserPlugin {
1942
2082
  async _fetchModelInfo() {
1943
2083
  const url = this._getModelInfoUrl();
1944
2084
  if (!url) {
1945
- console.warn("[GLTFParserPlugin] Cannot derive modelInfo.json URL: tiles not initialized");
2085
+ console.warn(
2086
+ "[GLTFParserPlugin] Cannot derive modelInfo.json URL: tiles not initialized"
2087
+ );
1946
2088
  return null;
1947
2089
  }
1948
2090
  try {
1949
2091
  const response = await fetch(url);
1950
2092
  if (!response.ok) {
1951
- console.warn(`[GLTFParserPlugin] Failed to fetch modelInfo.json: ${response.status}`);
2093
+ console.warn(
2094
+ `[GLTFParserPlugin] Failed to fetch modelInfo.json: ${response.status}`
2095
+ );
1952
2096
  return null;
1953
2097
  }
1954
2098
  const data = await response.json();
@@ -2129,7 +2273,8 @@ class GLTFParserPlugin {
2129
2273
  // =============================================
2130
2274
  _isOidBlocked(oid) {
2131
2275
  if (this._frozenOids.has(oid)) return true;
2132
- if (this._isolatedOids.size > 0 && !this._isolatedOids.has(oid)) return true;
2276
+ if (this._isolatedOids.size > 0 && !this._isolatedOids.has(oid))
2277
+ return true;
2133
2278
  return false;
2134
2279
  }
2135
2280
  _trackMesh(mesh, oid) {
@@ -2214,6 +2359,13 @@ class GLTFParserPlugin {
2214
2359
  }
2215
2360
  this._syncCollectorMeshes();
2216
2361
  }
2362
+ /**
2363
+ * 冻结单个构件
2364
+ */
2365
+ freezeByOid(oid) {
2366
+ this._frozenOids.add(oid);
2367
+ this._syncCollectorMeshes();
2368
+ }
2217
2369
  /**
2218
2370
  * 解冻指定构件
2219
2371
  */
@@ -2223,6 +2375,13 @@ class GLTFParserPlugin {
2223
2375
  }
2224
2376
  this._syncCollectorMeshes();
2225
2377
  }
2378
+ /**
2379
+ * 解冻单个构件
2380
+ */
2381
+ unfreezeByOid(oid) {
2382
+ this._frozenOids.delete(oid);
2383
+ this._syncCollectorMeshes();
2384
+ }
2226
2385
  /**
2227
2386
  * 解冻全部构件
2228
2387
  */
@@ -2245,6 +2404,13 @@ class GLTFParserPlugin {
2245
2404
  }
2246
2405
  this._syncCollectorMeshes();
2247
2406
  }
2407
+ /**
2408
+ * 往隔离集合中添加单个构件
2409
+ */
2410
+ isolateByOid(oid) {
2411
+ this._isolatedOids.add(oid);
2412
+ this._syncCollectorMeshes();
2413
+ }
2248
2414
  /**
2249
2415
  * 取消隔离指定构件
2250
2416
  */
@@ -2254,6 +2420,13 @@ class GLTFParserPlugin {
2254
2420
  }
2255
2421
  this._syncCollectorMeshes();
2256
2422
  }
2423
+ /**
2424
+ * 从隔离集合中移除单个构件
2425
+ */
2426
+ unisolateByOid(oid) {
2427
+ this._isolatedOids.delete(oid);
2428
+ this._syncCollectorMeshes();
2429
+ }
2257
2430
  /**
2258
2431
  * 取消全部隔离,恢复所有构件的交互能力
2259
2432
  */