astro-viewer 2.0.0 → 3.0.0
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/astroviewer.cjs +18851 -17175
- package/dist/astroviewer.js +1 -1
- package/dist/astroviewer.min.js +1 -1
- package/lib-esm/AstroSphere.d.ts +9 -0
- package/lib-esm/AstroSphere.js +63 -9
- package/lib-esm/AstroViewer.d.ts +18 -0
- package/lib-esm/AstroViewer.js +46 -0
- package/lib-esm/index.d.ts +5 -0
- package/lib-esm/index.js +4 -0
- package/lib-esm/model/AbstractSkyEntity.d.ts +10 -0
- package/lib-esm/model/earth/XYZAncestorMeshCache.d.ts +10 -0
- package/lib-esm/model/earth/XYZAncestorMeshCache.js +31 -0
- package/lib-esm/model/earth/XYZLayer.d.ts +31 -0
- package/lib-esm/model/earth/XYZLayer.js +231 -0
- package/lib-esm/model/earth/XYZMeshBuilder.d.ts +6 -0
- package/lib-esm/model/earth/XYZMeshBuilder.js +97 -0
- package/lib-esm/model/earth/XYZTile.d.ts +39 -0
- package/lib-esm/model/earth/XYZTile.js +187 -0
- package/lib-esm/model/earth/XYZTileBuffer.d.ts +39 -0
- package/lib-esm/model/earth/XYZTileBuffer.js +149 -0
- package/lib-esm/model/earth/XYZTileProvider.d.ts +29 -0
- package/lib-esm/model/earth/XYZTileProvider.js +187 -0
- package/lib-esm/model/earth/XYZTileRequestScheduler.d.ts +25 -0
- package/lib-esm/model/earth/XYZTileRequestScheduler.js +161 -0
- package/lib-esm/model/earth/XYZVisibleTilesManager.d.ts +30 -0
- package/lib-esm/model/earth/XYZVisibleTilesManager.js +208 -0
- package/lib-esm/model/earth/types.d.ts +87 -0
- package/lib-esm/model/earth/types.js +1 -0
- package/lib-esm/model/earth/wmts/WMTSAdapter.d.ts +11 -0
- package/lib-esm/model/earth/wmts/WMTSAdapter.js +85 -0
- package/lib-esm/model/earth/wmts/types.d.ts +1 -0
- package/lib-esm/model/earth/wmts/types.js +1 -0
- package/lib-esm/model/footprints/FootprintSetGL.js +1 -1
- package/lib-esm/model/terra/TerraFootprintSetGL.d.ts +4 -0
- package/lib-esm/model/terra/TerraFootprintSetGL.js +4 -0
- package/lib-esm/model/terra/TerraPointSetGL.d.ts +4 -0
- package/lib-esm/model/terra/TerraPointSetGL.js +4 -0
- package/lib-esm/shader/XYZShaderProgram.d.ts +20 -0
- package/lib-esm/shader/XYZShaderProgram.js +88 -0
- package/package.json +1 -2
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { sphericalToCartesian } from '../../utils/Utils.js';
|
|
2
|
+
const MAX_MERCATOR_LAT = 85.0511287798066;
|
|
3
|
+
function mercatorYToLatDeg(yNormalized) {
|
|
4
|
+
const mercator = Math.PI * (1 - 2 * yNormalized);
|
|
5
|
+
return (Math.atan(Math.sinh(mercator)) * 180) / Math.PI;
|
|
6
|
+
}
|
|
7
|
+
function wrapLonToPhi(lonDeg) {
|
|
8
|
+
return lonDeg < 0 ? lonDeg + 360 : lonDeg;
|
|
9
|
+
}
|
|
10
|
+
export class XYZMeshBuilder {
|
|
11
|
+
buildTileMesh(tile, segmentsPerSide = 16) {
|
|
12
|
+
const segments = Math.max(1, Math.floor(segmentsPerSide));
|
|
13
|
+
const gridSize = segments + 1;
|
|
14
|
+
const vertexCount = gridSize * gridSize;
|
|
15
|
+
const positions = new Float32Array(vertexCount * 3);
|
|
16
|
+
const uvs = new Float32Array(vertexCount * 2);
|
|
17
|
+
const tileCount = 2 ** tile.z;
|
|
18
|
+
let p = 0;
|
|
19
|
+
let uv = 0;
|
|
20
|
+
for (let row = 0; row <= segments; row++) {
|
|
21
|
+
const v = row / segments;
|
|
22
|
+
const yNormalized = (tile.y + v) / tileCount;
|
|
23
|
+
const latDeg = Math.max(-MAX_MERCATOR_LAT, Math.min(MAX_MERCATOR_LAT, mercatorYToLatDeg(yNormalized)));
|
|
24
|
+
const thetaDeg = 90 - latDeg;
|
|
25
|
+
for (let col = 0; col <= segments; col++) {
|
|
26
|
+
const u = col / segments;
|
|
27
|
+
const xNormalized = (tile.x + u) / tileCount;
|
|
28
|
+
const lonDeg = xNormalized * 360 - 180;
|
|
29
|
+
const phiDeg = wrapLonToPhi(lonDeg);
|
|
30
|
+
const [x, y, z] = sphericalToCartesian(phiDeg, thetaDeg, 1);
|
|
31
|
+
positions[p++] = x;
|
|
32
|
+
positions[p++] = y;
|
|
33
|
+
positions[p++] = z;
|
|
34
|
+
uvs[uv++] = u;
|
|
35
|
+
uvs[uv++] = 1 - v;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const triangleCount = segments * segments * 2;
|
|
39
|
+
const rawIndices = new Uint32Array(triangleCount * 3);
|
|
40
|
+
let i = 0;
|
|
41
|
+
for (let row = 0; row < segments; row++) {
|
|
42
|
+
for (let col = 0; col < segments; col++) {
|
|
43
|
+
const topLeft = row * gridSize + col;
|
|
44
|
+
const topRight = topLeft + 1;
|
|
45
|
+
const bottomLeft = topLeft + gridSize;
|
|
46
|
+
const bottomRight = bottomLeft + 1;
|
|
47
|
+
rawIndices[i++] = topLeft;
|
|
48
|
+
rawIndices[i++] = bottomLeft;
|
|
49
|
+
rawIndices[i++] = topRight;
|
|
50
|
+
rawIndices[i++] = topRight;
|
|
51
|
+
rawIndices[i++] = bottomLeft;
|
|
52
|
+
rawIndices[i++] = bottomRight;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const indices = rawIndices.length > 65535 ? rawIndices : new Uint16Array(rawIndices);
|
|
56
|
+
return { positions, uvs, indices };
|
|
57
|
+
}
|
|
58
|
+
buildAncestorMesh(targetTile, ancestorTile, segmentsPerSide = 16) {
|
|
59
|
+
const baseMesh = this.buildTileMesh(targetTile, segmentsPerSide);
|
|
60
|
+
const dz = targetTile.z - ancestorTile.z;
|
|
61
|
+
const scale = 2 ** dz;
|
|
62
|
+
const subTileX = targetTile.x - (ancestorTile.x << dz);
|
|
63
|
+
const subTileY = targetTile.y - (ancestorTile.y << dz);
|
|
64
|
+
const uvs = new Float32Array(baseMesh.uvs.length);
|
|
65
|
+
for (let i = 0; i < baseMesh.uvs.length; i += 2) {
|
|
66
|
+
const u = baseMesh.uvs[i] ?? 0;
|
|
67
|
+
const baseV = baseMesh.uvs[i + 1] ?? 0;
|
|
68
|
+
const v = 1 - baseV;
|
|
69
|
+
uvs[i] = (subTileX + u) / scale;
|
|
70
|
+
uvs[i + 1] = 1 - (subTileY + v) / scale;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
positions: baseMesh.positions,
|
|
74
|
+
uvs,
|
|
75
|
+
indices: baseMesh.indices,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
uploadMesh(mesh, webgl) {
|
|
79
|
+
const positionBuffer = webgl.createBuffer();
|
|
80
|
+
const uvBuffer = webgl.createBuffer();
|
|
81
|
+
const indexBuffer = webgl.createBuffer();
|
|
82
|
+
const indexType = mesh.indices instanceof Uint32Array ? webgl.UNSIGNED_INT : webgl.UNSIGNED_SHORT;
|
|
83
|
+
webgl.bindBuffer(webgl.ARRAY_BUFFER, positionBuffer);
|
|
84
|
+
webgl.bufferData(webgl.ARRAY_BUFFER, mesh.positions, webgl.STATIC_DRAW);
|
|
85
|
+
webgl.bindBuffer(webgl.ARRAY_BUFFER, uvBuffer);
|
|
86
|
+
webgl.bufferData(webgl.ARRAY_BUFFER, mesh.uvs, webgl.STATIC_DRAW);
|
|
87
|
+
webgl.bindBuffer(webgl.ELEMENT_ARRAY_BUFFER, indexBuffer);
|
|
88
|
+
webgl.bufferData(webgl.ELEMENT_ARRAY_BUFFER, mesh.indices, webgl.STATIC_DRAW);
|
|
89
|
+
return {
|
|
90
|
+
positionBuffer,
|
|
91
|
+
uvBuffer,
|
|
92
|
+
indexBuffer,
|
|
93
|
+
indexCount: mesh.indices.length,
|
|
94
|
+
indexType,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { XYZShaderProgram } from '../../shader/XYZShaderProgram.js';
|
|
2
|
+
import type { XYZTileCoord, XYZTileGpuMesh, XYZTileMesh } from './types.js';
|
|
3
|
+
export declare class XYZTile {
|
|
4
|
+
private _coord;
|
|
5
|
+
private _url;
|
|
6
|
+
private _webgl;
|
|
7
|
+
private _shaderProgram;
|
|
8
|
+
private _positionBuffer;
|
|
9
|
+
private _uvBuffer;
|
|
10
|
+
private _indexBuffer;
|
|
11
|
+
private _texture;
|
|
12
|
+
private _indices;
|
|
13
|
+
private _indexType;
|
|
14
|
+
private _ready;
|
|
15
|
+
private _aborted;
|
|
16
|
+
private _loading;
|
|
17
|
+
private _failedUntil;
|
|
18
|
+
private _lastUsedAt;
|
|
19
|
+
private _createdAt;
|
|
20
|
+
private _image?;
|
|
21
|
+
private _objectUrl;
|
|
22
|
+
constructor(coord: XYZTileCoord, url: string, mesh: XYZTileMesh, webgl: WebGL2RenderingContext, shaderProgram: XYZShaderProgram);
|
|
23
|
+
get ready(): boolean;
|
|
24
|
+
get coord(): XYZTileCoord;
|
|
25
|
+
get failedUntil(): number;
|
|
26
|
+
get loading(): boolean;
|
|
27
|
+
get lastUsedAt(): number;
|
|
28
|
+
get createdAt(): number;
|
|
29
|
+
touch(): void;
|
|
30
|
+
primeLoad(priority?: number): void;
|
|
31
|
+
private loadTexture;
|
|
32
|
+
private loadImageFromBlob;
|
|
33
|
+
private onImageLoaded;
|
|
34
|
+
draw(pMatrix: Float32Array, vMatrix: Float32Array, mMatrix: Float32Array, priority?: number, allowLoad?: boolean): void;
|
|
35
|
+
drawRemapped(mesh: XYZTileGpuMesh, pMatrix: Float32Array, vMatrix: Float32Array, mMatrix: Float32Array): void;
|
|
36
|
+
private drawWithGpuMesh;
|
|
37
|
+
dispose(): void;
|
|
38
|
+
private revokeObjectUrl;
|
|
39
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { xyzTileRequestScheduler, XYZTileRequestError } from './XYZTileRequestScheduler.js';
|
|
2
|
+
export class XYZTile {
|
|
3
|
+
_coord;
|
|
4
|
+
_url;
|
|
5
|
+
_webgl;
|
|
6
|
+
_shaderProgram;
|
|
7
|
+
_positionBuffer;
|
|
8
|
+
_uvBuffer;
|
|
9
|
+
_indexBuffer;
|
|
10
|
+
_texture = null;
|
|
11
|
+
_indices;
|
|
12
|
+
_indexType;
|
|
13
|
+
_ready = false;
|
|
14
|
+
_aborted = false;
|
|
15
|
+
_loading = false;
|
|
16
|
+
_failedUntil = 0;
|
|
17
|
+
_lastUsedAt = 0;
|
|
18
|
+
_createdAt = Date.now();
|
|
19
|
+
_image;
|
|
20
|
+
_objectUrl = null;
|
|
21
|
+
constructor(coord, url, mesh, webgl, shaderProgram) {
|
|
22
|
+
this._coord = coord;
|
|
23
|
+
this._url = url;
|
|
24
|
+
this._webgl = webgl;
|
|
25
|
+
this._shaderProgram = shaderProgram;
|
|
26
|
+
this._positionBuffer = webgl.createBuffer();
|
|
27
|
+
this._uvBuffer = webgl.createBuffer();
|
|
28
|
+
this._indexBuffer = webgl.createBuffer();
|
|
29
|
+
this._indices = mesh.indices;
|
|
30
|
+
this._indexType = mesh.indices instanceof Uint32Array ? webgl.UNSIGNED_INT : webgl.UNSIGNED_SHORT;
|
|
31
|
+
webgl.bindBuffer(webgl.ARRAY_BUFFER, this._positionBuffer);
|
|
32
|
+
webgl.bufferData(webgl.ARRAY_BUFFER, mesh.positions, webgl.STATIC_DRAW);
|
|
33
|
+
webgl.bindBuffer(webgl.ARRAY_BUFFER, this._uvBuffer);
|
|
34
|
+
webgl.bufferData(webgl.ARRAY_BUFFER, mesh.uvs, webgl.STATIC_DRAW);
|
|
35
|
+
webgl.bindBuffer(webgl.ELEMENT_ARRAY_BUFFER, this._indexBuffer);
|
|
36
|
+
webgl.bufferData(webgl.ELEMENT_ARRAY_BUFFER, mesh.indices, webgl.STATIC_DRAW);
|
|
37
|
+
}
|
|
38
|
+
get ready() {
|
|
39
|
+
return this._ready;
|
|
40
|
+
}
|
|
41
|
+
get coord() {
|
|
42
|
+
return this._coord;
|
|
43
|
+
}
|
|
44
|
+
get failedUntil() {
|
|
45
|
+
return this._failedUntil;
|
|
46
|
+
}
|
|
47
|
+
get loading() {
|
|
48
|
+
return this._loading;
|
|
49
|
+
}
|
|
50
|
+
get lastUsedAt() {
|
|
51
|
+
return this._lastUsedAt;
|
|
52
|
+
}
|
|
53
|
+
get createdAt() {
|
|
54
|
+
return this._createdAt;
|
|
55
|
+
}
|
|
56
|
+
touch() {
|
|
57
|
+
this._lastUsedAt = Date.now();
|
|
58
|
+
}
|
|
59
|
+
primeLoad(priority = 0) {
|
|
60
|
+
this.loadTexture(priority);
|
|
61
|
+
}
|
|
62
|
+
loadTexture(priority = 0) {
|
|
63
|
+
if (this._loading || this._ready || this._aborted) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const now = Date.now();
|
|
67
|
+
if (this._failedUntil > now) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
this._loading = true;
|
|
71
|
+
xyzTileRequestScheduler.load(this._url, priority)
|
|
72
|
+
.then((blob) => this.loadImageFromBlob(blob))
|
|
73
|
+
.catch((error) => {
|
|
74
|
+
this._loading = false;
|
|
75
|
+
this._ready = false;
|
|
76
|
+
const cooldownMs = error instanceof XYZTileRequestError ? error.cooldownMs : 10000;
|
|
77
|
+
this._failedUntil = Date.now() + cooldownMs;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
loadImageFromBlob(blob) {
|
|
81
|
+
const image = new Image();
|
|
82
|
+
this._image = image;
|
|
83
|
+
this._objectUrl = URL.createObjectURL(blob);
|
|
84
|
+
image.onload = () => this.onImageLoaded();
|
|
85
|
+
image.onerror = () => {
|
|
86
|
+
this._loading = false;
|
|
87
|
+
this._ready = false;
|
|
88
|
+
this._failedUntil = Date.now() + 30000;
|
|
89
|
+
this.revokeObjectUrl();
|
|
90
|
+
};
|
|
91
|
+
image.src = this._objectUrl;
|
|
92
|
+
}
|
|
93
|
+
onImageLoaded() {
|
|
94
|
+
if (!this._image || this._aborted) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const gl = this._webgl;
|
|
98
|
+
const texture = gl.createTexture();
|
|
99
|
+
if (!texture) {
|
|
100
|
+
throw new Error('Could not create XYZ texture');
|
|
101
|
+
}
|
|
102
|
+
this._texture = texture;
|
|
103
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
104
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
105
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
|
|
106
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._image);
|
|
107
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
108
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
109
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
110
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
111
|
+
this._loading = false;
|
|
112
|
+
this._failedUntil = 0;
|
|
113
|
+
this._ready = true;
|
|
114
|
+
this.revokeObjectUrl();
|
|
115
|
+
}
|
|
116
|
+
draw(pMatrix, vMatrix, mMatrix, priority = 0, allowLoad = true) {
|
|
117
|
+
this.touch();
|
|
118
|
+
if (!this._ready && allowLoad) {
|
|
119
|
+
this.loadTexture(priority);
|
|
120
|
+
}
|
|
121
|
+
if (!this._ready || !this._texture) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
this.drawWithGpuMesh({
|
|
125
|
+
positionBuffer: this._positionBuffer,
|
|
126
|
+
uvBuffer: this._uvBuffer,
|
|
127
|
+
indexBuffer: this._indexBuffer,
|
|
128
|
+
indexCount: this._indices.length,
|
|
129
|
+
indexType: this._indexType,
|
|
130
|
+
}, pMatrix, vMatrix, mMatrix);
|
|
131
|
+
}
|
|
132
|
+
drawRemapped(mesh, pMatrix, vMatrix, mMatrix) {
|
|
133
|
+
this.touch();
|
|
134
|
+
if (!this._ready || !this._texture) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
this.drawWithGpuMesh(mesh, pMatrix, vMatrix, mMatrix);
|
|
138
|
+
}
|
|
139
|
+
drawWithGpuMesh(mesh, pMatrix, vMatrix, mMatrix) {
|
|
140
|
+
if (!this._texture) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const gl = this._webgl;
|
|
144
|
+
this._shaderProgram.enableShaders(pMatrix, vMatrix, mMatrix);
|
|
145
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, mesh.positionBuffer);
|
|
146
|
+
gl.vertexAttribPointer(this._shaderProgram.locations.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
|
|
147
|
+
gl.enableVertexAttribArray(this._shaderProgram.locations.vertexPositionAttribute);
|
|
148
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, mesh.uvBuffer);
|
|
149
|
+
gl.vertexAttribPointer(this._shaderProgram.locations.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
|
|
150
|
+
gl.enableVertexAttribArray(this._shaderProgram.locations.textureCoordAttribute);
|
|
151
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
152
|
+
gl.bindTexture(gl.TEXTURE_2D, this._texture);
|
|
153
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mesh.indexBuffer);
|
|
154
|
+
gl.drawElements(gl.TRIANGLES, mesh.indexCount, mesh.indexType, 0);
|
|
155
|
+
gl.disableVertexAttribArray(this._shaderProgram.locations.vertexPositionAttribute);
|
|
156
|
+
gl.disableVertexAttribArray(this._shaderProgram.locations.textureCoordAttribute);
|
|
157
|
+
}
|
|
158
|
+
dispose() {
|
|
159
|
+
const gl = this._webgl;
|
|
160
|
+
if (this._texture) {
|
|
161
|
+
gl.deleteTexture(this._texture);
|
|
162
|
+
this._texture = null;
|
|
163
|
+
}
|
|
164
|
+
if (this._positionBuffer) {
|
|
165
|
+
gl.deleteBuffer(this._positionBuffer);
|
|
166
|
+
this._positionBuffer = null;
|
|
167
|
+
}
|
|
168
|
+
if (this._uvBuffer) {
|
|
169
|
+
gl.deleteBuffer(this._uvBuffer);
|
|
170
|
+
this._uvBuffer = null;
|
|
171
|
+
}
|
|
172
|
+
if (this._indexBuffer) {
|
|
173
|
+
gl.deleteBuffer(this._indexBuffer);
|
|
174
|
+
this._indexBuffer = null;
|
|
175
|
+
}
|
|
176
|
+
this._image = undefined;
|
|
177
|
+
this.revokeObjectUrl();
|
|
178
|
+
this._loading = false;
|
|
179
|
+
this._ready = false;
|
|
180
|
+
}
|
|
181
|
+
revokeObjectUrl() {
|
|
182
|
+
if (this._objectUrl) {
|
|
183
|
+
URL.revokeObjectURL(this._objectUrl);
|
|
184
|
+
this._objectUrl = null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { XYZShaderProgram } from '../../shader/XYZShaderProgram.js';
|
|
2
|
+
import { XYZMeshBuilder } from './XYZMeshBuilder.js';
|
|
3
|
+
import { XYZTile } from './XYZTile.js';
|
|
4
|
+
import type { XYZTileCoord } from './types.js';
|
|
5
|
+
export type XYZTileRequest = {
|
|
6
|
+
tileCoord: XYZTileCoord;
|
|
7
|
+
url: string;
|
|
8
|
+
priority: number;
|
|
9
|
+
role: 'current' | 'coverage' | 'fallback' | 'base';
|
|
10
|
+
};
|
|
11
|
+
type XYZTileBufferEntry = {
|
|
12
|
+
tile: XYZTile;
|
|
13
|
+
cacheTime0?: number;
|
|
14
|
+
role: 'current' | 'coverage' | 'fallback' | 'base';
|
|
15
|
+
};
|
|
16
|
+
export declare class XYZTileBuffer {
|
|
17
|
+
private _tiles;
|
|
18
|
+
private _cachedTiles;
|
|
19
|
+
private _cacheAliveMilliSeconds;
|
|
20
|
+
private _cleanerId;
|
|
21
|
+
private _webgl;
|
|
22
|
+
private _meshBuilder;
|
|
23
|
+
private _shaderProgram;
|
|
24
|
+
constructor(minutesToLiveInCache: number | undefined, webgl: WebGL2RenderingContext, meshBuilder: XYZMeshBuilder, shaderProgram: XYZShaderProgram);
|
|
25
|
+
get activeTiles(): Map<string, XYZTileBufferEntry>;
|
|
26
|
+
get cachedTiles(): Map<string, XYZTileBufferEntry>;
|
|
27
|
+
get size(): number;
|
|
28
|
+
getTile(tileCoord: XYZTileCoord, url: string, segmentsPerSide: number, role: 'current' | 'coverage' | 'fallback' | 'base'): XYZTile;
|
|
29
|
+
private getExistingTile;
|
|
30
|
+
ensureTiles(requests: XYZTileRequest[], segmentsPerSide: number): string[];
|
|
31
|
+
getActiveTile(tileKey: string): XYZTile | null;
|
|
32
|
+
getAnyTile(tileKey: string): XYZTile | null;
|
|
33
|
+
syncVisibleTiles(visibleTileKeys: string[]): void;
|
|
34
|
+
evictCached(maxCachedTiles: number): void;
|
|
35
|
+
dispose(): void;
|
|
36
|
+
private cacheCleaner;
|
|
37
|
+
private key;
|
|
38
|
+
}
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { XYZTile } from './XYZTile.js';
|
|
2
|
+
export class XYZTileBuffer {
|
|
3
|
+
_tiles = new Map();
|
|
4
|
+
_cachedTiles = new Map();
|
|
5
|
+
_cacheAliveMilliSeconds;
|
|
6
|
+
_cleanerId;
|
|
7
|
+
_webgl;
|
|
8
|
+
_meshBuilder;
|
|
9
|
+
_shaderProgram;
|
|
10
|
+
constructor(minutesToLiveInCache = 1, webgl, meshBuilder, shaderProgram) {
|
|
11
|
+
this._cacheAliveMilliSeconds = minutesToLiveInCache * 60 * 1000;
|
|
12
|
+
this._webgl = webgl;
|
|
13
|
+
this._meshBuilder = meshBuilder;
|
|
14
|
+
this._shaderProgram = shaderProgram;
|
|
15
|
+
this._cleanerId = window.setInterval(() => {
|
|
16
|
+
this.cacheCleaner();
|
|
17
|
+
}, 10_000);
|
|
18
|
+
}
|
|
19
|
+
get activeTiles() {
|
|
20
|
+
return this._tiles;
|
|
21
|
+
}
|
|
22
|
+
get cachedTiles() {
|
|
23
|
+
return this._cachedTiles;
|
|
24
|
+
}
|
|
25
|
+
get size() {
|
|
26
|
+
return this._tiles.size + this._cachedTiles.size;
|
|
27
|
+
}
|
|
28
|
+
getTile(tileCoord, url, segmentsPerSide, role) {
|
|
29
|
+
const tileKey = this.key(tileCoord);
|
|
30
|
+
if (!this._tiles.has(tileKey)) {
|
|
31
|
+
if (this._cachedTiles.has(tileKey)) {
|
|
32
|
+
const entry = this._cachedTiles.get(tileKey);
|
|
33
|
+
entry.cacheTime0 = undefined;
|
|
34
|
+
entry.role = role;
|
|
35
|
+
this._tiles.set(tileKey, entry);
|
|
36
|
+
this._cachedTiles.delete(tileKey);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const mesh = this._meshBuilder.buildTileMesh(tileCoord, segmentsPerSide);
|
|
40
|
+
this._tiles.set(tileKey, {
|
|
41
|
+
tile: new XYZTile(tileCoord, url, mesh, this._webgl, this._shaderProgram),
|
|
42
|
+
role,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const entry = this._tiles.get(tileKey);
|
|
48
|
+
entry.role = role;
|
|
49
|
+
}
|
|
50
|
+
return this._tiles.get(tileKey).tile;
|
|
51
|
+
}
|
|
52
|
+
getExistingTile(tileCoord, role) {
|
|
53
|
+
const tileKey = this.key(tileCoord);
|
|
54
|
+
if (this._tiles.has(tileKey)) {
|
|
55
|
+
const entry = this._tiles.get(tileKey);
|
|
56
|
+
entry.role = role;
|
|
57
|
+
return entry.tile;
|
|
58
|
+
}
|
|
59
|
+
if (this._cachedTiles.has(tileKey)) {
|
|
60
|
+
const entry = this._cachedTiles.get(tileKey);
|
|
61
|
+
entry.cacheTime0 = undefined;
|
|
62
|
+
entry.role = role;
|
|
63
|
+
this._tiles.set(tileKey, entry);
|
|
64
|
+
this._cachedTiles.delete(tileKey);
|
|
65
|
+
return entry.tile;
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
ensureTiles(requests, segmentsPerSide) {
|
|
70
|
+
const visibleTileKeys = [];
|
|
71
|
+
for (const request of requests) {
|
|
72
|
+
const tile = request.role === 'fallback'
|
|
73
|
+
? this.getExistingTile(request.tileCoord, 'fallback')
|
|
74
|
+
: this.getTile(request.tileCoord, request.url, segmentsPerSide, request.role);
|
|
75
|
+
if (!tile) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
tile.touch();
|
|
79
|
+
if (request.role !== 'fallback') {
|
|
80
|
+
tile.primeLoad(request.priority);
|
|
81
|
+
}
|
|
82
|
+
visibleTileKeys.push(this.key(request.tileCoord));
|
|
83
|
+
}
|
|
84
|
+
this.syncVisibleTiles(visibleTileKeys);
|
|
85
|
+
return visibleTileKeys;
|
|
86
|
+
}
|
|
87
|
+
getActiveTile(tileKey) {
|
|
88
|
+
return this._tiles.get(tileKey)?.tile ?? null;
|
|
89
|
+
}
|
|
90
|
+
getAnyTile(tileKey) {
|
|
91
|
+
return this._tiles.get(tileKey)?.tile ?? this._cachedTiles.get(tileKey)?.tile ?? null;
|
|
92
|
+
}
|
|
93
|
+
syncVisibleTiles(visibleTileKeys) {
|
|
94
|
+
const visibleKeySet = new Set(visibleTileKeys);
|
|
95
|
+
for (const [tileKey, entry] of this._tiles) {
|
|
96
|
+
if (visibleKeySet.has(tileKey)) {
|
|
97
|
+
entry.tile.touch();
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
entry.cacheTime0 = Date.now();
|
|
101
|
+
this._cachedTiles.set(tileKey, entry);
|
|
102
|
+
this._tiles.delete(tileKey);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
evictCached(maxCachedTiles) {
|
|
106
|
+
if (this.size <= maxCachedTiles) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const candidates = Array.from(this._cachedTiles.entries()).sort((a, b) => {
|
|
110
|
+
const scoreA = Math.min(a[1].tile.lastUsedAt || a[1].tile.createdAt, a[1].tile.createdAt);
|
|
111
|
+
const scoreB = Math.min(b[1].tile.lastUsedAt || b[1].tile.createdAt, b[1].tile.createdAt);
|
|
112
|
+
return scoreA - scoreB;
|
|
113
|
+
});
|
|
114
|
+
for (const [tileKey, entry] of candidates) {
|
|
115
|
+
if (this.size <= maxCachedTiles) {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
if (entry.tile.loading) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
entry.tile.dispose();
|
|
122
|
+
this._cachedTiles.delete(tileKey);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
dispose() {
|
|
126
|
+
window.clearInterval(this._cleanerId);
|
|
127
|
+
for (const entry of this._tiles.values()) {
|
|
128
|
+
entry.tile.dispose();
|
|
129
|
+
}
|
|
130
|
+
for (const entry of this._cachedTiles.values()) {
|
|
131
|
+
entry.tile.dispose();
|
|
132
|
+
}
|
|
133
|
+
this._tiles.clear();
|
|
134
|
+
this._cachedTiles.clear();
|
|
135
|
+
}
|
|
136
|
+
cacheCleaner() {
|
|
137
|
+
const now = Date.now();
|
|
138
|
+
for (const [tileKey, entry] of this._cachedTiles) {
|
|
139
|
+
const t0 = entry.cacheTime0;
|
|
140
|
+
if (t0 !== undefined && now - t0 > this._cacheAliveMilliSeconds && !entry.tile.loading) {
|
|
141
|
+
entry.tile.dispose();
|
|
142
|
+
this._cachedTiles.delete(tileKey);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
key(tileCoord) {
|
|
147
|
+
return `${tileCoord.z}/${tileCoord.x}/${tileCoord.y}`;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Point } from '../Point.js';
|
|
2
|
+
import type { XYZLayerConfig, XYZTileCoord } from './types.js';
|
|
3
|
+
type ViewCenterSpherical = {
|
|
4
|
+
phi: number;
|
|
5
|
+
theta: number;
|
|
6
|
+
};
|
|
7
|
+
export declare class XYZTileProvider {
|
|
8
|
+
private _config;
|
|
9
|
+
constructor(config: XYZLayerConfig);
|
|
10
|
+
get config(): XYZLayerConfig;
|
|
11
|
+
get minZoom(): number;
|
|
12
|
+
get maxZoom(): number;
|
|
13
|
+
getInitialTiles(): XYZTileCoord[];
|
|
14
|
+
getTileUrl(tile: XYZTileCoord): string;
|
|
15
|
+
resolveZoom(fovDeg: number): number;
|
|
16
|
+
private clampZoom;
|
|
17
|
+
private getEffectiveTileY;
|
|
18
|
+
private getSubdomain;
|
|
19
|
+
getVisibleTilesAtZoom(z: number, centerSphericalDeg: ViewCenterSpherical | null, fovPolygon: Point[], viewportSphericalSamples: ViewCenterSpherical[], padding?: number): XYZTileCoord[];
|
|
20
|
+
tileFromSpherical(zoom: number, sphericalDeg: ViewCenterSpherical): XYZTileCoord;
|
|
21
|
+
getNeighborTiles(tile: XYZTileCoord, ring?: number): XYZTileCoord[];
|
|
22
|
+
deduplicateTiles(tiles: XYZTileCoord[]): XYZTileCoord[];
|
|
23
|
+
private resolveViewCenter;
|
|
24
|
+
private latToTileY;
|
|
25
|
+
private wrapTileX;
|
|
26
|
+
private normalizeLonAround;
|
|
27
|
+
private clampTileY;
|
|
28
|
+
}
|
|
29
|
+
export {};
|