s3m-three 0.4.26 → 0.4.28
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/dist/browser/assets/s3mWorker-B2u-xt54.js +1 -0
- package/dist/browser/s3m-three.iife.ext-three.js +52 -40
- package/dist/browser/s3m-three.iife.js +52 -40
- package/dist/core/BakeMercator.d.ts +54 -0
- package/dist/core/BakeMercator.d.ts.map +1 -0
- package/dist/core/BakeMercator.js +65 -0
- package/dist/core/BakeMercator.js.map +1 -0
- package/dist/core/S3M1Parser.d.ts +19 -0
- package/dist/core/S3M1Parser.d.ts.map +1 -1
- package/dist/core/S3M1Parser.js +179 -8
- package/dist/core/S3M1Parser.js.map +1 -1
- package/dist/core/TileGeometry.d.ts +7 -0
- package/dist/core/TileGeometry.d.ts.map +1 -1
- package/dist/core/TileGeometry.js +20 -0
- package/dist/core/TileGeometry.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/render/DatasetManager.d.ts +27 -0
- package/dist/render/DatasetManager.d.ts.map +1 -1
- package/dist/render/DatasetManager.js +18 -4
- package/dist/render/DatasetManager.js.map +1 -1
- package/dist/render/GeoAdapter.d.ts +49 -24
- package/dist/render/GeoAdapter.d.ts.map +1 -1
- package/dist/render/GeoAdapter.js +96 -8
- package/dist/render/GeoAdapter.js.map +1 -1
- package/dist/render/GeometryBuilder.d.ts +17 -0
- package/dist/render/GeometryBuilder.d.ts.map +1 -1
- package/dist/render/GeometryBuilder.js +31 -2
- package/dist/render/GeometryBuilder.js.map +1 -1
- package/dist/render/S3MViewer.d.ts +80 -2
- package/dist/render/S3MViewer.d.ts.map +1 -1
- package/dist/render/S3MViewer.js +299 -9
- package/dist/render/S3MViewer.js.map +1 -1
- package/dist/render/StyleMaterial.d.ts +5 -0
- package/dist/render/StyleMaterial.d.ts.map +1 -1
- package/dist/render/StyleMaterial.js +21 -0
- package/dist/render/StyleMaterial.js.map +1 -1
- package/dist/render/tilePlacement.d.ts +84 -0
- package/dist/render/tilePlacement.d.ts.map +1 -0
- package/dist/render/tilePlacement.js +71 -0
- package/dist/render/tilePlacement.js.map +1 -0
- package/dist/render/viewer/EdgeDecorator.d.ts +1 -0
- package/dist/render/viewer/EdgeDecorator.d.ts.map +1 -1
- package/dist/render/viewer/EdgeDecorator.js +3 -0
- package/dist/render/viewer/EdgeDecorator.js.map +1 -1
- package/dist/render/viewer/PickService.d.ts +13 -0
- package/dist/render/viewer/PickService.d.ts.map +1 -1
- package/dist/render/viewer/PickService.js +24 -15
- package/dist/render/viewer/PickService.js.map +1 -1
- package/dist/render/viewer/types.d.ts +53 -0
- package/dist/render/viewer/types.d.ts.map +1 -1
- package/dist/render/viewer/types.js.map +1 -1
- package/dist/tileset/S3MTileset.d.ts +43 -1
- package/dist/tileset/S3MTileset.d.ts.map +1 -1
- package/dist/tileset/S3MTileset.js +217 -2
- package/dist/tileset/S3MTileset.js.map +1 -1
- package/dist/worker/s3mWorker.js +691 -508
- package/dist/worker/s3mWorker.js.map +1 -1
- package/docs/API.md +18 -0
- package/package.json +1 -1
- package/src/core/BakeMercator.ts +96 -0
- package/src/core/S3M1Parser.ts +179 -9
- package/src/core/TileGeometry.ts +26 -0
- package/src/index.ts +11 -1
- package/src/render/DatasetManager.ts +43 -5
- package/src/render/GeoAdapter.ts +139 -11
- package/src/render/GeometryBuilder.ts +53 -2
- package/src/render/S3MViewer.ts +335 -13
- package/src/render/StyleMaterial.ts +26 -0
- package/src/render/tilePlacement.ts +121 -0
- package/src/render/viewer/EdgeDecorator.ts +3 -0
- package/src/render/viewer/PickService.ts +44 -16
- package/src/render/viewer/types.ts +51 -0
- package/src/tileset/S3MTileset.ts +240 -3
- package/dist/browser/assets/s3mWorker-DHOVIrAU.js +0 -1
|
@@ -32,6 +32,7 @@ import type {
|
|
|
32
32
|
} from '../core/S3MBlockParser.js';
|
|
33
33
|
import type { Anchor, ParsedTile, Stats, StyleUniforms } from '../core/types.js';
|
|
34
34
|
import type { TileGeometryData } from '../core/TileGeometry.js';
|
|
35
|
+
import { AUTO_BAKE_RADIUS_THRESHOLD } from '../core/BakeMercator.js';
|
|
35
36
|
import type { TextureCreateOptions } from '../render/TextureFactory.js';
|
|
36
37
|
import type { Group, Texture } from 'three';
|
|
37
38
|
|
|
@@ -304,10 +305,14 @@ export type BuildTileFn = (
|
|
|
304
305
|
colorPipeline?: 'linear' | 'direct';
|
|
305
306
|
/** 纹理创建参数(透传给 buildTileObjects → createTexture) */
|
|
306
307
|
textureOptions?: TextureCreateOptions;
|
|
308
|
+
bakeMercator?: boolean;
|
|
309
|
+
tileAnchor?: { lon: number; lat: number; height?: number };
|
|
310
|
+
tileCenter?: { x: number; y: number; z?: number };
|
|
307
311
|
}
|
|
308
312
|
) => Promise<{ group: Group; stats: Partial<Stats> }>;
|
|
309
313
|
|
|
310
314
|
export interface S3MTilesetOptions {
|
|
315
|
+
bakeMercator?: boolean;
|
|
311
316
|
configUrl: string;
|
|
312
317
|
maxTiles?: number;
|
|
313
318
|
maxConcurrent?: number;
|
|
@@ -388,6 +393,18 @@ export interface S3MTilesetOptions {
|
|
|
388
393
|
* 'silent' —— 只记录到 `stats.degradations`,由 UI 自己决定怎么提示。
|
|
389
394
|
*/
|
|
390
395
|
unsupported?: UnsupportedPolicy;
|
|
396
|
+
/**
|
|
397
|
+
* LOD 细化过渡策略:
|
|
398
|
+
* - 'binary'(默认):整节点二值切换。所有子瓦片全部就绪或失败后,父瓦片整块隐藏、子瓦片整块接替。
|
|
399
|
+
* - 'incremental':增量细化(primary / fallback 双列表 + LEQUAL 深度推移)。
|
|
400
|
+
* 子瓦片就绪一个显示一个,未就绪区域由父级(fallback)兜底填充,消除整块跳变与慢 child 阻塞。
|
|
401
|
+
*/
|
|
402
|
+
lodTransition?: 'binary' | 'incremental';
|
|
403
|
+
/**
|
|
404
|
+
* 增量细化模式下 fallback 兜底瓦片的材质深度偏移系数。
|
|
405
|
+
* 默认 { factor: 1, units: 2 },通过向远处推移深度配合 gl.LEQUAL 消除共面 z-fighting。
|
|
406
|
+
*/
|
|
407
|
+
fallbackOffset?: { factor?: number; units?: number };
|
|
391
408
|
}
|
|
392
409
|
|
|
393
410
|
/** 估算单个纹理占用的显存字节数 */
|
|
@@ -505,6 +522,10 @@ export class S3MTileset {
|
|
|
505
522
|
*/
|
|
506
523
|
maxMemory: number;
|
|
507
524
|
lodRangeScale: number;
|
|
525
|
+
lodTransition: 'binary' | 'incremental';
|
|
526
|
+
fallbackOffset: { factor: number; units: number };
|
|
527
|
+
readonly primaryNodes = new Set<string>();
|
|
528
|
+
readonly fallbackNodes = new Set<string>();
|
|
508
529
|
|
|
509
530
|
/** 数据集配置声明的高度范围(米),若配置未声明则返回 null */
|
|
510
531
|
get heightRange(): { min: number; max: number } | null {
|
|
@@ -535,8 +556,16 @@ export class S3MTileset {
|
|
|
535
556
|
/** 请求量的硬上限(软上限 maxTiles 的超额余量),见构造函数注释 */
|
|
536
557
|
hardCap = 96;
|
|
537
558
|
/** 本数据集是 S3M 1.x(SuperMapCache,.s3m):子瓦地址规则与 3.x 不同 */
|
|
538
|
-
|
|
559
|
+
isS3MV1 = false;
|
|
539
560
|
private _buildTile: BuildTileFn | null;
|
|
561
|
+
private _bakeMercator?: boolean;
|
|
562
|
+
rootRadius?: number;
|
|
563
|
+
|
|
564
|
+
shouldBakeMercator(radius?: number): boolean {
|
|
565
|
+
if (this._bakeMercator !== undefined) return this._bakeMercator;
|
|
566
|
+
const r = radius ?? this.rootRadius ?? 0;
|
|
567
|
+
return r > AUTO_BAKE_RADIUS_THRESHOLD;
|
|
568
|
+
}
|
|
540
569
|
private readonly _polygonOffset: { factor: number; units: number } | undefined;
|
|
541
570
|
private _materialQuality: 'pbr' | 'lambert' | undefined;
|
|
542
571
|
private _colorPipeline: 'linear' | 'direct' | undefined;
|
|
@@ -550,6 +579,11 @@ export class S3MTileset {
|
|
|
550
579
|
constructor(options: S3MTilesetOptions) {
|
|
551
580
|
this.configUrl = options.configUrl;
|
|
552
581
|
this.lodRangeScale = options.lodRangeScale ?? 3.0;
|
|
582
|
+
this.lodTransition = options.lodTransition ?? 'binary';
|
|
583
|
+
this.fallbackOffset = {
|
|
584
|
+
factor: options.fallbackOffset?.factor ?? 1,
|
|
585
|
+
units: options.fallbackOffset?.units ?? 2,
|
|
586
|
+
};
|
|
553
587
|
this._onTile = options.onTile ?? (() => {});
|
|
554
588
|
this._onTileRemoved = options.onTileRemoved ?? (() => {});
|
|
555
589
|
this._onError = options.onError ?? ((e) => console.warn(e));
|
|
@@ -560,6 +594,7 @@ export class S3MTileset {
|
|
|
560
594
|
|
|
561
595
|
// 渲染层可注入:Node 环境下不需要 three,也能跑 URL / 解析链路
|
|
562
596
|
this._buildTile = options.buildTile ?? null;
|
|
597
|
+
this._bakeMercator = options.bakeMercator;
|
|
563
598
|
this._polygonOffset = options.polygonOffset;
|
|
564
599
|
this._materialQuality = options.materialQuality;
|
|
565
600
|
this._colorPipeline = options.colorPipeline;
|
|
@@ -903,6 +938,9 @@ export class S3MTileset {
|
|
|
903
938
|
if (refined !== allowRefined) continue;
|
|
904
939
|
// 正在显示且没有可见子瓦接手 → 踢了就是洞
|
|
905
940
|
if (!allowUncovered && node.group.visible) {
|
|
941
|
+
if (this.lodTransition === 'incremental') {
|
|
942
|
+
continue;
|
|
943
|
+
}
|
|
906
944
|
const covered = childUrls.some((u) => {
|
|
907
945
|
const c = this.nodes.get(u);
|
|
908
946
|
return !!c && c.group.visible;
|
|
@@ -913,6 +951,15 @@ export class S3MTileset {
|
|
|
913
951
|
victim = node;
|
|
914
952
|
continue;
|
|
915
953
|
}
|
|
954
|
+
// 可见性优先于时间戳:没有包围球的瓦片算不出距离,`lastSeen` 天然比别的瓦片旧,
|
|
955
|
+
// 只看时间戳会把「正在显示」的那块先踢掉(开洞 → 回补 → 再踢 = 闪)。
|
|
956
|
+
// 只有不可见的候选分不出来时,才轮到 lastSeen / distance 决定。
|
|
957
|
+
const nodeVisible = node.group.visible ? 1 : 0;
|
|
958
|
+
const victimVisible = victim.group.visible ? 1 : 0;
|
|
959
|
+
if (nodeVisible !== victimVisible) {
|
|
960
|
+
if (nodeVisible < victimVisible) victim = node;
|
|
961
|
+
continue;
|
|
962
|
+
}
|
|
916
963
|
const a = node.lastSeen ?? -1;
|
|
917
964
|
const b = victim.lastSeen ?? -1;
|
|
918
965
|
if (a < b || (a === b && (node.distance ?? 0) > (victim.distance ?? 0))) victim = node;
|
|
@@ -1350,6 +1397,11 @@ export class S3MTileset {
|
|
|
1350
1397
|
// 解析成功但能力不完整的(目前只有 3DGS),在花力气建几何之前先决定处置
|
|
1351
1398
|
this._noteDegradations(tile);
|
|
1352
1399
|
|
|
1400
|
+
const lodForBake = this._pickLod(tile);
|
|
1401
|
+
if (this.rootRadius === undefined && lodForBake?.boundingSphere?.radius) {
|
|
1402
|
+
this.rootRadius = lodForBake.boundingSphere.radius;
|
|
1403
|
+
}
|
|
1404
|
+
const shouldBake = this.shouldBakeMercator(lodForBake?.boundingSphere?.radius);
|
|
1353
1405
|
const build = await this._builder();
|
|
1354
1406
|
const buildRes = await build(tile, {
|
|
1355
1407
|
textureCache: this.textureCache,
|
|
@@ -1359,6 +1411,9 @@ export class S3MTileset {
|
|
|
1359
1411
|
materialQuality: this._materialQuality,
|
|
1360
1412
|
colorPipeline: this._colorPipeline,
|
|
1361
1413
|
textureOptions: this._textureOptions,
|
|
1414
|
+
bakeMercator: shouldBake,
|
|
1415
|
+
tileAnchor: this.anchor,
|
|
1416
|
+
tileCenter: lodForBake?.boundingSphere?.center,
|
|
1362
1417
|
});
|
|
1363
1418
|
const { group, stats } = buildRes;
|
|
1364
1419
|
const texKeys = (buildRes as any).textureKeys ?? (group.userData?.textureKeys as string[] | undefined) ?? Object.keys(tile.textures ?? {});
|
|
@@ -1467,6 +1522,11 @@ export class S3MTileset {
|
|
|
1467
1522
|
|
|
1468
1523
|
for (const node of this.nodes.values()) {
|
|
1469
1524
|
if (!node.sphere) {
|
|
1525
|
+
// 没有包围球(S3M 1.x 叶子瓦片:XML 是 `<PageLods><Geode>`,没有 PagedLOD)时
|
|
1526
|
+
// 算不出距离,但**仍要记「最近用过」**:`lastSeen` 恒为 undefined 会让它在
|
|
1527
|
+
// `_pickVictim` 里永远排最前(`?? -1`),硬上限一触发 `allowUncovered`,
|
|
1528
|
+
// 第一块被踢掉的就是正在显示的那块 —— 画面立刻一个洞,下一帧又加载回来。
|
|
1529
|
+
node.lastSeen = this._frame;
|
|
1470
1530
|
node.needRefine = false;
|
|
1471
1531
|
continue;
|
|
1472
1532
|
}
|
|
@@ -1570,10 +1630,21 @@ export class S3MTileset {
|
|
|
1570
1630
|
if (!p || !this.nodes.has(p)) roots.add(url);
|
|
1571
1631
|
}
|
|
1572
1632
|
|
|
1573
|
-
|
|
1574
|
-
if (this.
|
|
1633
|
+
if (this.lodTransition === 'incremental') {
|
|
1634
|
+
if (this._updateVisibilityIncremental(roots, visited)) {
|
|
1575
1635
|
hasChanges = true;
|
|
1576
1636
|
}
|
|
1637
|
+
} else {
|
|
1638
|
+
for (const rootUrl of roots) {
|
|
1639
|
+
if (this._updateNodeVisibility(rootUrl, true, visited)) {
|
|
1640
|
+
hasChanges = true;
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
this.primaryNodes.clear();
|
|
1644
|
+
for (const [url, node] of this.nodes) {
|
|
1645
|
+
if (node.group.visible) this.primaryNodes.add(url);
|
|
1646
|
+
}
|
|
1647
|
+
this.fallbackNodes.clear();
|
|
1577
1648
|
}
|
|
1578
1649
|
|
|
1579
1650
|
// 防御:若有任何未被 root 树访问到的游离瓦片,全部隐藏
|
|
@@ -1583,6 +1654,9 @@ export class S3MTileset {
|
|
|
1583
1654
|
node.group.visible = false;
|
|
1584
1655
|
hasChanges = true;
|
|
1585
1656
|
}
|
|
1657
|
+
if (this.lodTransition === 'incremental') {
|
|
1658
|
+
this._restoreNodePolygonOffset(node);
|
|
1659
|
+
}
|
|
1586
1660
|
}
|
|
1587
1661
|
}
|
|
1588
1662
|
|
|
@@ -1674,6 +1748,169 @@ export class S3MTileset {
|
|
|
1674
1748
|
return changed;
|
|
1675
1749
|
}
|
|
1676
1750
|
|
|
1751
|
+
|
|
1752
|
+
getLodTransition(): 'binary' | 'incremental' {
|
|
1753
|
+
return this.lodTransition;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
setLodTransition(mode: 'binary' | 'incremental'): void {
|
|
1757
|
+
if (this.lodTransition === mode) return;
|
|
1758
|
+
this.lodTransition = mode;
|
|
1759
|
+
if (mode === 'binary') {
|
|
1760
|
+
for (const node of this.nodes.values()) {
|
|
1761
|
+
this._restoreNodePolygonOffset(node);
|
|
1762
|
+
}
|
|
1763
|
+
this.fallbackNodes.clear();
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
private _applyNodeFallbackPolygonOffset(node: TileNode, depth: number): boolean {
|
|
1768
|
+
const factor = this.fallbackOffset.factor;
|
|
1769
|
+
const units = Math.max(2, (10 - Math.min(depth, 8)) * this.fallbackOffset.units);
|
|
1770
|
+
let changed = false;
|
|
1771
|
+
|
|
1772
|
+
node.group.traverse((obj) => {
|
|
1773
|
+
const target = obj as { isMesh?: boolean; isPoints?: boolean; isLine?: boolean; material?: any };
|
|
1774
|
+
if ((target.isMesh || target.isPoints || target.isLine) && target.material) {
|
|
1775
|
+
const materials = Array.isArray(target.material) ? target.material : [target.material];
|
|
1776
|
+
for (const mat of materials) {
|
|
1777
|
+
if (!mat) continue;
|
|
1778
|
+
if (!mat.userData) mat.userData = {};
|
|
1779
|
+
if (!mat.userData._basePolygonOffset) {
|
|
1780
|
+
mat.userData._basePolygonOffset = {
|
|
1781
|
+
polygonOffset: mat.polygonOffset === true,
|
|
1782
|
+
factor: mat.polygonOffsetFactor ?? 0,
|
|
1783
|
+
units: mat.polygonOffsetUnits ?? 0,
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
const base = mat.userData._basePolygonOffset;
|
|
1787
|
+
const targetFactor = base.factor + factor;
|
|
1788
|
+
const targetUnits = base.units + units;
|
|
1789
|
+
if (
|
|
1790
|
+
mat.polygonOffset !== true ||
|
|
1791
|
+
mat.polygonOffsetFactor !== targetFactor ||
|
|
1792
|
+
mat.polygonOffsetUnits !== targetUnits
|
|
1793
|
+
) {
|
|
1794
|
+
mat.polygonOffset = true;
|
|
1795
|
+
mat.polygonOffsetFactor = targetFactor;
|
|
1796
|
+
mat.polygonOffsetUnits = targetUnits;
|
|
1797
|
+
changed = true;
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
});
|
|
1802
|
+
return changed;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
private _restoreNodePolygonOffset(node: TileNode): boolean {
|
|
1806
|
+
let changed = false;
|
|
1807
|
+
node.group.traverse((obj) => {
|
|
1808
|
+
const target = obj as { isMesh?: boolean; isPoints?: boolean; isLine?: boolean; material?: any };
|
|
1809
|
+
if ((target.isMesh || target.isPoints || target.isLine) && target.material) {
|
|
1810
|
+
const materials = Array.isArray(target.material) ? target.material : [target.material];
|
|
1811
|
+
for (const mat of materials) {
|
|
1812
|
+
if (mat?.userData?._basePolygonOffset) {
|
|
1813
|
+
const base = mat.userData._basePolygonOffset;
|
|
1814
|
+
if (
|
|
1815
|
+
mat.polygonOffset !== base.polygonOffset ||
|
|
1816
|
+
mat.polygonOffsetFactor !== base.factor ||
|
|
1817
|
+
mat.polygonOffsetUnits !== base.units
|
|
1818
|
+
) {
|
|
1819
|
+
mat.polygonOffset = base.polygonOffset;
|
|
1820
|
+
mat.polygonOffsetFactor = base.factor;
|
|
1821
|
+
mat.polygonOffsetUnits = base.units;
|
|
1822
|
+
changed = true;
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
});
|
|
1828
|
+
return changed;
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
private _updateVisibilityIncremental(roots: Iterable<string>, visited: Set<string>): boolean {
|
|
1832
|
+
const nextPrimary = new Set<string>();
|
|
1833
|
+
const nextFallback = new Set<string>();
|
|
1834
|
+
const nodeDepths = new Map<string, number>();
|
|
1835
|
+
|
|
1836
|
+
const traverse = (url: string, depth: number) => {
|
|
1837
|
+
if (visited.has(url)) return;
|
|
1838
|
+
visited.add(url);
|
|
1839
|
+
nodeDepths.set(url, depth);
|
|
1840
|
+
|
|
1841
|
+
const node = this.nodes.get(url);
|
|
1842
|
+
if (!node) return;
|
|
1843
|
+
|
|
1844
|
+
const childUrls = node.childUrls ?? (node.childUrl ? [node.childUrl] : []);
|
|
1845
|
+
const hasChildren = childUrls.length > 0;
|
|
1846
|
+
const readyChildren = childUrls.filter((cUrl) => this.nodes.has(cUrl));
|
|
1847
|
+
const missingChildren = childUrls.filter(
|
|
1848
|
+
(cUrl) => !this.nodes.has(cUrl) && !this.failed.has(cUrl)
|
|
1849
|
+
);
|
|
1850
|
+
|
|
1851
|
+
const canRefine = !!node.needRefine && hasChildren && readyChildren.length > 0;
|
|
1852
|
+
|
|
1853
|
+
if (canRefine) {
|
|
1854
|
+
if (missingChildren.length > 0) {
|
|
1855
|
+
nextFallback.add(url);
|
|
1856
|
+
}
|
|
1857
|
+
for (const cUrl of readyChildren) {
|
|
1858
|
+
traverse(cUrl, depth + 1);
|
|
1859
|
+
}
|
|
1860
|
+
} else {
|
|
1861
|
+
nextPrimary.add(url);
|
|
1862
|
+
}
|
|
1863
|
+
};
|
|
1864
|
+
|
|
1865
|
+
for (const rootUrl of roots) {
|
|
1866
|
+
traverse(rootUrl, 0);
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
let changed = false;
|
|
1870
|
+
|
|
1871
|
+
for (const [url, node] of this.nodes) {
|
|
1872
|
+
if (!visited.has(url)) continue;
|
|
1873
|
+
|
|
1874
|
+
if (nextPrimary.has(url)) {
|
|
1875
|
+
if (!node.group.visible) {
|
|
1876
|
+
node.group.visible = true;
|
|
1877
|
+
changed = true;
|
|
1878
|
+
}
|
|
1879
|
+
const depth = nodeDepths.get(url) ?? 0;
|
|
1880
|
+
const targetOrder = 100 + depth;
|
|
1881
|
+
if (node.group.renderOrder !== targetOrder) {
|
|
1882
|
+
node.group.renderOrder = targetOrder;
|
|
1883
|
+
changed = true;
|
|
1884
|
+
}
|
|
1885
|
+
if (this._restoreNodePolygonOffset(node)) changed = true;
|
|
1886
|
+
} else if (nextFallback.has(url)) {
|
|
1887
|
+
if (!node.group.visible) {
|
|
1888
|
+
node.group.visible = true;
|
|
1889
|
+
changed = true;
|
|
1890
|
+
}
|
|
1891
|
+
const depth = nodeDepths.get(url) ?? 0;
|
|
1892
|
+
const targetOrder = depth;
|
|
1893
|
+
if (node.group.renderOrder !== targetOrder) {
|
|
1894
|
+
node.group.renderOrder = targetOrder;
|
|
1895
|
+
changed = true;
|
|
1896
|
+
}
|
|
1897
|
+
if (this._applyNodeFallbackPolygonOffset(node, depth)) changed = true;
|
|
1898
|
+
} else {
|
|
1899
|
+
if (node.group.visible) {
|
|
1900
|
+
node.group.visible = false;
|
|
1901
|
+
changed = true;
|
|
1902
|
+
}
|
|
1903
|
+
if (this._restoreNodePolygonOffset(node)) changed = true;
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
this.primaryNodes.clear();
|
|
1908
|
+
for (const u of nextPrimary) this.primaryNodes.add(u);
|
|
1909
|
+
this.fallbackNodes.clear();
|
|
1910
|
+
for (const u of nextFallback) this.fallbackNodes.add(u);
|
|
1911
|
+
|
|
1912
|
+
return changed;
|
|
1913
|
+
}
|
|
1677
1914
|
dispose(): void {
|
|
1678
1915
|
this._workerClient?.dispose();
|
|
1679
1916
|
for (const node of this.nodes.values()) {
|