@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.
@@ -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
- function scheduleDownload(f) {
12
- downloads.unshift(f);
13
- }
14
- function download() {
15
- if (nextDownloads.length == 0) {
16
- getNextDownloads();
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
- return;
29
- }
30
- function meshReceived(cache, register, key, distanceFunction, getSiblings, level, uuid) {
31
- ready.unshift([cache, register, key, distanceFunction, getSiblings, level, uuid]);
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
- const data = nextReady.shift();
39
- if (!data) return 0;
40
- const cache = data[0];
41
- const register = data[1];
42
- const key = data[2];
43
- const mesh = cache.get(key);
44
- if (!!mesh && !!register[key]) {
45
- Object.keys(register[key]).forEach(tile => {
46
- const callback = register[key][tile];
47
- if (!!callback) {
48
- callback(mesh);
49
- register[key][tile] = null;
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
- function getNextDownloads() {
57
- let smallestLevel = Number.MAX_VALUE;
58
- let smallestDistance = Number.MAX_VALUE;
59
- let closest = -1;
60
- for (let i = downloads.length - 1; i >= 0; i--) {
61
- if (!downloads[i].shouldDoDownload()) {
62
- downloads.splice(i, 1);
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
- if (!downloads[i].distanceFunction) { // if no distance function, must be a json, give absolute priority!
66
- nextDownloads.push(downloads.splice(i, 1)[0]);
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
- if (nextDownloads.length > 0) return;
70
- for (let i = downloads.length - 1; i >= 0; i--) {
71
- const dist = downloads[i].distanceFunction();
72
- if (dist < smallestDistance) {
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
- if (closest >= 0) {
81
- const closestItem = downloads.splice(closest, 1).pop();
82
- nextDownloads.push(closestItem);
83
- const siblings = closestItem.getSiblings();
84
- for (let i = downloads.length - 1; i >= 0; i--) {
85
- if (siblings.includes(downloads[i].uuid)) {
86
- nextDownloads.push(downloads.splice(i, 1).pop());
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
- function getNextReady() {
93
- let smallestLevel = Number.MAX_VALUE;
94
- let smallestDistance = Number.MAX_VALUE;
95
- let closest = -1;
96
- for (let i = ready.length - 1; i >= 0; i--) {
97
-
98
- if (!ready[i][3]) {// if no distance function, must be a json, give absolute priority!
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
- if (nextReady.length > 0) return;
103
- for (let i = ready.length - 1; i >= 0; i--) {
104
- const dist = ready[i][3]();
105
- if (dist < smallestDistance) {
106
- smallestDistance = dist;
107
- smallestLevel = ready[i][5]
108
- closest = i
109
- } else if (dist == smallestDistance && ready[i][5] < smallestLevel) {
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
- if (closest >= 0) {
115
- const closestItem = ready.splice(closest, 1).pop();
116
- nextReady.push(closestItem);
117
- const siblings = closestItem[4]();
118
- for (let i = ready.length - 1; i >= 0; i--) {
119
- if (siblings.includes(ready[i][6])) {
120
- nextready.push(ready.splice(i, 1).pop());
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
- class TileLoader {
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().then(buffer => B3DMDecoder.parseB3DM(buffer, self.meshCallback)).then(mesh => {
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().then(json => {
200
- self.cache.put(key, json);
201
- self.checkSize();
202
- meshReceived(self.cache, self.register, key);
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,