@jdultra/threedtiles 3.3.0 → 3.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -14
- package/index.html +1 -4
- package/package.json +1 -1
- package/src/index.js +40 -25
- package/src/tileset/OGC3DTile.js +32 -18
- package/src/tileset/TileLoader.js +167 -142
- package/src/draco/draco_decoder.js +0 -48
- package/src/draco/draco_decoder.wasm +0 -0
- package/src/draco/draco_encoder.js +0 -33
- package/src/draco/draco_wasm_wrapper.js +0 -104
|
@@ -1,157 +1,175 @@
|
|
|
1
1
|
import { LinkedHashMap } from 'js-utils-z';
|
|
2
2
|
import { B3DMDecoder } from "../decoder/B3DMDecoder";
|
|
3
3
|
import { setIntervalAsync } from 'set-interval-async/dynamic';
|
|
4
|
+
import { initial } from 'lodash';
|
|
5
|
+
import * as THREE from 'three';
|
|
4
6
|
|
|
5
|
-
const ready = [];
|
|
6
|
-
const downloads = [];
|
|
7
|
-
const nextReady = [];
|
|
8
|
-
const nextDownloads = [];
|
|
9
7
|
let concurentDownloads = 0;
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (nextDownloads.length == 0) return;
|
|
18
|
-
}
|
|
19
|
-
while (nextDownloads.length > 0 && concurentDownloads < 500) {
|
|
20
|
-
const nextDownload = nextDownloads.shift();
|
|
21
|
-
if (!!nextDownload && nextDownload.shouldDoDownload()) {
|
|
22
|
-
nextDownload.doDownload();
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
9
|
+
class TileLoader {
|
|
10
|
+
constructor(meshCallback, maxCachedItems) {
|
|
11
|
+
this.meshCallback = meshCallback;
|
|
12
|
+
this.cache = new LinkedHashMap();
|
|
13
|
+
this.maxCachedItems = !!maxCachedItems ? maxCachedItems : 100;
|
|
14
|
+
this.register = {};
|
|
26
15
|
|
|
27
16
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
function loadBatch() {
|
|
34
|
-
if (nextReady.length == 0) {
|
|
35
|
-
getNextReady();
|
|
36
|
-
if (nextReady.length == 0) return 0;
|
|
17
|
+
this.ready = [];
|
|
18
|
+
this.downloads = [];
|
|
19
|
+
this.nextReady = [];
|
|
20
|
+
this.nextDownloads = [];
|
|
21
|
+
this.init();
|
|
37
22
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
23
|
+
|
|
24
|
+
init(){
|
|
25
|
+
|
|
26
|
+
const self = this;
|
|
27
|
+
setIntervalAsync(() => {
|
|
28
|
+
self.download();
|
|
29
|
+
/* const start = Date.now();
|
|
30
|
+
let uploaded = 0;
|
|
31
|
+
do{
|
|
32
|
+
uploaded = download();
|
|
33
|
+
}while(uploaded > 0 && (Date.now() - start)<= 2 ) */
|
|
34
|
+
|
|
35
|
+
}, 10);
|
|
36
|
+
setIntervalAsync(() => {
|
|
37
|
+
const start = Date.now();
|
|
38
|
+
let loaded = 0;
|
|
39
|
+
do {
|
|
40
|
+
loaded = self.loadBatch();
|
|
41
|
+
} while (loaded > 0 && (Date.now() - start) <= 0)
|
|
42
|
+
|
|
43
|
+
}, 10);
|
|
52
44
|
}
|
|
53
|
-
return 1;
|
|
54
|
-
}
|
|
55
45
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
continue;
|
|
46
|
+
scheduleDownload(f) {
|
|
47
|
+
this.downloads.unshift(f);
|
|
48
|
+
}
|
|
49
|
+
download() {
|
|
50
|
+
if (this.nextDownloads.length == 0) {
|
|
51
|
+
this.getNextDownloads();
|
|
52
|
+
if (this.nextDownloads.length == 0) return;
|
|
64
53
|
}
|
|
65
|
-
|
|
66
|
-
nextDownloads.
|
|
54
|
+
while (this.nextDownloads.length > 0 && concurentDownloads < 500) {
|
|
55
|
+
const nextDownload = this.nextDownloads.shift();
|
|
56
|
+
if (!!nextDownload && nextDownload.shouldDoDownload()) {
|
|
57
|
+
nextDownload.doDownload();
|
|
58
|
+
}
|
|
67
59
|
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
meshReceived(cache, register, key, distanceFunction, getSiblings, level, uuid) {
|
|
66
|
+
this.ready.unshift([cache, register, key, distanceFunction, getSiblings, level, uuid]);
|
|
68
67
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
smallestDistance = dist;
|
|
74
|
-
closest = i;
|
|
75
|
-
} else if (dist == smallestDistance && downloads[i].level < smallestLevel) {
|
|
76
|
-
smallestLevel = downloads[i].level;
|
|
77
|
-
closest = i
|
|
68
|
+
loadBatch() {
|
|
69
|
+
if (this.nextReady.length == 0) {
|
|
70
|
+
this.getNextReady();
|
|
71
|
+
if (this.nextReady.length == 0) return 0;
|
|
78
72
|
}
|
|
73
|
+
const data = this.nextReady.shift();
|
|
74
|
+
if (!data) return 0;
|
|
75
|
+
const cache = data[0];
|
|
76
|
+
const register = data[1];
|
|
77
|
+
const key = data[2];
|
|
78
|
+
const mesh = cache.get(key);
|
|
79
|
+
|
|
80
|
+
if (!!mesh && !!register[key]) {
|
|
81
|
+
Object.keys(register[key]).forEach(tile => {
|
|
82
|
+
const callback = register[key][tile];
|
|
83
|
+
if (!!callback) {
|
|
84
|
+
callback(mesh);
|
|
85
|
+
register[key][tile] = null;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return 1;
|
|
79
90
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
91
|
+
|
|
92
|
+
getNextDownloads() {
|
|
93
|
+
let smallestLevel = Number.MAX_VALUE;
|
|
94
|
+
let smallestDistance = Number.MAX_VALUE;
|
|
95
|
+
let closest = -1;
|
|
96
|
+
for (let i = this.downloads.length - 1; i >= 0; i--) {
|
|
97
|
+
if (!this.downloads[i].shouldDoDownload()) {
|
|
98
|
+
this.downloads.splice(i, 1);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (!this.downloads[i].distanceFunction) { // if no distance function, must be a json, give absolute priority!
|
|
102
|
+
this.nextDownloads.push(this.downloads.splice(i, 1)[0]);
|
|
87
103
|
}
|
|
88
104
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
nextReady.push(ready.splice(i, 1)[0]);
|
|
105
|
+
if (this.nextDownloads.length > 0) return;
|
|
106
|
+
for (let i = this.downloads.length - 1; i >= 0; i--) {
|
|
107
|
+
const dist = this.downloads[i].distanceFunction();
|
|
108
|
+
if (dist < smallestDistance) {
|
|
109
|
+
smallestDistance = dist;
|
|
110
|
+
closest = i;
|
|
111
|
+
} else if (dist == smallestDistance && this.downloads[i].level < smallestLevel) {
|
|
112
|
+
smallestLevel = this.downloads[i].level;
|
|
113
|
+
closest = i
|
|
114
|
+
}
|
|
100
115
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
smallestLevel = ready[i][5]
|
|
111
|
-
closest = i
|
|
116
|
+
if (closest >= 0) {
|
|
117
|
+
const closestItem = this.downloads.splice(closest, 1).pop();
|
|
118
|
+
this.nextDownloads.push(closestItem);
|
|
119
|
+
const siblings = closestItem.getSiblings();
|
|
120
|
+
for (let i = this.downloads.length - 1; i >= 0; i--) {
|
|
121
|
+
if (siblings.includes(this.downloads[i].uuid)) {
|
|
122
|
+
this.nextDownloads.push(this.downloads.splice(i, 1).pop());
|
|
123
|
+
}
|
|
124
|
+
}
|
|
112
125
|
}
|
|
113
126
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
127
|
+
|
|
128
|
+
getNextReady() {
|
|
129
|
+
let smallestLevel = Number.MAX_VALUE;
|
|
130
|
+
let smallestDistance = Number.MAX_VALUE;
|
|
131
|
+
let closest = -1;
|
|
132
|
+
for (let i = this.ready.length - 1; i >= 0; i--) {
|
|
133
|
+
|
|
134
|
+
if (!this.ready[i][3]) {// if no distance function, must be a json, give absolute priority!
|
|
135
|
+
this.nextReady.push(this.ready.splice(i, 1)[0]);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (this.nextReady.length > 0) return;
|
|
139
|
+
for (let i = this.ready.length - 1; i >= 0; i--) {
|
|
140
|
+
const dist = this.ready[i][3]();
|
|
141
|
+
if (dist < smallestDistance) {
|
|
142
|
+
smallestDistance = dist;
|
|
143
|
+
smallestLevel = this.ready[i][5]
|
|
144
|
+
closest = i
|
|
145
|
+
} else if (dist == smallestDistance && this.ready[i][5] < smallestLevel) {
|
|
146
|
+
smallestLevel = this.ready[i][5]
|
|
147
|
+
closest = i
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (closest >= 0) {
|
|
151
|
+
const closestItem = this.ready.splice(closest, 1).pop();
|
|
152
|
+
this.nextReady.push(closestItem);
|
|
153
|
+
const siblings = closestItem[4]();
|
|
154
|
+
for (let i = this.ready.length - 1; i >= 0; i--) {
|
|
155
|
+
if (siblings.includes(this.ready[i][6])) {
|
|
156
|
+
this.nextready.push(this.ready.splice(i, 1).pop());
|
|
157
|
+
}
|
|
121
158
|
}
|
|
122
159
|
}
|
|
123
160
|
}
|
|
124
|
-
}
|
|
125
|
-
setIntervalAsync(() => {
|
|
126
|
-
download();
|
|
127
|
-
/* const start = Date.now();
|
|
128
|
-
let uploaded = 0;
|
|
129
|
-
do{
|
|
130
|
-
uploaded = download();
|
|
131
|
-
}while(uploaded > 0 && (Date.now() - start)<= 2 ) */
|
|
132
|
-
|
|
133
|
-
}, 10);
|
|
134
|
-
setIntervalAsync(() => {
|
|
135
|
-
const start = Date.now();
|
|
136
|
-
let loaded = 0;
|
|
137
|
-
do {
|
|
138
|
-
loaded = loadBatch();
|
|
139
|
-
} while (loaded > 0 && (Date.now() - start) <= 1)
|
|
140
161
|
|
|
141
|
-
}, 10);
|
|
142
162
|
|
|
143
|
-
|
|
144
|
-
constructor(meshCallback, maxCachedItems) {
|
|
145
|
-
this.meshCallback = meshCallback;
|
|
146
|
-
this.cache = new LinkedHashMap();
|
|
147
|
-
this.maxCachedItems = !!maxCachedItems ? maxCachedItems : 1000;
|
|
148
|
-
this.register = {};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
get(tileIdentifier, path, callback, distanceFunction, getSiblings, level) {
|
|
163
|
+
get(abortController, tileIdentifier, path, callback, distanceFunction, getSiblings, level) {
|
|
152
164
|
const self = this;
|
|
153
165
|
const key = simplifyPath(path);
|
|
154
166
|
|
|
167
|
+
const realAbortController = new AbortController();
|
|
168
|
+
abortController.signal.addEventListener("abort", ()=>{
|
|
169
|
+
if(!self.register[key] || Object.keys(self.register[key]).length == 0){
|
|
170
|
+
realAbortController.abort();
|
|
171
|
+
}
|
|
172
|
+
})
|
|
155
173
|
|
|
156
174
|
if (!path.includes(".b3dm") && !path.includes(".json")) {
|
|
157
175
|
console.error("the 3DTiles cache can only be used to load B3DM and json data");
|
|
@@ -167,46 +185,53 @@ class TileLoader {
|
|
|
167
185
|
|
|
168
186
|
const cachedObject = self.cache.get(key);
|
|
169
187
|
if (!!cachedObject) {
|
|
170
|
-
meshReceived(self.cache, self.register, key, distanceFunction, getSiblings, level, tileIdentifier);
|
|
188
|
+
this.meshReceived(self.cache, self.register, key, distanceFunction, getSiblings, level, tileIdentifier);
|
|
171
189
|
} else if (Object.keys(self.register[key]).length == 1) {
|
|
172
190
|
let downloadFunction;
|
|
173
191
|
if (path.includes(".b3dm")) {
|
|
174
192
|
downloadFunction = () => {
|
|
175
193
|
concurentDownloads++;
|
|
176
|
-
fetch(path).then(result => {
|
|
194
|
+
fetch(path, {signal: realAbortController.signal}).then(result => {
|
|
177
195
|
concurentDownloads--;
|
|
178
196
|
if (!result.ok) {
|
|
179
197
|
console.error("could not load tile with path : " + path)
|
|
180
198
|
throw new Error(`couldn't load "${path}". Request failed with status ${result.status} : ${result.statusText}`);
|
|
181
199
|
}
|
|
182
|
-
result.arrayBuffer()
|
|
183
|
-
self.cache.put(key, mesh);
|
|
184
|
-
self.checkSize();
|
|
185
|
-
meshReceived(self.cache, self.register, key, distanceFunction, getSiblings, level, tileIdentifier);
|
|
186
|
-
});
|
|
200
|
+
return result.arrayBuffer();
|
|
187
201
|
|
|
188
|
-
})
|
|
202
|
+
})
|
|
203
|
+
.then(resultArrayBuffer=>{
|
|
204
|
+
return B3DMDecoder.parseB3DM(resultArrayBuffer, self.meshCallback);
|
|
205
|
+
})
|
|
206
|
+
.then(mesh=>{
|
|
207
|
+
self.cache.put(key, mesh);
|
|
208
|
+
self.checkSize();
|
|
209
|
+
this.meshReceived(self.cache, self.register, key, distanceFunction, getSiblings, level, tileIdentifier);
|
|
210
|
+
})
|
|
211
|
+
.catch(()=>{});;
|
|
189
212
|
}
|
|
190
213
|
} else if (path.includes(".json")) {
|
|
191
214
|
downloadFunction = () => {
|
|
192
215
|
concurentDownloads++;
|
|
193
|
-
fetch(path).then(result => {
|
|
216
|
+
fetch(path, {signal: realAbortController.signal}).then(result => {
|
|
194
217
|
concurentDownloads--;
|
|
195
218
|
if (!result.ok) {
|
|
196
219
|
console.error("could not load tile with path : " + path)
|
|
197
220
|
throw new Error(`couldn't load "${path}". Request failed with status ${result.status} : ${result.statusText}`);
|
|
198
221
|
}
|
|
199
|
-
result.json()
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
222
|
+
return result.json();
|
|
223
|
+
|
|
224
|
+
}).then(json => {
|
|
225
|
+
self.cache.put(key, json);
|
|
226
|
+
self.checkSize();
|
|
227
|
+
this.meshReceived(self.cache, self.register, key);
|
|
228
|
+
})
|
|
229
|
+
.catch(e=>console.error("tile download aborted"));
|
|
205
230
|
}
|
|
206
231
|
}
|
|
207
|
-
scheduleDownload({
|
|
232
|
+
this.scheduleDownload({
|
|
208
233
|
"shouldDoDownload": () => {
|
|
209
|
-
return !!self.register[key] && Object.keys(self.register[key]).length > 0;
|
|
234
|
+
return !abortController.signal.aborted && !!self.register[key] && Object.keys(self.register[key]).length > 0;
|
|
210
235
|
},
|
|
211
236
|
"doDownload": downloadFunction,
|
|
212
237
|
"distanceFunction": distanceFunction,
|