gltf-parser-plugin 1.1.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/gltf-parser-plugin.module.js +540 -292
- package/build/gltf-parser-plugin.module.js.map +1 -1
- package/build/index.d.ts +29 -49
- package/package.json +47 -47
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Mesh, Vector3, Triangle, BufferGeometry, EventDispatcher, DataTexture, RGBAFormat, UnsignedByteType, SRGBColorSpace, Texture, MeshStandardMaterial, DoubleSide, FrontSide, BufferAttribute, OrthographicCamera, Float32BufferAttribute,
|
|
1
|
+
import { Mesh, Vector3, Triangle, BufferGeometry, EventDispatcher, DataTexture, RGBAFormat, UnsignedByteType, SRGBColorSpace, Texture, MeshStandardMaterial, DoubleSide, FrontSide, BufferAttribute, Box3, Vector2, OrthographicCamera, Float32BufferAttribute, WebGLRenderer, WebGLRenderTarget, ShaderMaterial, OneFactor, ZeroFactor, CustomBlending, Box2, Matrix4, Matrix3, Matrix2, Vector4, MeshBasicMaterial, Loader, Scene, Group, InstancedMesh, Quaternion, Color } from "three";
|
|
2
2
|
class FeatureIdUniforms {
|
|
3
3
|
mesh;
|
|
4
4
|
plugin;
|
|
@@ -554,6 +554,114 @@ function acquireWorker() {
|
|
|
554
554
|
currentWorkerIndex = (currentWorkerIndex + 1) % workerPool.length;
|
|
555
555
|
return worker;
|
|
556
556
|
}
|
|
557
|
+
function pointInPolygon(px, py, polygon) {
|
|
558
|
+
let inside = false;
|
|
559
|
+
const n = polygon.length;
|
|
560
|
+
for (let i = 0, j = n - 1; i < n; j = i++) {
|
|
561
|
+
const xi = polygon[i].x, yi = polygon[i].y;
|
|
562
|
+
const xj = polygon[j].x, yj = polygon[j].y;
|
|
563
|
+
if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi) {
|
|
564
|
+
inside = !inside;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return inside;
|
|
568
|
+
}
|
|
569
|
+
function segmentsIntersect(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2) {
|
|
570
|
+
const cross = (ox, oy, ax, ay, bx, by) => (ax - ox) * (by - oy) - (ay - oy) * (bx - ox);
|
|
571
|
+
const d1 = cross(bx1, by1, bx2, by2, ax1, ay1);
|
|
572
|
+
const d2 = cross(bx1, by1, bx2, by2, ax2, ay2);
|
|
573
|
+
const d3 = cross(ax1, ay1, ax2, ay2, bx1, by1);
|
|
574
|
+
const d4 = cross(ax1, ay1, ax2, ay2, bx2, by2);
|
|
575
|
+
if ((d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d3 > 0 && d4 < 0 || d3 < 0 && d4 > 0)) {
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
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);
|
|
579
|
+
if (d1 === 0 && onSeg(bx1, by1, bx2, by2, ax1, ay1)) return true;
|
|
580
|
+
if (d2 === 0 && onSeg(bx1, by1, bx2, by2, ax2, ay2)) return true;
|
|
581
|
+
if (d3 === 0 && onSeg(ax1, ay1, ax2, ay2, bx1, by1)) return true;
|
|
582
|
+
if (d4 === 0 && onSeg(ax1, ay1, ax2, ay2, bx2, by2)) return true;
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
function polygonIntersectsRect(polygon, minX, minY, maxX, maxY) {
|
|
586
|
+
const n = polygon.length;
|
|
587
|
+
for (let i = 0; i < n; i++) {
|
|
588
|
+
const p = polygon[i];
|
|
589
|
+
if (p.x >= minX && p.x <= maxX && p.y >= minY && p.y <= maxY) {
|
|
590
|
+
return true;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
if (pointInPolygon(minX, minY, polygon) || pointInPolygon(maxX, minY, polygon) || pointInPolygon(maxX, maxY, polygon) || pointInPolygon(minX, maxY, polygon)) {
|
|
594
|
+
return true;
|
|
595
|
+
}
|
|
596
|
+
const rx = [minX, maxX, maxX, minX];
|
|
597
|
+
const ry = [minY, minY, maxY, maxY];
|
|
598
|
+
for (let i = 0; i < n; i++) {
|
|
599
|
+
const a = polygon[i];
|
|
600
|
+
const b = polygon[(i + 1) % n];
|
|
601
|
+
for (let j = 0; j < 4; j++) {
|
|
602
|
+
const k = (j + 1) % 4;
|
|
603
|
+
if (segmentsIntersect(a.x, a.y, b.x, b.y, rx[j], ry[j], rx[k], ry[k])) {
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
function selectByBoxFromOidMap(oidNodeMap, box) {
|
|
611
|
+
const result = [];
|
|
612
|
+
const nodeBox = new Box3();
|
|
613
|
+
for (const [oid, node] of oidNodeMap) {
|
|
614
|
+
if (!node.bbox || node.bbox.length < 6) continue;
|
|
615
|
+
nodeBox.min.set(node.bbox[0], node.bbox[1], node.bbox[2]);
|
|
616
|
+
nodeBox.max.set(node.bbox[3], node.bbox[4], node.bbox[5]);
|
|
617
|
+
if (box.intersectsBox(nodeBox)) {
|
|
618
|
+
result.push(oid);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return result;
|
|
622
|
+
}
|
|
623
|
+
function selectByPolygonFromOidMap(oidNodeMap, polygon, axis = "xz") {
|
|
624
|
+
const result = [];
|
|
625
|
+
const polygon2D = polygon.map((p) => {
|
|
626
|
+
switch (axis) {
|
|
627
|
+
case "xy":
|
|
628
|
+
return new Vector2(p.x, p.y);
|
|
629
|
+
case "yz":
|
|
630
|
+
return new Vector2(p.y, p.z);
|
|
631
|
+
case "xz":
|
|
632
|
+
default:
|
|
633
|
+
return new Vector2(p.x, p.z);
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
for (const [oid, node] of oidNodeMap) {
|
|
637
|
+
if (!node.bbox || node.bbox.length < 6) continue;
|
|
638
|
+
let minU, minV, maxU, maxV;
|
|
639
|
+
switch (axis) {
|
|
640
|
+
case "xy":
|
|
641
|
+
minU = node.bbox[0];
|
|
642
|
+
minV = node.bbox[1];
|
|
643
|
+
maxU = node.bbox[3];
|
|
644
|
+
maxV = node.bbox[4];
|
|
645
|
+
break;
|
|
646
|
+
case "xz":
|
|
647
|
+
minU = node.bbox[0];
|
|
648
|
+
minV = node.bbox[2];
|
|
649
|
+
maxU = node.bbox[3];
|
|
650
|
+
maxV = node.bbox[5];
|
|
651
|
+
break;
|
|
652
|
+
case "yz":
|
|
653
|
+
minU = node.bbox[1];
|
|
654
|
+
minV = node.bbox[2];
|
|
655
|
+
maxU = node.bbox[4];
|
|
656
|
+
maxV = node.bbox[5];
|
|
657
|
+
break;
|
|
658
|
+
}
|
|
659
|
+
if (polygonIntersectsRect(polygon2D, minU, minV, maxU, maxV)) {
|
|
660
|
+
result.push(oid);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return result;
|
|
664
|
+
}
|
|
557
665
|
const _camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
|
558
666
|
class FullscreenTriangleGeometry extends BufferGeometry {
|
|
559
667
|
constructor() {
|
|
@@ -1646,6 +1754,369 @@ class GLTFWorkerLoader extends Loader {
|
|
|
1646
1754
|
});
|
|
1647
1755
|
}
|
|
1648
1756
|
}
|
|
1757
|
+
function ensureColor(color) {
|
|
1758
|
+
if (color instanceof Color) return color;
|
|
1759
|
+
return new Color(color);
|
|
1760
|
+
}
|
|
1761
|
+
function getMaterials(mesh) {
|
|
1762
|
+
const mat = mesh.material;
|
|
1763
|
+
if (!mat) return [];
|
|
1764
|
+
return Array.isArray(mat) ? mat : [mat];
|
|
1765
|
+
}
|
|
1766
|
+
function getMaterialForColor(color) {
|
|
1767
|
+
const key = color.getHex();
|
|
1768
|
+
if (!materialCache.has(key)) {
|
|
1769
|
+
materialCache.set(key, new MeshStandardMaterial({
|
|
1770
|
+
color: color.clone(),
|
|
1771
|
+
roughness: 0.5,
|
|
1772
|
+
metalness: 0.1
|
|
1773
|
+
}));
|
|
1774
|
+
}
|
|
1775
|
+
return materialCache.get(key);
|
|
1776
|
+
}
|
|
1777
|
+
const materialCache = /* @__PURE__ */ new Map();
|
|
1778
|
+
class ComponentColorHelper {
|
|
1779
|
+
constructor(context) {
|
|
1780
|
+
this.context = context;
|
|
1781
|
+
}
|
|
1782
|
+
coloredOids = /* @__PURE__ */ new Set();
|
|
1783
|
+
materialByOid = /* @__PURE__ */ new Map();
|
|
1784
|
+
originalMaterialByMesh = /* @__PURE__ */ new Map();
|
|
1785
|
+
opacityModifiedOids = /* @__PURE__ */ new Set();
|
|
1786
|
+
opacityByOid = /* @__PURE__ */ new Map();
|
|
1787
|
+
originalOpacityByMaterial = /* @__PURE__ */ new Map();
|
|
1788
|
+
meshChangeHandlers = /* @__PURE__ */ new Map();
|
|
1789
|
+
getAllModifiedOids() {
|
|
1790
|
+
return Array.from(/* @__PURE__ */ new Set([...this.coloredOids, ...this.opacityModifiedOids]));
|
|
1791
|
+
}
|
|
1792
|
+
applyToMeshes(oid) {
|
|
1793
|
+
const scene = this.context.getScene();
|
|
1794
|
+
if (!scene) return;
|
|
1795
|
+
const collector = this.context.getMeshCollectorByOid(oid);
|
|
1796
|
+
const colorMaterial = this.materialByOid.get(oid);
|
|
1797
|
+
const opacity = this.opacityByOid.get(oid);
|
|
1798
|
+
collector.meshes.forEach((mesh) => {
|
|
1799
|
+
if (!mesh.parent) scene.add(mesh);
|
|
1800
|
+
if (colorMaterial) {
|
|
1801
|
+
mesh.material = colorMaterial;
|
|
1802
|
+
}
|
|
1803
|
+
if (opacity !== void 0) {
|
|
1804
|
+
for (const mat of getMaterials(mesh)) {
|
|
1805
|
+
if (!this.originalOpacityByMaterial.has(mat)) {
|
|
1806
|
+
this.originalOpacityByMaterial.set(mat, mat.opacity);
|
|
1807
|
+
}
|
|
1808
|
+
mat.opacity = opacity;
|
|
1809
|
+
mat.transparent = opacity < 1;
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
/**
|
|
1815
|
+
* 根据 oid 数组设置构件颜色
|
|
1816
|
+
* 隐藏原 mesh,将 split mesh 替换材质后加入场景
|
|
1817
|
+
*/
|
|
1818
|
+
setComponentColorByOids(oids, color) {
|
|
1819
|
+
const scene = this.context.getScene();
|
|
1820
|
+
if (!scene) return;
|
|
1821
|
+
const threeColor = ensureColor(color);
|
|
1822
|
+
const material = getMaterialForColor(threeColor);
|
|
1823
|
+
for (const oid of oids) {
|
|
1824
|
+
this.coloredOids.add(oid);
|
|
1825
|
+
this.materialByOid.set(oid, material);
|
|
1826
|
+
const collector = this.context.getMeshCollectorByOid(oid);
|
|
1827
|
+
collector.meshes.forEach((mesh) => {
|
|
1828
|
+
if (!this.originalMaterialByMesh.has(mesh.uuid)) {
|
|
1829
|
+
this.originalMaterialByMesh.set(mesh.uuid, mesh.material);
|
|
1830
|
+
}
|
|
1831
|
+
mesh.material = material;
|
|
1832
|
+
scene.add(mesh);
|
|
1833
|
+
});
|
|
1834
|
+
if (!this.meshChangeHandlers.has(oid)) {
|
|
1835
|
+
const handler = () => this.applyToMeshes(oid);
|
|
1836
|
+
this.meshChangeHandlers.set(oid, handler);
|
|
1837
|
+
collector.addEventListener("mesh-change", handler);
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
this.context.hideByOids(this.getAllModifiedOids());
|
|
1841
|
+
}
|
|
1842
|
+
/**
|
|
1843
|
+
* 恢复指定构件的颜色
|
|
1844
|
+
* 若该 oid 已无颜色且无透明度修改,则从场景移除 split mesh 并 unhide 原 mesh
|
|
1845
|
+
*/
|
|
1846
|
+
restoreComponentColorByOids(oids) {
|
|
1847
|
+
const scene = this.context.getScene();
|
|
1848
|
+
if (!scene) return;
|
|
1849
|
+
for (const oid of oids) {
|
|
1850
|
+
this.coloredOids.delete(oid);
|
|
1851
|
+
this.materialByOid.delete(oid);
|
|
1852
|
+
const collector = this.context.getMeshCollectorByOid(oid);
|
|
1853
|
+
const opacity = this.opacityByOid.get(oid);
|
|
1854
|
+
collector.meshes.forEach((mesh) => {
|
|
1855
|
+
const originalMat = this.originalMaterialByMesh.get(mesh.uuid);
|
|
1856
|
+
if (originalMat) {
|
|
1857
|
+
mesh.material = originalMat;
|
|
1858
|
+
this.originalMaterialByMesh.delete(mesh.uuid);
|
|
1859
|
+
if (opacity !== void 0) {
|
|
1860
|
+
for (const mat of getMaterials(mesh)) {
|
|
1861
|
+
if (!this.originalOpacityByMaterial.has(mat)) {
|
|
1862
|
+
this.originalOpacityByMaterial.set(mat, mat.opacity);
|
|
1863
|
+
}
|
|
1864
|
+
mat.opacity = opacity;
|
|
1865
|
+
mat.transparent = opacity < 1;
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
if (!this.coloredOids.has(oid) && !this.opacityModifiedOids.has(oid) && mesh.parent === scene) {
|
|
1870
|
+
scene.remove(mesh);
|
|
1871
|
+
}
|
|
1872
|
+
});
|
|
1873
|
+
if (!this.coloredOids.has(oid) && !this.opacityModifiedOids.has(oid)) {
|
|
1874
|
+
const handler = this.meshChangeHandlers.get(oid);
|
|
1875
|
+
if (handler) {
|
|
1876
|
+
this.meshChangeHandlers.delete(oid);
|
|
1877
|
+
collector.removeEventListener("mesh-change", handler);
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
this.context.unhideByOids(oids);
|
|
1882
|
+
}
|
|
1883
|
+
/**
|
|
1884
|
+
* 根据 oid 数组设置构件透明度
|
|
1885
|
+
* 隐藏原 mesh,将 split mesh 修改材质透明度后加入场景
|
|
1886
|
+
* @param oids 构件 OID 数组
|
|
1887
|
+
* @param opacity 透明度,0-1,0 完全透明,1 完全不透明
|
|
1888
|
+
*/
|
|
1889
|
+
setComponentOpacityByOids(oids, opacity) {
|
|
1890
|
+
const scene = this.context.getScene();
|
|
1891
|
+
if (!scene) return;
|
|
1892
|
+
const clampedOpacity = Math.max(0, Math.min(1, opacity));
|
|
1893
|
+
for (const oid of oids) {
|
|
1894
|
+
this.opacityModifiedOids.add(oid);
|
|
1895
|
+
this.opacityByOid.set(oid, clampedOpacity);
|
|
1896
|
+
const colorMat = this.materialByOid.get(oid);
|
|
1897
|
+
if (colorMat && colorMat.opacity !== clampedOpacity) {
|
|
1898
|
+
const clone = colorMat.clone();
|
|
1899
|
+
clone.opacity = clampedOpacity;
|
|
1900
|
+
clone.transparent = clampedOpacity < 1;
|
|
1901
|
+
this.materialByOid.set(oid, clone);
|
|
1902
|
+
this.originalOpacityByMaterial.set(clone, 1);
|
|
1903
|
+
}
|
|
1904
|
+
const collector = this.context.getMeshCollectorByOid(oid);
|
|
1905
|
+
collector.meshes.forEach((mesh) => {
|
|
1906
|
+
scene.add(mesh);
|
|
1907
|
+
const mat = colorMat ? this.materialByOid.get(oid) : mesh.material;
|
|
1908
|
+
if (!this.originalOpacityByMaterial.has(mat)) {
|
|
1909
|
+
this.originalOpacityByMaterial.set(mat, mat.opacity);
|
|
1910
|
+
}
|
|
1911
|
+
mat.opacity = clampedOpacity;
|
|
1912
|
+
mat.transparent = clampedOpacity < 1;
|
|
1913
|
+
if (colorMat) mesh.material = mat;
|
|
1914
|
+
});
|
|
1915
|
+
if (!this.meshChangeHandlers.has(oid)) {
|
|
1916
|
+
const handler = () => this.applyToMeshes(oid);
|
|
1917
|
+
this.meshChangeHandlers.set(oid, handler);
|
|
1918
|
+
collector.addEventListener("mesh-change", handler);
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
this.context.hideByOids(this.getAllModifiedOids());
|
|
1922
|
+
}
|
|
1923
|
+
/**
|
|
1924
|
+
* 恢复指定构件的透明度
|
|
1925
|
+
* 若该 oid 已无颜色且无透明度修改,则从场景移除 split mesh 并 unhide 原 mesh
|
|
1926
|
+
*/
|
|
1927
|
+
restoreComponentOpacityByOids(oids) {
|
|
1928
|
+
const scene = this.context.getScene();
|
|
1929
|
+
if (!scene) return;
|
|
1930
|
+
for (const oid of oids) {
|
|
1931
|
+
this.opacityModifiedOids.delete(oid);
|
|
1932
|
+
this.opacityByOid.delete(oid);
|
|
1933
|
+
const collector = this.context.getMeshCollectorByOid(oid);
|
|
1934
|
+
collector.meshes.forEach((mesh) => {
|
|
1935
|
+
for (const mat of getMaterials(mesh)) {
|
|
1936
|
+
const original = this.originalOpacityByMaterial.get(mat);
|
|
1937
|
+
if (original !== void 0) {
|
|
1938
|
+
mat.opacity = original;
|
|
1939
|
+
mat.transparent = original < 1;
|
|
1940
|
+
this.originalOpacityByMaterial.delete(mat);
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
if (!this.coloredOids.has(oid) && !this.opacityModifiedOids.has(oid) && mesh.parent === scene) {
|
|
1944
|
+
scene.remove(mesh);
|
|
1945
|
+
}
|
|
1946
|
+
});
|
|
1947
|
+
if (!this.coloredOids.has(oid) && !this.opacityModifiedOids.has(oid)) {
|
|
1948
|
+
const handler = this.meshChangeHandlers.get(oid);
|
|
1949
|
+
if (handler) {
|
|
1950
|
+
this.meshChangeHandlers.delete(oid);
|
|
1951
|
+
collector.removeEventListener("mesh-change", handler);
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
this.context.unhideByOids(oids);
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
class InteractionFilter {
|
|
1959
|
+
constructor(context) {
|
|
1960
|
+
this.context = context;
|
|
1961
|
+
}
|
|
1962
|
+
frozenOids = /* @__PURE__ */ new Set();
|
|
1963
|
+
isolatedOids = /* @__PURE__ */ new Set();
|
|
1964
|
+
trackedMeshes = /* @__PURE__ */ new Map();
|
|
1965
|
+
meshListeners = /* @__PURE__ */ new Map();
|
|
1966
|
+
isPluginRemoving = false;
|
|
1967
|
+
isOidBlocked(oid) {
|
|
1968
|
+
if (this.frozenOids.has(oid)) return true;
|
|
1969
|
+
if (this.isolatedOids.size > 0 && !this.isolatedOids.has(oid)) return true;
|
|
1970
|
+
return false;
|
|
1971
|
+
}
|
|
1972
|
+
trackMesh(mesh, oid) {
|
|
1973
|
+
if (this.meshListeners.has(mesh)) return;
|
|
1974
|
+
const onAdded = () => {
|
|
1975
|
+
if (this.isPluginRemoving) return;
|
|
1976
|
+
mesh.userData._detachedParent = null;
|
|
1977
|
+
if (this.isOidBlocked(oid) && mesh.parent) {
|
|
1978
|
+
const parent = mesh.parent;
|
|
1979
|
+
this.isPluginRemoving = true;
|
|
1980
|
+
mesh.userData._detachedParent = parent;
|
|
1981
|
+
parent.remove(mesh);
|
|
1982
|
+
this.isPluginRemoving = false;
|
|
1983
|
+
}
|
|
1984
|
+
};
|
|
1985
|
+
const onRemoved = () => {
|
|
1986
|
+
if (this.isPluginRemoving) return;
|
|
1987
|
+
mesh.userData._detachedParent = null;
|
|
1988
|
+
};
|
|
1989
|
+
mesh.addEventListener("added", onAdded);
|
|
1990
|
+
mesh.addEventListener("removed", onRemoved);
|
|
1991
|
+
this.meshListeners.set(mesh, { onAdded, onRemoved });
|
|
1992
|
+
}
|
|
1993
|
+
untrackMesh(mesh) {
|
|
1994
|
+
const listeners = this.meshListeners.get(mesh);
|
|
1995
|
+
if (listeners) {
|
|
1996
|
+
mesh.removeEventListener("added", listeners.onAdded);
|
|
1997
|
+
mesh.removeEventListener("removed", listeners.onRemoved);
|
|
1998
|
+
this.meshListeners.delete(mesh);
|
|
1999
|
+
}
|
|
2000
|
+
mesh.userData._detachedParent = null;
|
|
2001
|
+
}
|
|
2002
|
+
onCollectorMeshChange(oid, newMeshes) {
|
|
2003
|
+
const tracked = this.trackedMeshes.get(oid);
|
|
2004
|
+
const newSet = new Set(newMeshes);
|
|
2005
|
+
if (tracked) {
|
|
2006
|
+
for (const mesh of tracked) {
|
|
2007
|
+
if (!newSet.has(mesh)) {
|
|
2008
|
+
this.untrackMesh(mesh);
|
|
2009
|
+
tracked.delete(mesh);
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
const trackSet = tracked || /* @__PURE__ */ new Set();
|
|
2014
|
+
for (const mesh of newMeshes) {
|
|
2015
|
+
if (!trackSet.has(mesh)) {
|
|
2016
|
+
this.trackMesh(mesh, oid);
|
|
2017
|
+
trackSet.add(mesh);
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
this.trackedMeshes.set(oid, trackSet);
|
|
2021
|
+
}
|
|
2022
|
+
syncCollectorMeshes() {
|
|
2023
|
+
this.isPluginRemoving = true;
|
|
2024
|
+
for (const [oid, collector] of this.context.getCollectorCache()) {
|
|
2025
|
+
const blocked = this.isOidBlocked(oid);
|
|
2026
|
+
for (const mesh of collector.meshes) {
|
|
2027
|
+
if (!this.meshListeners.has(mesh)) continue;
|
|
2028
|
+
if (blocked) {
|
|
2029
|
+
if (mesh.parent && !mesh.userData._detachedParent) {
|
|
2030
|
+
const parent = mesh.parent;
|
|
2031
|
+
mesh.userData._detachedParent = parent;
|
|
2032
|
+
parent.remove(mesh);
|
|
2033
|
+
}
|
|
2034
|
+
} else {
|
|
2035
|
+
const storedParent = mesh.userData._detachedParent;
|
|
2036
|
+
if (storedParent && !mesh.parent) {
|
|
2037
|
+
storedParent.add(mesh);
|
|
2038
|
+
mesh.userData._detachedParent = null;
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
this.isPluginRemoving = false;
|
|
2044
|
+
}
|
|
2045
|
+
onUnregisterCollector(oid) {
|
|
2046
|
+
const tracked = this.trackedMeshes.get(oid);
|
|
2047
|
+
if (tracked) {
|
|
2048
|
+
for (const mesh of tracked) {
|
|
2049
|
+
this.untrackMesh(mesh);
|
|
2050
|
+
}
|
|
2051
|
+
this.trackedMeshes.delete(oid);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
freezeByOids(oids) {
|
|
2055
|
+
for (const oid of oids) {
|
|
2056
|
+
this.frozenOids.add(oid);
|
|
2057
|
+
}
|
|
2058
|
+
this.syncCollectorMeshes();
|
|
2059
|
+
}
|
|
2060
|
+
freezeByOid(oid) {
|
|
2061
|
+
this.frozenOids.add(oid);
|
|
2062
|
+
this.syncCollectorMeshes();
|
|
2063
|
+
}
|
|
2064
|
+
unfreezeByOids(oids) {
|
|
2065
|
+
for (const oid of oids) {
|
|
2066
|
+
this.frozenOids.delete(oid);
|
|
2067
|
+
}
|
|
2068
|
+
this.syncCollectorMeshes();
|
|
2069
|
+
}
|
|
2070
|
+
unfreezeByOid(oid) {
|
|
2071
|
+
this.frozenOids.delete(oid);
|
|
2072
|
+
this.syncCollectorMeshes();
|
|
2073
|
+
}
|
|
2074
|
+
unfreeze() {
|
|
2075
|
+
this.frozenOids.clear();
|
|
2076
|
+
this.syncCollectorMeshes();
|
|
2077
|
+
}
|
|
2078
|
+
getFrozenOids() {
|
|
2079
|
+
return Array.from(this.frozenOids);
|
|
2080
|
+
}
|
|
2081
|
+
isolateByOids(oids) {
|
|
2082
|
+
for (const oid of oids) {
|
|
2083
|
+
this.isolatedOids.add(oid);
|
|
2084
|
+
}
|
|
2085
|
+
this.syncCollectorMeshes();
|
|
2086
|
+
}
|
|
2087
|
+
isolateByOid(oid) {
|
|
2088
|
+
this.isolatedOids.add(oid);
|
|
2089
|
+
this.syncCollectorMeshes();
|
|
2090
|
+
}
|
|
2091
|
+
unisolateByOids(oids) {
|
|
2092
|
+
for (const oid of oids) {
|
|
2093
|
+
this.isolatedOids.delete(oid);
|
|
2094
|
+
}
|
|
2095
|
+
this.syncCollectorMeshes();
|
|
2096
|
+
}
|
|
2097
|
+
unisolateByOid(oid) {
|
|
2098
|
+
this.isolatedOids.delete(oid);
|
|
2099
|
+
this.syncCollectorMeshes();
|
|
2100
|
+
}
|
|
2101
|
+
unisolate() {
|
|
2102
|
+
this.isolatedOids.clear();
|
|
2103
|
+
this.syncCollectorMeshes();
|
|
2104
|
+
}
|
|
2105
|
+
getIsolatedOids() {
|
|
2106
|
+
return Array.from(this.isolatedOids);
|
|
2107
|
+
}
|
|
2108
|
+
dispose() {
|
|
2109
|
+
for (const [, meshSet] of this.trackedMeshes) {
|
|
2110
|
+
for (const mesh of meshSet) {
|
|
2111
|
+
this.untrackMesh(mesh);
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
this.trackedMeshes.clear();
|
|
2115
|
+
this.meshListeners.clear();
|
|
2116
|
+
this.frozenOids.clear();
|
|
2117
|
+
this.isolatedOids.clear();
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
1649
2120
|
const DB_NAME = "GLTFParserPluginTilesCache";
|
|
1650
2121
|
const DB_VERSION = 1;
|
|
1651
2122
|
const STORE_NAME = "tiles";
|
|
@@ -1749,12 +2220,8 @@ class GLTFParserPlugin {
|
|
|
1749
2220
|
// --- Model info properties ---
|
|
1750
2221
|
_modelInfo = null;
|
|
1751
2222
|
_modelInfoPromise = null;
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
_isolatedOids = /* @__PURE__ */ new Set();
|
|
1755
|
-
_trackedMeshes = /* @__PURE__ */ new Map();
|
|
1756
|
-
_meshListeners = /* @__PURE__ */ new Map();
|
|
1757
|
-
_isPluginRemoving = false;
|
|
2223
|
+
_interactionFilter;
|
|
2224
|
+
_componentColorHelper = null;
|
|
1758
2225
|
// --- Mesh helper properties ---
|
|
1759
2226
|
oids = [];
|
|
1760
2227
|
renderer = null;
|
|
@@ -1777,6 +2244,9 @@ class GLTFParserPlugin {
|
|
|
1777
2244
|
if (options?.renderer) {
|
|
1778
2245
|
this.renderer = options.renderer;
|
|
1779
2246
|
}
|
|
2247
|
+
this._interactionFilter = new InteractionFilter({
|
|
2248
|
+
getCollectorCache: () => this.collectorCache
|
|
2249
|
+
});
|
|
1780
2250
|
setMaxWorkers(this._options.maxWorkers);
|
|
1781
2251
|
}
|
|
1782
2252
|
/**
|
|
@@ -1784,6 +2254,12 @@ class GLTFParserPlugin {
|
|
|
1784
2254
|
*/
|
|
1785
2255
|
init(tiles) {
|
|
1786
2256
|
this.tiles = tiles;
|
|
2257
|
+
this._componentColorHelper = new ComponentColorHelper({
|
|
2258
|
+
hideByOids: (oids) => this.hideByOids(oids),
|
|
2259
|
+
unhideByOids: (oids) => this.unhideByOids(oids),
|
|
2260
|
+
getMeshCollectorByOid: (oid) => this.getMeshCollectorByOid(oid),
|
|
2261
|
+
getScene: () => this.tiles?.group ?? null
|
|
2262
|
+
});
|
|
1787
2263
|
this._loader = new GLTFWorkerLoader(tiles.manager, {
|
|
1788
2264
|
metadata: this._options.metadata,
|
|
1789
2265
|
materialBuilder: this._options.materialBuilder
|
|
@@ -1935,71 +2411,6 @@ class GLTFParserPlugin {
|
|
|
1935
2411
|
async getStructureData() {
|
|
1936
2412
|
return this._ensureStructureLoaded();
|
|
1937
2413
|
}
|
|
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
2414
|
/**
|
|
2004
2415
|
* 选择包围盒范围内的构件(包含相交和包含两种情况)
|
|
2005
2416
|
* @param box 查询用的 Box3 范围,坐标系与 structure.json 中 bbox 一致
|
|
@@ -2007,17 +2418,7 @@ class GLTFParserPlugin {
|
|
|
2007
2418
|
*/
|
|
2008
2419
|
async selectByBox(box) {
|
|
2009
2420
|
await this._ensureStructureLoaded();
|
|
2010
|
-
|
|
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;
|
|
2421
|
+
return selectByBoxFromOidMap(this._oidNodeMap, box);
|
|
2021
2422
|
}
|
|
2022
2423
|
/**
|
|
2023
2424
|
* 选择多边形(平面投影)范围内的构件(包含相交和包含两种情况)
|
|
@@ -2030,46 +2431,7 @@ class GLTFParserPlugin {
|
|
|
2030
2431
|
*/
|
|
2031
2432
|
async selectByPolygon(polygon, axis = "xz") {
|
|
2032
2433
|
await this._ensureStructureLoaded();
|
|
2033
|
-
|
|
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;
|
|
2434
|
+
return selectByPolygonFromOidMap(this._oidNodeMap, polygon, axis);
|
|
2073
2435
|
}
|
|
2074
2436
|
// =============================================
|
|
2075
2437
|
// Model Info Methods
|
|
@@ -2154,13 +2516,7 @@ class GLTFParserPlugin {
|
|
|
2154
2516
|
const oid = collector.getOid();
|
|
2155
2517
|
this.collectors.delete(collector);
|
|
2156
2518
|
this.collectorCache.delete(oid);
|
|
2157
|
-
|
|
2158
|
-
if (tracked) {
|
|
2159
|
-
for (const mesh of tracked) {
|
|
2160
|
-
this._untrackMesh(mesh);
|
|
2161
|
-
}
|
|
2162
|
-
this._trackedMeshes.delete(oid);
|
|
2163
|
-
}
|
|
2519
|
+
this._interactionFilter.onUnregisterCollector(oid);
|
|
2164
2520
|
}
|
|
2165
2521
|
_updateWebGLLimits() {
|
|
2166
2522
|
const gl = this.renderer.getContext();
|
|
@@ -2259,186 +2615,53 @@ class GLTFParserPlugin {
|
|
|
2259
2615
|
queryFeatureFromIntersection(hit) {
|
|
2260
2616
|
const result = queryFeatureFromIntersection(hit);
|
|
2261
2617
|
if (result.isValid && result.oid !== void 0) {
|
|
2262
|
-
if (this.
|
|
2263
|
-
return {
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2618
|
+
if (this._interactionFilter.isOidBlocked(result.oid)) {
|
|
2619
|
+
return {
|
|
2620
|
+
isValid: false,
|
|
2621
|
+
error: this._interactionFilter.getFrozenOids().includes(result.oid) ? "Component is frozen" : "Component is not in isolated set"
|
|
2622
|
+
};
|
|
2267
2623
|
}
|
|
2268
2624
|
}
|
|
2269
2625
|
return result;
|
|
2270
2626
|
}
|
|
2271
2627
|
// =============================================
|
|
2272
|
-
// Interaction Filter Methods
|
|
2628
|
+
// Interaction Filter Methods (delegated)
|
|
2273
2629
|
// =============================================
|
|
2274
|
-
_isOidBlocked(oid) {
|
|
2275
|
-
if (this._frozenOids.has(oid)) return true;
|
|
2276
|
-
if (this._isolatedOids.size > 0 && !this._isolatedOids.has(oid))
|
|
2277
|
-
return true;
|
|
2278
|
-
return false;
|
|
2279
|
-
}
|
|
2280
|
-
_trackMesh(mesh, oid) {
|
|
2281
|
-
if (this._meshListeners.has(mesh)) return;
|
|
2282
|
-
const onAdded = () => {
|
|
2283
|
-
if (this._isPluginRemoving) return;
|
|
2284
|
-
mesh.userData._detachedParent = null;
|
|
2285
|
-
if (this._isOidBlocked(oid) && mesh.parent) {
|
|
2286
|
-
const parent = mesh.parent;
|
|
2287
|
-
this._isPluginRemoving = true;
|
|
2288
|
-
mesh.userData._detachedParent = parent;
|
|
2289
|
-
parent.remove(mesh);
|
|
2290
|
-
this._isPluginRemoving = false;
|
|
2291
|
-
}
|
|
2292
|
-
};
|
|
2293
|
-
const onRemoved = () => {
|
|
2294
|
-
if (this._isPluginRemoving) return;
|
|
2295
|
-
mesh.userData._detachedParent = null;
|
|
2296
|
-
};
|
|
2297
|
-
mesh.addEventListener("added", onAdded);
|
|
2298
|
-
mesh.addEventListener("removed", onRemoved);
|
|
2299
|
-
this._meshListeners.set(mesh, { onAdded, onRemoved });
|
|
2300
|
-
}
|
|
2301
|
-
_untrackMesh(mesh) {
|
|
2302
|
-
const listeners = this._meshListeners.get(mesh);
|
|
2303
|
-
if (listeners) {
|
|
2304
|
-
mesh.removeEventListener("added", listeners.onAdded);
|
|
2305
|
-
mesh.removeEventListener("removed", listeners.onRemoved);
|
|
2306
|
-
this._meshListeners.delete(mesh);
|
|
2307
|
-
}
|
|
2308
|
-
mesh.userData._detachedParent = null;
|
|
2309
|
-
}
|
|
2310
|
-
_onCollectorMeshChange(oid, newMeshes) {
|
|
2311
|
-
const tracked = this._trackedMeshes.get(oid);
|
|
2312
|
-
const newSet = new Set(newMeshes);
|
|
2313
|
-
if (tracked) {
|
|
2314
|
-
for (const mesh of tracked) {
|
|
2315
|
-
if (!newSet.has(mesh)) {
|
|
2316
|
-
this._untrackMesh(mesh);
|
|
2317
|
-
tracked.delete(mesh);
|
|
2318
|
-
}
|
|
2319
|
-
}
|
|
2320
|
-
}
|
|
2321
|
-
const trackSet = tracked || /* @__PURE__ */ new Set();
|
|
2322
|
-
for (const mesh of newMeshes) {
|
|
2323
|
-
if (!trackSet.has(mesh)) {
|
|
2324
|
-
this._trackMesh(mesh, oid);
|
|
2325
|
-
trackSet.add(mesh);
|
|
2326
|
-
}
|
|
2327
|
-
}
|
|
2328
|
-
this._trackedMeshes.set(oid, trackSet);
|
|
2329
|
-
}
|
|
2330
|
-
_syncCollectorMeshes() {
|
|
2331
|
-
this._isPluginRemoving = true;
|
|
2332
|
-
for (const [oid, collector] of this.collectorCache) {
|
|
2333
|
-
const blocked = this._isOidBlocked(oid);
|
|
2334
|
-
for (const mesh of collector.meshes) {
|
|
2335
|
-
if (!this._meshListeners.has(mesh)) continue;
|
|
2336
|
-
if (blocked) {
|
|
2337
|
-
if (mesh.parent && !mesh.userData._detachedParent) {
|
|
2338
|
-
const parent = mesh.parent;
|
|
2339
|
-
mesh.userData._detachedParent = parent;
|
|
2340
|
-
this.unhideByOids([oid]);
|
|
2341
|
-
}
|
|
2342
|
-
} else {
|
|
2343
|
-
const storedParent = mesh.userData._detachedParent;
|
|
2344
|
-
if (storedParent && !mesh.parent) {
|
|
2345
|
-
storedParent.add(mesh);
|
|
2346
|
-
mesh.userData._detachedParent = null;
|
|
2347
|
-
}
|
|
2348
|
-
}
|
|
2349
|
-
}
|
|
2350
|
-
}
|
|
2351
|
-
this._isPluginRemoving = false;
|
|
2352
|
-
}
|
|
2353
|
-
/**
|
|
2354
|
-
* 冻结指定构件,被冻结的构件不再响应任何交互和事件
|
|
2355
|
-
*/
|
|
2356
2630
|
freezeByOids(oids) {
|
|
2357
|
-
|
|
2358
|
-
this._frozenOids.add(oid);
|
|
2359
|
-
}
|
|
2360
|
-
this._syncCollectorMeshes();
|
|
2631
|
+
this._interactionFilter.freezeByOids(oids);
|
|
2361
2632
|
}
|
|
2362
|
-
/**
|
|
2363
|
-
* 冻结单个构件
|
|
2364
|
-
*/
|
|
2365
2633
|
freezeByOid(oid) {
|
|
2366
|
-
this.
|
|
2367
|
-
this._syncCollectorMeshes();
|
|
2634
|
+
this._interactionFilter.freezeByOid(oid);
|
|
2368
2635
|
}
|
|
2369
|
-
/**
|
|
2370
|
-
* 解冻指定构件
|
|
2371
|
-
*/
|
|
2372
2636
|
unfreezeByOids(oids) {
|
|
2373
|
-
|
|
2374
|
-
this._frozenOids.delete(oid);
|
|
2375
|
-
}
|
|
2376
|
-
this._syncCollectorMeshes();
|
|
2637
|
+
this._interactionFilter.unfreezeByOids(oids);
|
|
2377
2638
|
}
|
|
2378
|
-
/**
|
|
2379
|
-
* 解冻单个构件
|
|
2380
|
-
*/
|
|
2381
2639
|
unfreezeByOid(oid) {
|
|
2382
|
-
this.
|
|
2383
|
-
this._syncCollectorMeshes();
|
|
2640
|
+
this._interactionFilter.unfreezeByOid(oid);
|
|
2384
2641
|
}
|
|
2385
|
-
/**
|
|
2386
|
-
* 解冻全部构件
|
|
2387
|
-
*/
|
|
2388
2642
|
unfreeze() {
|
|
2389
|
-
this.
|
|
2390
|
-
this._syncCollectorMeshes();
|
|
2643
|
+
this._interactionFilter.unfreeze();
|
|
2391
2644
|
}
|
|
2392
|
-
/**
|
|
2393
|
-
* 获取当前被冻结的 OID 数组
|
|
2394
|
-
*/
|
|
2395
2645
|
getFrozenOids() {
|
|
2396
|
-
return
|
|
2646
|
+
return this._interactionFilter.getFrozenOids();
|
|
2397
2647
|
}
|
|
2398
|
-
/**
|
|
2399
|
-
* 隔离指定构件,隔离模式下只有被隔离的构件才能响应交互和事件
|
|
2400
|
-
*/
|
|
2401
2648
|
isolateByOids(oids) {
|
|
2402
|
-
|
|
2403
|
-
this._isolatedOids.add(oid);
|
|
2404
|
-
}
|
|
2405
|
-
this._syncCollectorMeshes();
|
|
2649
|
+
this._interactionFilter.isolateByOids(oids);
|
|
2406
2650
|
}
|
|
2407
|
-
/**
|
|
2408
|
-
* 往隔离集合中添加单个构件
|
|
2409
|
-
*/
|
|
2410
2651
|
isolateByOid(oid) {
|
|
2411
|
-
this.
|
|
2412
|
-
this._syncCollectorMeshes();
|
|
2652
|
+
this._interactionFilter.isolateByOid(oid);
|
|
2413
2653
|
}
|
|
2414
|
-
/**
|
|
2415
|
-
* 取消隔离指定构件
|
|
2416
|
-
*/
|
|
2417
2654
|
unisolateByOids(oids) {
|
|
2418
|
-
|
|
2419
|
-
this._isolatedOids.delete(oid);
|
|
2420
|
-
}
|
|
2421
|
-
this._syncCollectorMeshes();
|
|
2655
|
+
this._interactionFilter.unisolateByOids(oids);
|
|
2422
2656
|
}
|
|
2423
|
-
/**
|
|
2424
|
-
* 从隔离集合中移除单个构件
|
|
2425
|
-
*/
|
|
2426
2657
|
unisolateByOid(oid) {
|
|
2427
|
-
this.
|
|
2428
|
-
this._syncCollectorMeshes();
|
|
2658
|
+
this._interactionFilter.unisolateByOid(oid);
|
|
2429
2659
|
}
|
|
2430
|
-
/**
|
|
2431
|
-
* 取消全部隔离,恢复所有构件的交互能力
|
|
2432
|
-
*/
|
|
2433
2660
|
unisolate() {
|
|
2434
|
-
this.
|
|
2435
|
-
this._syncCollectorMeshes();
|
|
2661
|
+
this._interactionFilter.unisolate();
|
|
2436
2662
|
}
|
|
2437
|
-
/**
|
|
2438
|
-
* 获取当前被隔离的 OID 数组
|
|
2439
|
-
*/
|
|
2440
2663
|
getIsolatedOids() {
|
|
2441
|
-
return
|
|
2664
|
+
return this._interactionFilter.getIsolatedOids();
|
|
2442
2665
|
}
|
|
2443
2666
|
/**
|
|
2444
2667
|
* 内部方法:根据 oid 获取 mesh 数组
|
|
@@ -2469,9 +2692,9 @@ class GLTFParserPlugin {
|
|
|
2469
2692
|
}
|
|
2470
2693
|
const collector = new MeshCollector(oid, this);
|
|
2471
2694
|
this.collectorCache.set(oid, collector);
|
|
2472
|
-
this.
|
|
2695
|
+
this._interactionFilter.onCollectorMeshChange(oid, collector.meshes);
|
|
2473
2696
|
collector.addEventListener("mesh-change", (event) => {
|
|
2474
|
-
this.
|
|
2697
|
+
this._interactionFilter.onCollectorMeshChange(oid, event.meshes);
|
|
2475
2698
|
});
|
|
2476
2699
|
return collector;
|
|
2477
2700
|
}
|
|
@@ -2491,6 +2714,38 @@ class GLTFParserPlugin {
|
|
|
2491
2714
|
this.oids = newOids;
|
|
2492
2715
|
this.featureIdCount = this._calculateFeatureIdCount();
|
|
2493
2716
|
}
|
|
2717
|
+
/**
|
|
2718
|
+
* 根据 oid 数组设置构件颜色
|
|
2719
|
+
* 隐藏原 mesh,将 split mesh 替换材质后加入场景(使用 tiles.group)
|
|
2720
|
+
* @param oids 构件 OID 数组
|
|
2721
|
+
* @param color 颜色值,支持 hex 数字、颜色字符串(如 "#ff0000")、THREE.Color 对象
|
|
2722
|
+
*/
|
|
2723
|
+
setComponentColorByOids(oids, color) {
|
|
2724
|
+
this._componentColorHelper?.setComponentColorByOids(oids, color);
|
|
2725
|
+
}
|
|
2726
|
+
/**
|
|
2727
|
+
* 恢复指定构件的颜色
|
|
2728
|
+
* 从场景移除 split mesh,unhide 原 mesh
|
|
2729
|
+
* @param oids 构件 OID 数组
|
|
2730
|
+
*/
|
|
2731
|
+
restoreComponentColorByOids(oids) {
|
|
2732
|
+
this._componentColorHelper?.restoreComponentColorByOids(oids);
|
|
2733
|
+
}
|
|
2734
|
+
/**
|
|
2735
|
+
* 根据 oid 数组设置构件透明度
|
|
2736
|
+
* @param oids 构件 OID 数组
|
|
2737
|
+
* @param opacity 透明度,0-1,0 完全透明,1 完全不透明
|
|
2738
|
+
*/
|
|
2739
|
+
setComponentOpacityByOids(oids, opacity) {
|
|
2740
|
+
this._componentColorHelper?.setComponentOpacityByOids(oids, opacity);
|
|
2741
|
+
}
|
|
2742
|
+
/**
|
|
2743
|
+
* 恢复指定构件的透明度
|
|
2744
|
+
* @param oids 构件 OID 数组
|
|
2745
|
+
*/
|
|
2746
|
+
restoreComponentOpacityByOids(oids) {
|
|
2747
|
+
this._componentColorHelper?.restoreComponentOpacityByOids(oids);
|
|
2748
|
+
}
|
|
2494
2749
|
/**
|
|
2495
2750
|
* Restore the original materials of the mesh
|
|
2496
2751
|
*/
|
|
@@ -2527,15 +2782,8 @@ class GLTFParserPlugin {
|
|
|
2527
2782
|
this._structurePromise = null;
|
|
2528
2783
|
this._modelInfo = null;
|
|
2529
2784
|
this._modelInfoPromise = null;
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
this._untrackMesh(mesh);
|
|
2533
|
-
}
|
|
2534
|
-
}
|
|
2535
|
-
this._trackedMeshes.clear();
|
|
2536
|
-
this._meshListeners.clear();
|
|
2537
|
-
this._frozenOids.clear();
|
|
2538
|
-
this._isolatedOids.clear();
|
|
2785
|
+
this._interactionFilter.dispose();
|
|
2786
|
+
this._componentColorHelper = null;
|
|
2539
2787
|
this._loader = null;
|
|
2540
2788
|
this.tiles = null;
|
|
2541
2789
|
}
|