gltf-parser-plugin 1.1.1 → 1.1.2

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,131 @@ 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 多边形顶点数组(Vector2),按顺序连接构成闭合多边形
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
+ for (const [oid, node] of this._oidNodeMap) {
2035
+ if (!node.bbox || node.bbox.length < 6) continue;
2036
+ let minU, minV, maxU, maxV;
2037
+ switch (axis) {
2038
+ case "xy":
2039
+ minU = node.bbox[0];
2040
+ minV = node.bbox[1];
2041
+ maxU = node.bbox[3];
2042
+ maxV = node.bbox[4];
2043
+ break;
2044
+ case "xz":
2045
+ minU = node.bbox[0];
2046
+ minV = node.bbox[2];
2047
+ maxU = node.bbox[3];
2048
+ maxV = node.bbox[5];
2049
+ break;
2050
+ case "yz":
2051
+ minU = node.bbox[1];
2052
+ minV = node.bbox[2];
2053
+ maxU = node.bbox[4];
2054
+ maxV = node.bbox[5];
2055
+ break;
2056
+ }
2057
+ if (this._polygonIntersectsRect(polygon, minU, minV, maxU, maxV)) {
2058
+ result.push(oid);
2059
+ }
2060
+ }
2061
+ return result;
2062
+ }
2063
+ // =============================================
1935
2064
  // Model Info Methods
1936
2065
  // =============================================
1937
2066
  _getModelInfoUrl() {
@@ -1942,13 +2071,17 @@ class GLTFParserPlugin {
1942
2071
  async _fetchModelInfo() {
1943
2072
  const url = this._getModelInfoUrl();
1944
2073
  if (!url) {
1945
- console.warn("[GLTFParserPlugin] Cannot derive modelInfo.json URL: tiles not initialized");
2074
+ console.warn(
2075
+ "[GLTFParserPlugin] Cannot derive modelInfo.json URL: tiles not initialized"
2076
+ );
1946
2077
  return null;
1947
2078
  }
1948
2079
  try {
1949
2080
  const response = await fetch(url);
1950
2081
  if (!response.ok) {
1951
- console.warn(`[GLTFParserPlugin] Failed to fetch modelInfo.json: ${response.status}`);
2082
+ console.warn(
2083
+ `[GLTFParserPlugin] Failed to fetch modelInfo.json: ${response.status}`
2084
+ );
1952
2085
  return null;
1953
2086
  }
1954
2087
  const data = await response.json();
@@ -2129,7 +2262,8 @@ class GLTFParserPlugin {
2129
2262
  // =============================================
2130
2263
  _isOidBlocked(oid) {
2131
2264
  if (this._frozenOids.has(oid)) return true;
2132
- if (this._isolatedOids.size > 0 && !this._isolatedOids.has(oid)) return true;
2265
+ if (this._isolatedOids.size > 0 && !this._isolatedOids.has(oid))
2266
+ return true;
2133
2267
  return false;
2134
2268
  }
2135
2269
  _trackMesh(mesh, oid) {
@@ -2214,6 +2348,13 @@ class GLTFParserPlugin {
2214
2348
  }
2215
2349
  this._syncCollectorMeshes();
2216
2350
  }
2351
+ /**
2352
+ * 冻结单个构件
2353
+ */
2354
+ freezeByOid(oid) {
2355
+ this._frozenOids.add(oid);
2356
+ this._syncCollectorMeshes();
2357
+ }
2217
2358
  /**
2218
2359
  * 解冻指定构件
2219
2360
  */
@@ -2223,6 +2364,13 @@ class GLTFParserPlugin {
2223
2364
  }
2224
2365
  this._syncCollectorMeshes();
2225
2366
  }
2367
+ /**
2368
+ * 解冻单个构件
2369
+ */
2370
+ unfreezeByOid(oid) {
2371
+ this._frozenOids.delete(oid);
2372
+ this._syncCollectorMeshes();
2373
+ }
2226
2374
  /**
2227
2375
  * 解冻全部构件
2228
2376
  */
@@ -2245,6 +2393,13 @@ class GLTFParserPlugin {
2245
2393
  }
2246
2394
  this._syncCollectorMeshes();
2247
2395
  }
2396
+ /**
2397
+ * 往隔离集合中添加单个构件
2398
+ */
2399
+ isolateByOid(oid) {
2400
+ this._isolatedOids.add(oid);
2401
+ this._syncCollectorMeshes();
2402
+ }
2248
2403
  /**
2249
2404
  * 取消隔离指定构件
2250
2405
  */
@@ -2254,6 +2409,13 @@ class GLTFParserPlugin {
2254
2409
  }
2255
2410
  this._syncCollectorMeshes();
2256
2411
  }
2412
+ /**
2413
+ * 从隔离集合中移除单个构件
2414
+ */
2415
+ unisolateByOid(oid) {
2416
+ this._isolatedOids.delete(oid);
2417
+ this._syncCollectorMeshes();
2418
+ }
2257
2419
  /**
2258
2420
  * 取消全部隔离,恢复所有构件的交互能力
2259
2421
  */