itowns 2.44.3-next.35 → 2.44.3-next.37
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/itowns.js +1 -1
- package/dist/itowns.js.map +1 -1
- package/examples/copc_simple_loader.html +15 -5
- package/lib/Core/MainLoop.js +1 -3
- package/lib/Core/Prefab/TileBuilder.js +8 -5
- package/lib/Core/Scheduler/Cache.js +1 -240
- package/lib/Core/Style.js +11 -8
- package/lib/Core/TileGeometry.js +2 -2
- package/lib/Layer/CopcLayer.js +2 -2
- package/lib/Layer/EntwinePointTileLayer.js +2 -2
- package/lib/Layer/Layer.js +10 -5
- package/lib/Layer/PointCloudLayer.js +5 -3
- package/lib/Layer/Potree2Layer.js +2 -0
- package/lib/Layer/PotreeLayer.js +2 -0
- package/lib/Renderer/PointsMaterial.js +4 -4
- package/lib/Source/FileSource.js +8 -6
- package/lib/Source/OrientedImageSource.js +2 -2
- package/lib/Source/Source.js +24 -41
- package/lib/Source/VectorTilesSource.js +5 -11
- package/lib/Source/WFSSource.js +3 -3
- package/package.json +2 -1
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
</head>
|
|
20
20
|
<body>
|
|
21
21
|
<div id="description">Specify the URL of a COPC file to load:
|
|
22
|
-
<input type="text" id="
|
|
22
|
+
<input type="text" id="copc_url" />
|
|
23
23
|
<button onclick="readURL()">Load</button>
|
|
24
24
|
<div>
|
|
25
25
|
<button onClick="loadAutzen()">Load Autzen Stadium (80mb)</button>
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
|
|
72
72
|
|
|
73
73
|
function readURL() {
|
|
74
|
-
const url = document.getElementById('
|
|
74
|
+
const url = document.getElementById('copc_url').value;
|
|
75
75
|
|
|
76
76
|
if (url) {
|
|
77
77
|
setUrl(url);
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
function setUrl(url) {
|
|
82
82
|
if (!url) return;
|
|
83
83
|
|
|
84
|
-
const input_url = document.getElementById('
|
|
84
|
+
const input_url = document.getElementById('copc_url');
|
|
85
85
|
if (!input_url) return;
|
|
86
86
|
|
|
87
87
|
uri.searchParams.set('copc', url);
|
|
@@ -93,6 +93,13 @@
|
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
function load(url) {
|
|
96
|
+
const options = {};
|
|
97
|
+
const urlParams = uri.searchParams
|
|
98
|
+
urlParams.keys().forEach(key => {
|
|
99
|
+
if (key !== 'copc') {
|
|
100
|
+
options[key] = parseInt(urlParams.get(key), 10);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
96
103
|
const source = new itowns.CopcSource({ url });
|
|
97
104
|
|
|
98
105
|
if (layer) {
|
|
@@ -102,12 +109,15 @@
|
|
|
102
109
|
layer.delete();
|
|
103
110
|
}
|
|
104
111
|
|
|
105
|
-
|
|
112
|
+
const config = {
|
|
106
113
|
source,
|
|
107
114
|
crs: view.referenceCrs,
|
|
108
115
|
sseThreshold: 2,
|
|
109
116
|
pointBudget: 3000000,
|
|
110
|
-
|
|
117
|
+
...options,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
layer = new itowns.CopcLayer('COPC', config);
|
|
111
121
|
view.addLayer(layer).then(onLayerReady);
|
|
112
122
|
layer.whenReady
|
|
113
123
|
.then(() => debug.PointCloudDebug.initTools(view, layer, gui));
|
package/lib/Core/MainLoop.js
CHANGED
|
@@ -42,7 +42,6 @@ function updateElements(context, geometryLayer, elements) {
|
|
|
42
42
|
for (const attachedLayer of geometryLayer.attachedLayers) {
|
|
43
43
|
if (attachedLayer.ready) {
|
|
44
44
|
attachedLayer.update(context, attachedLayer, sub.element, sub.parent);
|
|
45
|
-
attachedLayer.cache.flush();
|
|
46
45
|
}
|
|
47
46
|
}
|
|
48
47
|
} else if (sub.elements) {
|
|
@@ -56,7 +55,6 @@ function updateElements(context, geometryLayer, elements) {
|
|
|
56
55
|
for (const attachedLayer of geometryLayer.attachedLayers) {
|
|
57
56
|
if (attachedLayer.ready) {
|
|
58
57
|
attachedLayer.update(context, attachedLayer, sub.elements[i], sub.parent);
|
|
59
|
-
attachedLayer.cache.flush();
|
|
60
58
|
}
|
|
61
59
|
}
|
|
62
60
|
}
|
|
@@ -140,7 +138,7 @@ class MainLoop extends EventDispatcher {
|
|
|
140
138
|
}
|
|
141
139
|
|
|
142
140
|
// Clear the cache of expired resources
|
|
143
|
-
|
|
141
|
+
|
|
144
142
|
view.execFrameRequesters(MAIN_LOOP_EVENTS.AFTER_LAYER_UPDATE, dt, this.#updateLoopRestarted, geometryLayer);
|
|
145
143
|
}
|
|
146
144
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
2
|
import { TileGeometry } from "../TileGeometry.js";
|
|
3
|
-
import
|
|
3
|
+
import { LRUCache } from 'lru-cache';
|
|
4
4
|
import { computeBuffers } from "./computeBufferTileGeometry.js";
|
|
5
5
|
import OBB from "../../Renderer/OBB.js";
|
|
6
6
|
const cacheBuffer = new Map();
|
|
7
|
-
const cacheTile = new
|
|
7
|
+
const cacheTile = new LRUCache({
|
|
8
|
+
max: 500
|
|
9
|
+
});
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Reference to a tile's extent with rigid transformations.
|
|
@@ -19,7 +21,8 @@ export function newTileGeometry(builder, params) {
|
|
|
19
21
|
} = builder.computeShareableExtent(params.extent);
|
|
20
22
|
const south = shareableExtent.south.toFixed(6);
|
|
21
23
|
const bufferKey = `${builder.crs}_${params.disableSkirt ? 0 : 1}_${params.segments}`;
|
|
22
|
-
|
|
24
|
+
const key = `s${south}l${params.level}bK${bufferKey}`;
|
|
25
|
+
let promiseGeometry = cacheTile.get(key);
|
|
23
26
|
|
|
24
27
|
// build geometry if doesn't exist
|
|
25
28
|
if (!promiseGeometry) {
|
|
@@ -27,7 +30,7 @@ export function newTileGeometry(builder, params) {
|
|
|
27
30
|
promiseGeometry = new Promise(r => {
|
|
28
31
|
resolve = r;
|
|
29
32
|
});
|
|
30
|
-
cacheTile.set(
|
|
33
|
+
cacheTile.set(key, promiseGeometry);
|
|
31
34
|
params.extent = shareableExtent;
|
|
32
35
|
params.center = builder.center(params.extent).clone();
|
|
33
36
|
// Read previously cached values (index and uv.wgs84 only
|
|
@@ -63,7 +66,7 @@ export function newTileGeometry(builder, params) {
|
|
|
63
66
|
};
|
|
64
67
|
const geometry = new TileGeometry(builder, params, gpuBuffers);
|
|
65
68
|
geometry.OBB = new OBB(geometry.boundingBox.min, geometry.boundingBox.max);
|
|
66
|
-
geometry.initRefCount(cacheTile,
|
|
69
|
+
geometry.initRefCount(cacheTile, key);
|
|
67
70
|
resolve(geometry);
|
|
68
71
|
return Promise.resolve({
|
|
69
72
|
geometry,
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
let entry;
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Cache policies for flushing. Those policies can be used when something is
|
|
5
3
|
* [set]{@link Cache.set} into the Cache, as the lifetime property.
|
|
@@ -16,241 +14,4 @@ export const CACHE_POLICIES = {
|
|
|
16
14
|
INFINITE: Infinity,
|
|
17
15
|
TEXTURE: 900000,
|
|
18
16
|
GEOMETRY: 900000
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* This is a copy of the Map object, except that it also store a value for last
|
|
23
|
-
* time used. This value is used for cache expiration mechanism.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* import Cache, { CACHE_POLICIES } from 'Core/Scheduler/Cache';
|
|
27
|
-
*
|
|
28
|
-
* const cache = new Cache(CACHE_POLICIES.TEXTURE)
|
|
29
|
-
* cache.set({ bar: 1 }, 'foo');
|
|
30
|
-
* cache.set({ bar: 32 }, 'foo', 'toto');
|
|
31
|
-
*
|
|
32
|
-
* cache.get('foo');
|
|
33
|
-
*
|
|
34
|
-
* cache.delete('foo');
|
|
35
|
-
*
|
|
36
|
-
* cache.clear();
|
|
37
|
-
*
|
|
38
|
-
* cache.flush();
|
|
39
|
-
*/
|
|
40
|
-
class Cache {
|
|
41
|
-
/**
|
|
42
|
-
* @param {number} [lifetime=CACHE_POLICIES.INFINITE] The cache expiration time for all values.
|
|
43
|
-
*/
|
|
44
|
-
constructor() {
|
|
45
|
-
let lifetime = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : CACHE_POLICIES.INFINITE;
|
|
46
|
-
this.lifeTime = lifetime;
|
|
47
|
-
this.lastTimeFlush = Date.now();
|
|
48
|
-
this.data = new Map();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Returns the entry related to the specified key, content in array, from the cache.
|
|
53
|
-
* The array contents one to three key.
|
|
54
|
-
* The last time used property of the entry is updated to extend the longevity of the
|
|
55
|
-
* entry.
|
|
56
|
-
*
|
|
57
|
-
* @param {string[]|number[]} keyArray key array ([key0, key1, key3])
|
|
58
|
-
*
|
|
59
|
-
* @return {Object}
|
|
60
|
-
*/
|
|
61
|
-
|
|
62
|
-
getByArray(keyArray) {
|
|
63
|
-
return this.get(keyArray[0], keyArray[1], keyArray[2]);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Adds or updates an entry with specified keys array ([key0, key1, key3]).
|
|
68
|
-
* Caution: it overrides any existing entry already set at this/those key/s.
|
|
69
|
-
*
|
|
70
|
-
* @param {Object} value to add in cache
|
|
71
|
-
* @param {string[]|number[]} keyArray key array ([key0, key1, key3])
|
|
72
|
-
*
|
|
73
|
-
* @return {Object} the added value
|
|
74
|
-
*/
|
|
75
|
-
setByArray(value, keyArray) {
|
|
76
|
-
return this.set(value, keyArray[0], keyArray[1], keyArray[2]);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Returns the entry related to the specified key from the cache. The last
|
|
81
|
-
* time used property of the entry is updated to extend the longevity of the
|
|
82
|
-
* entry.
|
|
83
|
-
*
|
|
84
|
-
* @param {string|number} key1
|
|
85
|
-
* @param {string|number} [key2]
|
|
86
|
-
* @param {string|number} [key3]
|
|
87
|
-
*
|
|
88
|
-
* @return {Object}
|
|
89
|
-
*/
|
|
90
|
-
get(key1, key2, key3) {
|
|
91
|
-
const entry_1 = this.data.get(key1);
|
|
92
|
-
if (entry_1 == undefined) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
if (entry_1.lastTimeUsed != undefined) {
|
|
96
|
-
entry = entry_1;
|
|
97
|
-
} else {
|
|
98
|
-
const entry_2 = entry_1.get(key2);
|
|
99
|
-
if (entry_2 == undefined) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
if (entry_2.lastTimeUsed != undefined) {
|
|
103
|
-
entry = entry_2;
|
|
104
|
-
} else {
|
|
105
|
-
const entry_3 = entry_2.get(key3);
|
|
106
|
-
if (entry_3 == undefined) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
entry = entry_3;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (entry.value) {
|
|
113
|
-
entry.lastTimeUsed = Date.now();
|
|
114
|
-
return entry.value;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Adds or updates an entry with specified keys (up to 3).
|
|
120
|
-
* Caution: it overrides any existing entry already set at this/those key/s.
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* @param {Object} value to add in cache
|
|
124
|
-
* @param {string|number} key1
|
|
125
|
-
* @param {string|number} [key2]
|
|
126
|
-
* @param {string|number} [key3]
|
|
127
|
-
*
|
|
128
|
-
* @return {Object} the added value
|
|
129
|
-
*/
|
|
130
|
-
set(value, key1, key2, key3) {
|
|
131
|
-
entry = {
|
|
132
|
-
value,
|
|
133
|
-
lastTimeUsed: Date.now()
|
|
134
|
-
};
|
|
135
|
-
if (key2 == undefined) {
|
|
136
|
-
this.data.set(key1, entry);
|
|
137
|
-
return value;
|
|
138
|
-
}
|
|
139
|
-
if (!this.data.get(key1)) {
|
|
140
|
-
this.data.set(key1, new Map());
|
|
141
|
-
}
|
|
142
|
-
const entry_map = this.data.get(key1);
|
|
143
|
-
if (key3 == undefined) {
|
|
144
|
-
entry_map.set(key2, entry);
|
|
145
|
-
return value;
|
|
146
|
-
}
|
|
147
|
-
if (!entry_map.get(key2)) {
|
|
148
|
-
entry_map.set(key2, new Map());
|
|
149
|
-
}
|
|
150
|
-
entry_map.get(key2).set(key3, entry);
|
|
151
|
-
return value;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Deletes the specified entry from the cache.
|
|
156
|
-
*
|
|
157
|
-
* @param {string|number} key1
|
|
158
|
-
* @param {string|number} [key2]
|
|
159
|
-
* @param {string|number} [key3]
|
|
160
|
-
*/
|
|
161
|
-
delete(key1, key2, key3) {
|
|
162
|
-
const entry_1 = this.data.get(key1);
|
|
163
|
-
if (entry_1 === undefined) {
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
if (entry_1.lastTimeUsed != undefined) {
|
|
167
|
-
delete this.data.get(key1);
|
|
168
|
-
this.data.delete(key1);
|
|
169
|
-
} else {
|
|
170
|
-
const entry_2 = entry_1.get(key2);
|
|
171
|
-
if (entry_2 === undefined) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
if (entry_2.lastTimeUsed != undefined) {
|
|
175
|
-
delete entry_1.get(key2);
|
|
176
|
-
entry_1.delete(key2);
|
|
177
|
-
if (entry_1.size == 0) {
|
|
178
|
-
this.data.delete(key1);
|
|
179
|
-
}
|
|
180
|
-
} else {
|
|
181
|
-
const entry_3 = entry_2.get(key3);
|
|
182
|
-
if (entry_3 === undefined) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
delete entry_2.get(key3);
|
|
186
|
-
entry_2.delete(key3);
|
|
187
|
-
if (entry_2.size == 0) {
|
|
188
|
-
entry_1.delete(key2);
|
|
189
|
-
if (entry_1.size == 0) {
|
|
190
|
-
this.data.delete(key1);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Removes all entries of the cache.
|
|
199
|
-
*
|
|
200
|
-
*/
|
|
201
|
-
clear() {
|
|
202
|
-
this.data.clear();
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Flush the cache: entries that have been present for too long since the
|
|
207
|
-
* last time they were used, are removed from the cache. By default, the
|
|
208
|
-
* time is the current time, but the interval can be reduced by doing
|
|
209
|
-
* something like `Cache.flush(Date.now() - reductionTime)`. If you want to
|
|
210
|
-
* clear the whole cache, use {@link Cache.clear} instead.
|
|
211
|
-
*
|
|
212
|
-
* @param {number} [time=Date.now()]
|
|
213
|
-
*/
|
|
214
|
-
flush() {
|
|
215
|
-
let time = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Date.now();
|
|
216
|
-
if (this.lifeTime == CACHE_POLICIES.INFINITE || this.lifeTime > time - this.lastTimeFlush || !this.data.size) {
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
this.lastTimeFlush = Infinity;
|
|
220
|
-
this.data.forEach((v1, i) => {
|
|
221
|
-
if (this.lifeTime < time - v1.lastTimeUsed) {
|
|
222
|
-
delete this.data.get(i);
|
|
223
|
-
this.data.delete(i);
|
|
224
|
-
} else {
|
|
225
|
-
v1.forEach((v2, j) => {
|
|
226
|
-
if (this.lifeTime < time - v2.lastTimeUsed) {
|
|
227
|
-
delete v1.get(j);
|
|
228
|
-
v1.delete(j);
|
|
229
|
-
} else {
|
|
230
|
-
v2.forEach((v3, k) => {
|
|
231
|
-
if (this.lifeTime < time - v3.lastTimeUsed) {
|
|
232
|
-
delete v2.get(k);
|
|
233
|
-
v2.delete(k);
|
|
234
|
-
} else {
|
|
235
|
-
// Work for the moment because all flushed caches have 3 key!
|
|
236
|
-
this.lastTimeFlush = Math.min(this.lastTimeFlush, v3.lastTimeUsed);
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
if (!v2.size) {
|
|
240
|
-
delete v1.get(j);
|
|
241
|
-
v1.delete(j);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
if (!v1.size) {
|
|
246
|
-
delete this.data.get(i);
|
|
247
|
-
this.data.delete(i);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
if (this.data.size == 0) {
|
|
252
|
-
this.lastTimeFlush = Date.now();
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
export default Cache;
|
|
17
|
+
};
|
package/lib/Core/Style.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { LRUCache } from 'lru-cache';
|
|
2
2
|
import Fetcher from "../Provider/Fetcher.js";
|
|
3
3
|
import { Color } from 'three';
|
|
4
4
|
import { deltaE } from "../Renderer/Color.js";
|
|
5
5
|
import Coordinates from "./Geographic/Coordinates.js";
|
|
6
6
|
/* babel-plugin-inline-import './StyleChunk/itowns_stroke_single_before.css' */
|
|
7
7
|
const itowns_stroke_single_before = ".itowns-stroke-single:before {\n display: var(--text_stroke_display);\n content: attr(data-before);\n opacity: 1;\n position: absolute;\n -webkit-text-stroke-width: var(--text_stroke_width);\n -webkit-text-stroke-color: var(--text_stroke_color);\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: -1;\n white-space: inherit;\n overflow-wrap: inherit;\n letter-spacing: inherit;\n text-align: inherit;\n padding: inherit;\n font-family: inherit;\n text-transform: inherit;\n max-width: inherit;\n font-size: inherit;\n}\n";
|
|
8
|
-
const
|
|
8
|
+
const cachedImg = new LRUCache({
|
|
9
|
+
max: 500
|
|
10
|
+
});
|
|
9
11
|
const matrix = document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGMatrix();
|
|
10
12
|
const canvas = document.createElement('canvas');
|
|
11
13
|
function baseAltitudeDefault(properties, ctx) {
|
|
@@ -37,13 +39,14 @@ export function readExpression(property, ctx) {
|
|
|
37
39
|
}
|
|
38
40
|
return property;
|
|
39
41
|
}
|
|
40
|
-
async function loadImage(
|
|
41
|
-
|
|
42
|
+
async function loadImage(url) {
|
|
43
|
+
const imgUrl = url.split('?')[0];
|
|
44
|
+
let promise = cachedImg.get(imgUrl);
|
|
42
45
|
if (!promise) {
|
|
43
|
-
promise = Fetcher.texture(
|
|
46
|
+
promise = Fetcher.texture(url, {
|
|
44
47
|
crossOrigin: 'anonymous'
|
|
45
48
|
});
|
|
46
|
-
|
|
49
|
+
cachedImg.set(imgUrl, promise);
|
|
47
50
|
}
|
|
48
51
|
return (await promise).image;
|
|
49
52
|
}
|
|
@@ -64,7 +67,7 @@ function replaceWhitePxl(imgd, color, id) {
|
|
|
64
67
|
if (!color) {
|
|
65
68
|
return imgd;
|
|
66
69
|
}
|
|
67
|
-
const imgdColored =
|
|
70
|
+
const imgdColored = cachedImg.get(`${id}_${color}`);
|
|
68
71
|
if (!imgdColored) {
|
|
69
72
|
const pix = imgd.data;
|
|
70
73
|
const newColor = new Color(color);
|
|
@@ -75,7 +78,7 @@ function replaceWhitePxl(imgd, color, id) {
|
|
|
75
78
|
pix[i + 1] = pix[i + 1] * d + newColor.g * 255 * (1 - d);
|
|
76
79
|
pix[i + 2] = pix[i + 2] * d + newColor.b * 255 * (1 - d);
|
|
77
80
|
}
|
|
78
|
-
|
|
81
|
+
cachedImg.set(`${id}_${color}`, imgd);
|
|
79
82
|
return imgd;
|
|
80
83
|
}
|
|
81
84
|
return imgdColored;
|
package/lib/Core/TileGeometry.js
CHANGED
|
@@ -71,7 +71,7 @@ export class TileGeometry extends THREE.BufferGeometry {
|
|
|
71
71
|
* @param cacheTile - The [Cache] used to store this geometry.
|
|
72
72
|
* @param keys - The [south, level, epsg] key of this geometry.
|
|
73
73
|
*/
|
|
74
|
-
initRefCount(cacheTile,
|
|
74
|
+
initRefCount(cacheTile, key) {
|
|
75
75
|
if (this._refCount !== null) {
|
|
76
76
|
return;
|
|
77
77
|
}
|
|
@@ -87,7 +87,7 @@ export class TileGeometry extends THREE.BufferGeometry {
|
|
|
87
87
|
// (in THREE.WebGLBindingStates code).
|
|
88
88
|
this.index = null;
|
|
89
89
|
delete this.attributes.uv;
|
|
90
|
-
cacheTile.delete(
|
|
90
|
+
cacheTile.delete(key);
|
|
91
91
|
super.dispose();
|
|
92
92
|
// THREE.BufferGeometry.prototype.dispose.call(this);
|
|
93
93
|
}
|
package/lib/Layer/CopcLayer.js
CHANGED
|
@@ -49,8 +49,8 @@ class CopcLayer extends PointCloudLayer {
|
|
|
49
49
|
this.root = new CopcNode(0, 0, 0, 0, pageOffset, pageLength, this, -1);
|
|
50
50
|
this.root.bbox.min.fromArray(cube, 0);
|
|
51
51
|
this.root.bbox.max.fromArray(cube, 3);
|
|
52
|
-
this.minElevationRange = source.header.min[2];
|
|
53
|
-
this.maxElevationRange = source.header.max[2];
|
|
52
|
+
this.minElevationRange = this.minElevationRange ?? source.header.min[2];
|
|
53
|
+
this.maxElevationRange = this.maxElevationRange ?? source.header.max[2];
|
|
54
54
|
this.scale = new THREE.Vector3(1.0, 1.0, 1.0);
|
|
55
55
|
this.offset = new THREE.Vector3(0.0, 0.0, 0.0);
|
|
56
56
|
return this.root.loadOctree().then(resolve);
|
|
@@ -58,8 +58,8 @@ class EntwinePointTileLayer extends PointCloudLayer {
|
|
|
58
58
|
this.root = new EntwinePointTileNode(0, 0, 0, 0, this, -1);
|
|
59
59
|
this.root.bbox.min.fromArray(this.source.boundsConforming, 0);
|
|
60
60
|
this.root.bbox.max.fromArray(this.source.boundsConforming, 3);
|
|
61
|
-
this.minElevationRange = this.source.boundsConforming[2];
|
|
62
|
-
this.maxElevationRange = this.source.boundsConforming[5];
|
|
61
|
+
this.minElevationRange = this.minElevationRange ?? this.source.boundsConforming[2];
|
|
62
|
+
this.maxElevationRange = this.maxElevationRange ?? this.source.boundsConforming[5];
|
|
63
63
|
this.extent = Extent.fromBox3(config.crs || 'EPSG:4326', this.root.bbox);
|
|
64
64
|
return this.root.loadOctree().then(resolve);
|
|
65
65
|
});
|
package/lib/Layer/Layer.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as THREE from 'three';
|
|
|
2
2
|
import { STRATEGY_MIN_NETWORK_TRAFFIC } from "./LayerUpdateStrategy.js";
|
|
3
3
|
import InfoLayer from "./InfoLayer.js";
|
|
4
4
|
import Source from "../Source/Source.js";
|
|
5
|
-
import
|
|
5
|
+
import { LRUCache } from 'lru-cache';
|
|
6
6
|
import Style from "../Core/Style.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -195,7 +195,12 @@ class Layer extends THREE.EventDispatcher {
|
|
|
195
195
|
/**
|
|
196
196
|
* @type {Cache}
|
|
197
197
|
*/
|
|
198
|
-
this.cache = new
|
|
198
|
+
this.cache = new LRUCache({
|
|
199
|
+
max: 500,
|
|
200
|
+
...(cacheLifeTime !== Infinity && {
|
|
201
|
+
ttl: cacheLifeTime
|
|
202
|
+
})
|
|
203
|
+
});
|
|
199
204
|
this.mergeFeatures = mergeFeatures;
|
|
200
205
|
}
|
|
201
206
|
addInitializationStep() {
|
|
@@ -267,13 +272,13 @@ class Layer extends THREE.EventDispatcher {
|
|
|
267
272
|
return data;
|
|
268
273
|
}
|
|
269
274
|
getData(from, to) {
|
|
270
|
-
const key = this.source.
|
|
271
|
-
let data = this.cache.
|
|
275
|
+
const key = this.source.getDataKey(this.source.isVectorSource ? to : from);
|
|
276
|
+
let data = this.cache.get(key);
|
|
272
277
|
if (!data) {
|
|
273
278
|
data = this.source.loadData(from, this).then(feat => this.convert(feat, to), err => {
|
|
274
279
|
throw err;
|
|
275
280
|
});
|
|
276
|
-
this.cache.
|
|
281
|
+
this.cache.set(key, data);
|
|
277
282
|
}
|
|
278
283
|
return data;
|
|
279
284
|
}
|
|
@@ -130,7 +130,9 @@ class PointCloudLayer extends GeometryLayer {
|
|
|
130
130
|
* contains three elements `name, protocol, extent`, these elements will be
|
|
131
131
|
* available using `layer.name` or something else depending on the property
|
|
132
132
|
* name. See the list of properties to know which one can be specified.
|
|
133
|
-
* @param {Source} config.source - Description and options of the source.
|
|
133
|
+
* @param {Source} config.source - Description and options of the source See @Layer.
|
|
134
|
+
* @param {number} [options.minElevationRange] - Min value for the elevation range (default value will be taken from the source.metadata).
|
|
135
|
+
* @param {number} [options.maxElevationRange] - Max value for the elevation range (default value will be taken from the source.metadata).
|
|
134
136
|
*/
|
|
135
137
|
constructor(id) {
|
|
136
138
|
let config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -144,8 +146,8 @@ class PointCloudLayer extends GeometryLayer {
|
|
|
144
146
|
sseThreshold = 2,
|
|
145
147
|
minIntensityRange = 1,
|
|
146
148
|
maxIntensityRange = 65536,
|
|
147
|
-
minElevationRange
|
|
148
|
-
maxElevationRange
|
|
149
|
+
minElevationRange,
|
|
150
|
+
maxElevationRange,
|
|
149
151
|
minAngleRange = -90,
|
|
150
152
|
maxAngleRange = 90,
|
|
151
153
|
material = {},
|
|
@@ -154,6 +154,8 @@ class Potree2Layer extends PointCloudLayer {
|
|
|
154
154
|
const root = new Potree2Node(0, 0, this);
|
|
155
155
|
root.bbox = boundingBox;
|
|
156
156
|
root.boundingSphere = boundingBox.getBoundingSphere(new THREE.Sphere());
|
|
157
|
+
this.minElevationRange = this.minElevationRange ?? metadata.boundingBox.min[2];
|
|
158
|
+
this.maxElevationRange = this.maxElevationRange ?? metadata.boundingBox.max[2];
|
|
157
159
|
root.id = 'r';
|
|
158
160
|
root.depth = 0;
|
|
159
161
|
root.nodeType = 2;
|
package/lib/Layer/PotreeLayer.js
CHANGED
|
@@ -62,6 +62,8 @@ class PotreeLayer extends PointCloudLayer {
|
|
|
62
62
|
this.root = new PotreeNode(0, 0, this);
|
|
63
63
|
this.root.bbox.min.set(cloud.boundingBox.lx, cloud.boundingBox.ly, cloud.boundingBox.lz);
|
|
64
64
|
this.root.bbox.max.set(cloud.boundingBox.ux, cloud.boundingBox.uy, cloud.boundingBox.uz);
|
|
65
|
+
this.minElevationRange = this.minElevationRange ?? cloud.boundingBox.lz;
|
|
66
|
+
this.maxElevationRange = this.maxElevationRange ?? cloud.boundingBox.uz;
|
|
65
67
|
this.extent = Extent.fromBox3(this.source.crs || 'EPSG:4326', this.root.bbox);
|
|
66
68
|
return this.root.loadOctree().then(resolve);
|
|
67
69
|
});
|
|
@@ -262,10 +262,7 @@ class PointsMaterial extends THREE.ShaderMaterial {
|
|
|
262
262
|
* @param {number} [options.mode=PNTS_MODE.COLOR] display mode.
|
|
263
263
|
* @param {number} [options.shape=PNTS_SHAPE.CIRCLE] rendered points shape.
|
|
264
264
|
* @param {THREE.Vector4} [options.overlayColor=new THREE.Vector4(0, 0, 0, 0)] overlay color.
|
|
265
|
-
|
|
266
|
-
* @param {THREE.Vector2} [options.elevationRange=new THREE.Vector2(0, 1000)] elevation range.
|
|
267
|
-
* @param {THREE.Vector2} [options.angleRange=new THREE.Vector2(-90, 90)] scan angle range.
|
|
268
|
-
* @param {Scheme} [options.classificationScheme] LUT for point classification colorization.
|
|
265
|
+
* @param {Scheme} [options.classificationScheme] LUT for point classification colorization.
|
|
269
266
|
* @param {Scheme} [options.discreteScheme] LUT for other discret point values colorization.
|
|
270
267
|
* @param {string} [options.gradient] Descrition of the gradient to use for continuous point values.
|
|
271
268
|
* (Default value will be the 'SPECTRAL' gradient from Utils/Gradients)
|
|
@@ -273,6 +270,9 @@ class PointsMaterial extends THREE.ShaderMaterial {
|
|
|
273
270
|
* @param {number} [options.minAttenuatedSize=3] minimum scale used by 'ATTENUATED' size mode
|
|
274
271
|
* @param {number} [options.maxAttenuatedSize=10] maximum scale used by 'ATTENUATED' size mode
|
|
275
272
|
*
|
|
273
|
+
* @property {THREE.Vector2} [options.intensityRange=new THREE.Vector2(1, 65536)] intensity range (default value will be [1, 65536] if not defined at Layer level).
|
|
274
|
+
* @property {THREE.Vector2} [options.elevationRange=new THREE.Vector2(0, 1000)] elevation range (default value will be [0, 1000] if not defined at Layer level).
|
|
275
|
+
* @property {THREE.Vector2} [options.angleRange=new THREE.Vector2(-90, 90)] scan angle range (default value will be [-90, 90] if not defined at Layer level).
|
|
276
276
|
* @property {Scheme} classificationScheme - Color scheme for point classification values.
|
|
277
277
|
* @property {Scheme} discreteScheme - Color scheme for all other discrete values.
|
|
278
278
|
* @property {object} gradients - Descriptions of all available gradients.
|
package/lib/Source/FileSource.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Source from "./Source.js";
|
|
2
|
-
import
|
|
2
|
+
import { LRUCache } from 'lru-cache';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* An object defining the source of a single resource to get from a direct
|
|
@@ -133,8 +133,10 @@ class FileSource extends Source {
|
|
|
133
133
|
this.fetchedData = f;
|
|
134
134
|
});
|
|
135
135
|
} else if (source.features) {
|
|
136
|
-
this._featuresCaches[source.features.crs] = new
|
|
137
|
-
|
|
136
|
+
this._featuresCaches[source.features.crs] = new LRUCache({
|
|
137
|
+
max: 500
|
|
138
|
+
});
|
|
139
|
+
this._featuresCaches[source.features.crs].set(0, Promise.resolve(source.features));
|
|
138
140
|
}
|
|
139
141
|
this.whenReady.then(() => this.fetchedData);
|
|
140
142
|
this.zoom = {
|
|
@@ -148,14 +150,14 @@ class FileSource extends Source {
|
|
|
148
150
|
onLayerAdded(options) {
|
|
149
151
|
options.in = this;
|
|
150
152
|
super.onLayerAdded(options);
|
|
151
|
-
let features = this._featuresCaches[options.out.crs].
|
|
153
|
+
let features = this._featuresCaches[options.out.crs].get(0);
|
|
152
154
|
if (!features) {
|
|
153
155
|
options.out.buildExtent = this.crs != 'EPSG:4978';
|
|
154
156
|
if (options.out.buildExtent) {
|
|
155
157
|
options.out.forcedExtentCrs = options.out.crs != 'EPSG:4978' ? options.out.crs : this.crs;
|
|
156
158
|
}
|
|
157
159
|
features = this.parser(this.fetchedData, options);
|
|
158
|
-
this._featuresCaches[options.out.crs].
|
|
160
|
+
this._featuresCaches[options.out.crs].set(0, features);
|
|
159
161
|
}
|
|
160
162
|
features.then(data => {
|
|
161
163
|
if (data.extent) {
|
|
@@ -177,7 +179,7 @@ class FileSource extends Source {
|
|
|
177
179
|
* @return {FeatureCollection|Texture} The parsed data.
|
|
178
180
|
*/
|
|
179
181
|
loadData(extent, out) {
|
|
180
|
-
return this._featuresCaches[out.crs].
|
|
182
|
+
return this._featuresCaches[out.crs].get(0);
|
|
181
183
|
}
|
|
182
184
|
extentInsideLimit(extent) {
|
|
183
185
|
return this.extent.intersectsExtent(extent);
|
|
@@ -41,8 +41,8 @@ class OrientedImageSource extends Source {
|
|
|
41
41
|
urlFromExtent(imageInfo) {
|
|
42
42
|
return this.imageUrl(imageInfo.cameraId, imageInfo.panoId);
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
return
|
|
44
|
+
getDataKey(image) {
|
|
45
|
+
return `c${image.cameraId}p${image.panoId}`;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|