s3m-three 0.4.17 → 0.4.18
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/s3m-three.iife.ext-three.js +24 -24
- package/dist/browser/s3m-three.iife.js +24 -24
- package/dist/core/AttributeQuery.d.ts +13 -0
- package/dist/core/AttributeQuery.d.ts.map +1 -1
- package/dist/core/AttributeQuery.js +20 -3
- package/dist/core/AttributeQuery.js.map +1 -1
- package/dist/core/AuthFetch.d.ts +52 -0
- package/dist/core/AuthFetch.d.ts.map +1 -0
- package/dist/core/AuthFetch.js +44 -0
- package/dist/core/AuthFetch.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/render/DatasetManager.d.ts +7 -1
- package/dist/render/DatasetManager.d.ts.map +1 -1
- package/dist/render/DatasetManager.js +2 -1
- package/dist/render/DatasetManager.js.map +1 -1
- package/dist/render/HostRenderer.d.ts +105 -0
- package/dist/render/HostRenderer.d.ts.map +1 -0
- package/dist/render/HostRenderer.js +170 -0
- package/dist/render/HostRenderer.js.map +1 -0
- package/dist/render/S3MViewer.d.ts +10 -0
- package/dist/render/S3MViewer.d.ts.map +1 -1
- package/dist/render/S3MViewer.js +13 -4
- package/dist/render/S3MViewer.js.map +1 -1
- package/dist/tileset/S3MTileset.d.ts +8 -0
- package/dist/tileset/S3MTileset.d.ts.map +1 -1
- package/dist/tileset/S3MTileset.js +8 -4
- package/dist/tileset/S3MTileset.js.map +1 -1
- package/package.json +1 -1
- package/src/core/AttributeQuery.ts +26 -3
- package/src/core/AuthFetch.ts +82 -0
- package/src/index.ts +4 -0
- package/src/render/DatasetManager.ts +9 -1
- package/src/render/HostRenderer.ts +222 -0
- package/src/render/S3MViewer.ts +22 -4
- package/src/tileset/S3MTileset.ts +13 -4
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 宿主无关渲染底座(HostRenderer)
|
|
3
|
+
*
|
|
4
|
+
* 把「宿主协议 ↔ s3m-three 渲染内核」的**宿主无关**部分抽出来,作为所有地图适配层
|
|
5
|
+
* (MapLibre / Mapbox / 未来的 ArcGIS / Cesium)的共同基类。它只做三件事:
|
|
6
|
+
*
|
|
7
|
+
* 1. 持有并构造 `S3MViewer`(渲染内核,宿主无关);
|
|
8
|
+
* 2. 提供每帧驱动(把宿主给的 world→clip 矩阵喂给内核,并按需请求下一帧)、
|
|
9
|
+
* 生命周期(mount / restore / unmount)、投影模式状态与近平面缩放状态;
|
|
10
|
+
* 3. 把「宿主能力」做成两个抽象钩子 `requestRepaint()` / `getBearing()`,
|
|
11
|
+
* 由具体适配器实现(maplibre → `triggerRepaint()`,arcgis → `requestRender()`)。
|
|
12
|
+
*
|
|
13
|
+
* 凡是依赖具体地图 API 的东西(CustomLayerInterface 形态、从宿主 render 参数里抽矩阵、
|
|
14
|
+
* 事件绑定、上下文恢复重加图层、经纬度→墨卡托的 WorldCoordinateHelper 提取)都**不在这里**——
|
|
15
|
+
* 那是各适配层自己的事。这样「绕开墨卡托」也成为可能:非墨卡托宿主(ECEF / 局部米制)只要
|
|
16
|
+
* 实现 `requestRepaint` 并提供返回自己坐标系的 GeoAdapter,内核就完全不碰墨卡托。
|
|
17
|
+
*
|
|
18
|
+
* 设计约束(对应 AGENTS.md 不变式①):本类不引入任何默认行为变更;maplibre 适配器继承它后,
|
|
19
|
+
* 默认路径与改动前逐字一致。
|
|
20
|
+
*/
|
|
21
|
+
import { S3MViewer } from './S3MViewer.js';
|
|
22
|
+
import type { S3MViewerOptions, PickResult } from './S3MViewer.js';
|
|
23
|
+
import type { ProjectionMode } from './OrthoProjection.js';
|
|
24
|
+
import type { TransitionOptions } from '../anim/Animator.js';
|
|
25
|
+
import type { Stats } from '../core/types.js';
|
|
26
|
+
import type { S3MDatasetEntry } from './DatasetManager.js';
|
|
27
|
+
|
|
28
|
+
/** HostRenderer 构造选项:渲染内核选项 + 三个适配器层专属开关 */
|
|
29
|
+
export interface HostRendererOptions extends S3MViewerOptions {
|
|
30
|
+
/** 图层 / 适配器 id,默认 's3m' */
|
|
31
|
+
id?: string;
|
|
32
|
+
/** 投影模式,默认 'perspective'(跟随宿主) */
|
|
33
|
+
projection?: ProjectionMode;
|
|
34
|
+
/** 近裁剪面缩放系数(0 < scale < 1,默认 1 = 不改) */
|
|
35
|
+
nearPlaneScale?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** 每帧喂给内核的矩阵输入(宿主无关;适配器负责从宿主 render 参数里抽出来) */
|
|
39
|
+
export interface HostFrame {
|
|
40
|
+
/** world→clip 矩阵(宿主坐标系下) */
|
|
41
|
+
mvp: ArrayLike<number>;
|
|
42
|
+
/** 相机在场景 ENU 中的位置(米,相对场景锚点) */
|
|
43
|
+
cameraEnu: [number, number, number];
|
|
44
|
+
/** 垂直视场角(弧度),用于 LOD 屏幕误差 */
|
|
45
|
+
fovRad: number;
|
|
46
|
+
/** 绘图缓冲高度(像素),LOD 判定用 */
|
|
47
|
+
canvasHeight: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 宿主无关渲染底座。具体地图适配器(如 S3MLayer)继承它,只补宿主专属胶水。
|
|
52
|
+
*/
|
|
53
|
+
export abstract class HostRenderer {
|
|
54
|
+
readonly id: string;
|
|
55
|
+
readonly options: HostRendererOptions;
|
|
56
|
+
readonly pickable: boolean;
|
|
57
|
+
|
|
58
|
+
/** 公开回调,可被使用方运行时重新赋值 */
|
|
59
|
+
onStats: (stats: Stats) => void;
|
|
60
|
+
onReady: (entry: S3MDatasetEntry) => void;
|
|
61
|
+
onPick: (result: PickResult | null) => void;
|
|
62
|
+
onError: (error: unknown) => void;
|
|
63
|
+
|
|
64
|
+
/** 渲染内核(宿主无关) */
|
|
65
|
+
readonly viewer: S3MViewer;
|
|
66
|
+
|
|
67
|
+
/** 当前投影模式 */
|
|
68
|
+
protected _projection: ProjectionMode = 'perspective';
|
|
69
|
+
/** 正交插值比例(0 = 纯透视,1 = 纯正交);过渡期间由 animator 平滑推进 */
|
|
70
|
+
protected _projectionT = 0;
|
|
71
|
+
/** 正交不可用只告警一次 */
|
|
72
|
+
protected _orthoWarned = false;
|
|
73
|
+
/** 近裁剪面缩放系数,1 = 不改(默认) */
|
|
74
|
+
protected _nearPlaneScale = 1;
|
|
75
|
+
|
|
76
|
+
constructor(options: HostRendererOptions = {}) {
|
|
77
|
+
this.id = options.id ?? 's3m';
|
|
78
|
+
this.options = options;
|
|
79
|
+
this.pickable = options.pickable !== false;
|
|
80
|
+
this._projection = options.projection === 'orthographic' ? 'orthographic' : 'perspective';
|
|
81
|
+
this._nearPlaneScale = HostRenderer.normalizeNearPlaneScale(options.nearPlaneScale);
|
|
82
|
+
this._projectionT = this._projection === 'orthographic' ? 1 : 0;
|
|
83
|
+
|
|
84
|
+
this.onStats = options.onStats ?? (() => {});
|
|
85
|
+
this.onReady = options.onReady ?? (() => {});
|
|
86
|
+
this.onPick = options.onPick ?? (() => {});
|
|
87
|
+
this.onError = options.onError ?? ((e) => console.warn('[s3m]', e));
|
|
88
|
+
|
|
89
|
+
// 把宿主能力做成钩子,内核不碰任何地图 API
|
|
90
|
+
const { id: _id, projection: _projection, nearPlaneScale: _nearPlaneScale, ...viewerOptions } = options;
|
|
91
|
+
this.viewer = new S3MViewer({
|
|
92
|
+
...viewerOptions,
|
|
93
|
+
onRequestRepaint: () => this.requestRepaint(),
|
|
94
|
+
getBearing: () => this.getBearing(),
|
|
95
|
+
onStats: (s) => this.onStats(s),
|
|
96
|
+
onReady: (e) => this.onReady(e),
|
|
97
|
+
onPick: (r) => this.onPick(r),
|
|
98
|
+
onError: (e) => this.onError(e),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 宿主能力的钩子:请求下一帧重绘。
|
|
104
|
+
* maplibre → `map.triggerRepaint()`;arcgis → `externalRenderers.requestRender(view)`。
|
|
105
|
+
*/
|
|
106
|
+
protected abstract requestRepaint(): void;
|
|
107
|
+
|
|
108
|
+
/** 宿主方位角(度);宿主无关默认 0(灯光不跟随视角) */
|
|
109
|
+
protected getBearing(): number {
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* ----------------------------------------------------------------- 生命周期 */
|
|
114
|
+
|
|
115
|
+
/** 挂载渲染内核到宿主的 canvas + 共享 GL 上下文(上下文恢复时原地换新 renderer) */
|
|
116
|
+
protected mountViewer(canvas: HTMLCanvasElement, gl: WebGLRenderingContext | WebGL2RenderingContext): void {
|
|
117
|
+
if (this.viewer.renderer) {
|
|
118
|
+
// 上下文恢复路径:onAdd 被再次触发(map.addLayer),原地换新 renderer,
|
|
119
|
+
// 保留已加载的场景与瓦片,不重建、不重拉。
|
|
120
|
+
this.viewer.restoreContext(gl);
|
|
121
|
+
} else {
|
|
122
|
+
this.viewer.mount(canvas, gl);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** 卸载渲染内核(保留已加载的瓦片,下次 mount 可复用) */
|
|
127
|
+
protected unmountViewer(): void {
|
|
128
|
+
this.viewer.unmount();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* ----------------------------------------------------------------- 每帧驱动 */
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 把宿主抽好的矩阵喂给内核,并按需请求下一帧。
|
|
135
|
+
* 返回内核是否需要继续驱动(动态着色 / 瓦片加载中 / LOD 变化)。
|
|
136
|
+
*/
|
|
137
|
+
protected driveFrame(frame: HostFrame): boolean {
|
|
138
|
+
const needsNext = this.viewer.renderFrame(frame);
|
|
139
|
+
if (needsNext) this.requestRepaint();
|
|
140
|
+
return needsNext;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* ----------------------------------------------------------------- 投影模式 */
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* 切换投影模式,可带平滑过渡。
|
|
147
|
+
* 正交只影响本层:底图瓦片、地形、DOM Marker / 弹窗仍走宿主的透视投影。
|
|
148
|
+
* 拾取、选中描边、按单体着色/隐藏/抬高不受影响。
|
|
149
|
+
*/
|
|
150
|
+
setProjection(mode: ProjectionMode, transition?: TransitionOptions): void {
|
|
151
|
+
const next = mode === 'orthographic' ? 'orthographic' : 'perspective';
|
|
152
|
+
const targetT = next === 'orthographic' ? 1 : 0;
|
|
153
|
+
const duration = transition?.duration ?? 0;
|
|
154
|
+
const wantAnim = duration > 0 || !!transition?.spring;
|
|
155
|
+
|
|
156
|
+
this._projection = next;
|
|
157
|
+
this._orthoWarned = false;
|
|
158
|
+
|
|
159
|
+
if (!wantAnim) {
|
|
160
|
+
if (this.viewer.animator.has('projection.t')) this.viewer.animator.cancel('projection.t');
|
|
161
|
+
this._projectionT = targetT;
|
|
162
|
+
this.requestRepaint();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
this._ensureProjectionChannel();
|
|
167
|
+
this.viewer.animator.to('projection.t', targetT, {
|
|
168
|
+
...transition,
|
|
169
|
+
duration,
|
|
170
|
+
easing: transition?.easing ?? 'easeInOutCubic',
|
|
171
|
+
onComplete: () => {
|
|
172
|
+
this._projectionT = targetT;
|
|
173
|
+
this.requestRepaint();
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
this.requestRepaint();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** 当前投影模式 */
|
|
180
|
+
get projection(): ProjectionMode {
|
|
181
|
+
return this._projection;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** 当前正交插值比例(0 = 纯透视,1 = 纯正交) */
|
|
185
|
+
get projectionT(): number {
|
|
186
|
+
return this._projectionT;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** 正交插值参数通道:由 animator 平滑推进,写回时请求重绘 */
|
|
190
|
+
protected _ensureProjectionChannel(): void {
|
|
191
|
+
if (this.viewer.animator.has('projection.t')) return;
|
|
192
|
+
this.viewer.animator.register('projection.t', {
|
|
193
|
+
dim: 1,
|
|
194
|
+
read: (out) => {
|
|
195
|
+
out[0] = this._projectionT;
|
|
196
|
+
},
|
|
197
|
+
write: (v) => {
|
|
198
|
+
this._projectionT = v[0];
|
|
199
|
+
this.requestRepaint();
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* ----------------------------------------------------------------- 近平面缩放 */
|
|
205
|
+
|
|
206
|
+
/** 动态调整近裁剪面缩放(0 < scale < 1)。传 1 / 0 / 非法值 = 恢复宿主原始 near */
|
|
207
|
+
setNearPlaneScale(scale: number): void {
|
|
208
|
+
this._nearPlaneScale = HostRenderer.normalizeNearPlaneScale(scale);
|
|
209
|
+
this.requestRepaint();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** 当前近裁剪面缩放系数(1 = 不改,用宿主的默认值) */
|
|
213
|
+
get nearPlaneScale(): number {
|
|
214
|
+
return this._nearPlaneScale;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** 近裁剪缩放系数的合法化:非数字 / <=0 / >=1 一律视为「不改」 */
|
|
218
|
+
static normalizeNearPlaneScale(v: number | undefined): number {
|
|
219
|
+
if (typeof v !== 'number' || !Number.isFinite(v)) return 1;
|
|
220
|
+
return v > 0 && v < 1 ? v : 1;
|
|
221
|
+
}
|
|
222
|
+
}
|
package/src/render/S3MViewer.ts
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
import * as THREE from 'three';
|
|
24
24
|
import { S3MTileset, usableGeoBounds } from '../tileset/S3MTileset.js';
|
|
25
25
|
import type { BuildTileFn, TileNode } from '../tileset/S3MTileset.js';
|
|
26
|
+
import { authFetch, type AuthenticateFn } from '../core/AuthFetch.js';
|
|
26
27
|
import { setMaxAnisotropy, setCompressedTexturesSupported, setTextureOffThreadDecode, setMaxTextureSize as setTextureSizeCap } from './TextureFactory.js';
|
|
27
28
|
import { getMaterialQuality, setMaterialQuality } from './StyleMaterial.js';
|
|
28
29
|
import { decodeTextureWithWorker } from '../worker/S3MWorkerClient.js';
|
|
@@ -290,6 +291,13 @@ export interface S3MViewerOptions {
|
|
|
290
291
|
onRequestRepaint?: () => void;
|
|
291
292
|
/** 地图朝向(弧度),用于让灯光跟着视角走。不传则灯光方向固定 */
|
|
292
293
|
getBearing?: () => number;
|
|
294
|
+
/**
|
|
295
|
+
* 鉴权适配函数(全局默认,数据集可用自己的 `authenticate` 覆盖)。
|
|
296
|
+
* 内核主线程发出的全部请求(配置 scp / 瓦片 / 子图集 / 棱线缓存 / 属性查询)
|
|
297
|
+
* 发出前都过一遍,可改写 URL(加 `?token=`)或附加请求头。
|
|
298
|
+
* 不传 = 行为与旧版完全一致。见 `AuthenticateFn`。
|
|
299
|
+
*/
|
|
300
|
+
authenticate?: AuthenticateFn;
|
|
293
301
|
onStats?: (stats: Stats) => void;
|
|
294
302
|
onReady?: (entry: S3MDatasetEntry) => void;
|
|
295
303
|
onPick?: (result: PickResult | null) => void;
|
|
@@ -572,6 +580,8 @@ export class S3MViewer {
|
|
|
572
580
|
/** 宿主重画信号与地图朝向,构造时注入 */
|
|
573
581
|
private _onRequestRepaint: () => void = () => {};
|
|
574
582
|
private _getBearing: (() => number) | undefined;
|
|
583
|
+
/** 鉴权适配(全局默认),构造时注入 */
|
|
584
|
+
private readonly _authenticate: AuthenticateFn | undefined;
|
|
575
585
|
private _lodRangeScale = 1.0;
|
|
576
586
|
/** LOD 判定屏幕高度的 DPR 上限。Infinity = 不截断(默认,行为同旧版) */
|
|
577
587
|
private _lodPixelRatioCap = Infinity;
|
|
@@ -600,6 +610,7 @@ export class S3MViewer {
|
|
|
600
610
|
}
|
|
601
611
|
this._onRequestRepaint = options.onRequestRepaint ?? (() => {});
|
|
602
612
|
this._getBearing = options.getBearing;
|
|
613
|
+
this._authenticate = options.authenticate;
|
|
603
614
|
this.onStats = options.onStats ?? (() => {});
|
|
604
615
|
this.onReady = options.onReady ?? (() => {});
|
|
605
616
|
this.onPick = options.onPick ?? (() => {});
|
|
@@ -670,7 +681,11 @@ export class S3MViewer {
|
|
|
670
681
|
|
|
671
682
|
this._fps.last = performance.now();
|
|
672
683
|
this._datasetQueue = this._normalizeDatasets(options);
|
|
673
|
-
if (options.attributes)
|
|
684
|
+
if (options.attributes)
|
|
685
|
+
this.attributeQuery = new AttributeQuery({
|
|
686
|
+
...options.attributes,
|
|
687
|
+
authenticate: options.attributes.authenticate ?? this._authenticate,
|
|
688
|
+
});
|
|
674
689
|
}
|
|
675
690
|
|
|
676
691
|
/* ---------------------------------------------------------------- 生命周期 */
|
|
@@ -950,7 +965,8 @@ export class S3MViewer {
|
|
|
950
965
|
},
|
|
951
966
|
},
|
|
952
967
|
this.options.maxTriangles ?? Infinity,
|
|
953
|
-
this.options.maxImageCache ?? 128
|
|
968
|
+
this.options.maxImageCache ?? 128,
|
|
969
|
+
this._authenticate
|
|
954
970
|
);
|
|
955
971
|
return entry;
|
|
956
972
|
}
|
|
@@ -1616,7 +1632,9 @@ export class S3MViewer {
|
|
|
1616
1632
|
/* ---------------------------------------------------------------- 按业务字段着色 */
|
|
1617
1633
|
|
|
1618
1634
|
setAttributeSource(options: AttributeQueryOptions | null): void {
|
|
1619
|
-
this.attributeQuery = options
|
|
1635
|
+
this.attributeQuery = options
|
|
1636
|
+
? new AttributeQuery({ ...options, authenticate: options.authenticate ?? this._authenticate })
|
|
1637
|
+
: null;
|
|
1620
1638
|
}
|
|
1621
1639
|
|
|
1622
1640
|
getLoadedSmids(): number[] {
|
|
@@ -2683,7 +2701,7 @@ export class S3MViewer {
|
|
|
2683
2701
|
* @param url 棱线缓存地址(二进制 Float32 序列:x,y,z,x,y,z,… 成对成段)
|
|
2684
2702
|
*/
|
|
2685
2703
|
async loadCreases(url: string): Promise<void> {
|
|
2686
|
-
const resp = await
|
|
2704
|
+
const resp = await authFetch(url, this._authenticate, 'creases');
|
|
2687
2705
|
if (!resp.ok) throw new Error(`[s3m] 棱线缓存加载失败: ${resp.status} ${url}`);
|
|
2688
2706
|
const buf = await resp.arrayBuffer();
|
|
2689
2707
|
const arr = new Float32Array(buf);
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* 命中阈值就请求 childTile,实现渐进式细化。
|
|
8
8
|
*/
|
|
9
9
|
import { parseS3MB } from '../core/S3MBParser.js';
|
|
10
|
+
import { authFetch, type AuthenticateFn } from '../core/AuthFetch.js';
|
|
10
11
|
import { getSharedS3MWorker, S3MWorkerClient, WorkerDeadError } from '../worker/S3MWorkerClient.js';
|
|
11
12
|
import {
|
|
12
13
|
composeLeafAtlas,
|
|
@@ -281,6 +282,11 @@ export interface S3MTilesetOptions {
|
|
|
281
282
|
* 度量方式见 `_tmp/atlas/rule2.mts`。
|
|
282
283
|
*/
|
|
283
284
|
atlasLod?: boolean;
|
|
285
|
+
/**
|
|
286
|
+
* 鉴权适配函数(默认不传 = 行为与旧版一致)。每个请求(配置 scp / 瓦片 /
|
|
287
|
+
* 子图集)发出前过一遍,可改写 URL(加 `?token=`)或附加请求头。见 `AuthenticateFn`。
|
|
288
|
+
*/
|
|
289
|
+
authenticate?: AuthenticateFn;
|
|
284
290
|
}
|
|
285
291
|
|
|
286
292
|
export class S3MTileset {
|
|
@@ -360,6 +366,8 @@ export class S3MTileset {
|
|
|
360
366
|
private readonly _onError: (error: unknown) => void;
|
|
361
367
|
private readonly _onProgress: (stats: Stats) => void;
|
|
362
368
|
private readonly _maxRetries: number;
|
|
369
|
+
/** 鉴权适配函数;undefined = 不做任何改写(行为与旧版一致) */
|
|
370
|
+
readonly authenticate: AuthenticateFn | undefined;
|
|
363
371
|
/** 失败重试计数与下次可用时间,退避期间 _enqueue 会直接跳过 */
|
|
364
372
|
private readonly _retryCount = new Map<string, number>();
|
|
365
373
|
private readonly _retryAt = new Map<string, number>();
|
|
@@ -388,6 +396,7 @@ export class S3MTileset {
|
|
|
388
396
|
this._onError = options.onError ?? ((e) => console.warn(e));
|
|
389
397
|
this._onProgress = options.onProgress ?? (() => {});
|
|
390
398
|
this._maxRetries = Math.max(0, options.maxRetries ?? 2);
|
|
399
|
+
this.authenticate = options.authenticate;
|
|
391
400
|
|
|
392
401
|
// 渲染层可注入:Node 环境下不需要 three,也能跑 URL / 解析链路
|
|
393
402
|
this._buildTile = options.buildTile ?? null;
|
|
@@ -409,7 +418,7 @@ export class S3MTileset {
|
|
|
409
418
|
|
|
410
419
|
async init(): Promise<this> {
|
|
411
420
|
this.configUrl = toAbsolute(this.configUrl);
|
|
412
|
-
const res = await
|
|
421
|
+
const res = await authFetch(this.configUrl, this.authenticate, 'config');
|
|
413
422
|
if (!res.ok) throw new Error(`配置读取失败 ${res.status} ${this.configUrl}`);
|
|
414
423
|
const text = await res.text();
|
|
415
424
|
const config = parseConfigText(text);
|
|
@@ -991,7 +1000,7 @@ export class S3MTileset {
|
|
|
991
1000
|
const u = resolveUrl(dirOf(baseUrl), `${names[0]}.texblock?extratiles=${names.join(';')}`);
|
|
992
1001
|
try {
|
|
993
1002
|
if (!u) throw new Error('无法拼出 URL');
|
|
994
|
-
const res = await
|
|
1003
|
+
const res = await authFetch(u, this.authenticate, 'texblock');
|
|
995
1004
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
996
1005
|
const segments = await parseTexblockSegments(await res.arrayBuffer());
|
|
997
1006
|
if (segments.length !== names.length) {
|
|
@@ -1009,7 +1018,7 @@ export class S3MTileset {
|
|
|
1009
1018
|
const u = resolveUrl(dirOf(baseUrl), `${stem}.texblock`);
|
|
1010
1019
|
try {
|
|
1011
1020
|
if (!u) throw new Error('无法拼出 URL');
|
|
1012
|
-
const res = await
|
|
1021
|
+
const res = await authFetch(u, this.authenticate, 'texblock');
|
|
1013
1022
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1014
1023
|
const records = (await parseTexblockSegments(await res.arrayBuffer())).flat();
|
|
1015
1024
|
this.putLeafRecords(stem, records);
|
|
@@ -1052,7 +1061,7 @@ export class S3MTileset {
|
|
|
1052
1061
|
groupNames = cachedSet.names;
|
|
1053
1062
|
tile = cachedSet.tiles[groupIndex] ?? cachedSet.tiles[0]!;
|
|
1054
1063
|
} else {
|
|
1055
|
-
const res = await
|
|
1064
|
+
const res = await authFetch(baseUrl, this.authenticate, 'tile');
|
|
1056
1065
|
if (!res.ok) {
|
|
1057
1066
|
throw new Error(`HTTP ${res.status} 加载瓦片失败: ${baseUrl}`);
|
|
1058
1067
|
}
|