Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0505297

Browse files
committed
feat: introducing workers for LAS parser
1 parent 9abdeed commit 0505297

File tree

5 files changed

+88
-17
lines changed

5 files changed

+88
-17
lines changed

src/Parser/LASParser.js

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
11
import * as THREE from 'three';
2-
import LASLoader from 'Loader/LASLoader';
2+
import { spawn, Thread, Transfer } from 'threads';
33

4-
const lasLoader = new LASLoader();
4+
let _lazPerf;
5+
let _thread;
6+
7+
function workerInstance() {
8+
return new Worker(
9+
/* webpackChunkName: "itowns_lasparser" */
10+
new URL('../Worker/LASLoaderWorker.js', import.meta.url),
11+
{ type: 'module' },
12+
);
13+
}
14+
15+
async function loader() {
16+
if (_thread) { return _thread; }
17+
_thread = await spawn(workerInstance());
18+
if (_lazPerf) { _thread.lazPerf(_lazPerf); }
19+
return _thread;
20+
}
521

622
function buildBufferGeometry(attributes) {
723
const geometry = new THREE.BufferGeometry();
@@ -53,9 +69,18 @@ export default {
5369
if (!path) {
5470
throw new Error('Path to laz-perf is mandatory');
5571
}
56-
lasLoader.lazPerf = path;
72+
_lazPerf = path;
5773
},
5874

75+
/**
76+
* Terminate all worker instances.
77+
* @returns {Promise<void>}
78+
*/
79+
terminate() {
80+
const currentThread = _thread;
81+
_thread = undefined;
82+
return Thread.terminate(currentThread);
83+
},
5984

6085
/**
6186
* Parses a chunk of a LAS or LAZ (LASZip) and returns the corresponding
@@ -79,12 +104,18 @@ export default {
79104
* @return {Promise<THREE.BufferGeometry>} A promise resolving with a
80105
* `THREE.BufferGeometry`.
81106
*/
82-
parseChunk(data, options = {}) {
83-
return lasLoader.parseChunk(data, options.in).then((parsedData) => {
84-
const geometry = buildBufferGeometry(parsedData.attributes);
85-
geometry.computeBoundingBox();
86-
return geometry;
107+
async parseChunk(data, options = {}) {
108+
const lasLoader = await loader();
109+
const parsedData = await lasLoader.parseChunk(Transfer(data), {
110+
pointCount: options.in.pointCount,
111+
header: options.in.header,
112+
eb: options.eb,
113+
colorDepth: options.in.colorDepth,
87114
});
115+
116+
const geometry = buildBufferGeometry(parsedData.attributes);
117+
geometry.computeBoundingBox();
118+
return geometry;
88119
},
89120

90121
/**
@@ -101,17 +132,21 @@ export default {
101132
* @return {Promise} A promise resolving with a `THREE.BufferGeometry`. The
102133
* header of the file is contained in `userData`.
103134
*/
104-
parse(data, options = {}) {
135+
async parse(data, options = {}) {
105136
if (options.out?.skip) {
106137
console.warn("Warning: options 'skip' not supported anymore");
107138
}
108-
return lasLoader.parseFile(data, {
109-
colorDepth: options.in?.colorDepth,
110-
}).then((parsedData) => {
111-
const geometry = buildBufferGeometry(parsedData.attributes);
112-
geometry.userData.header = parsedData.header;
113-
geometry.computeBoundingBox();
114-
return geometry;
139+
140+
const input = options.in;
141+
142+
const lasLoader = await loader();
143+
const parsedData = await lasLoader.parseFile(Transfer(data), {
144+
colorDepth: input?.colorDepth,
115145
});
146+
147+
const geometry = buildBufferGeometry(parsedData.attributes);
148+
geometry.userData.header = parsedData.header;
149+
geometry.computeBoundingBox();
150+
return geometry;
116151
},
117152
};

src/Worker/LASLoaderWorker.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { expose, Transfer } from 'threads/worker';
2+
import LASLoader from 'Loader/LASLoader';
3+
4+
const loader = new LASLoader();
5+
6+
function transferable(attributes) {
7+
return Object.values(attributes)
8+
.filter(ArrayBuffer.isView)
9+
.map(a => a.buffer);
10+
}
11+
12+
expose({
13+
lazPerf(path) {
14+
loader.lazPerf = path;
15+
},
16+
17+
async parseChunk(data, options) {
18+
const result = await loader.parseChunk(data, options);
19+
return Transfer(result, transferable(result.attributes));
20+
},
21+
22+
async parseFile(data, options) {
23+
const result = await loader.parseFile(data, options);
24+
return Transfer(result, transferable(result.attributes));
25+
},
26+
});

test/unit/entwine.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Coordinates from 'Core/Geographic/Coordinates';
55
import EntwinePointTileSource from 'Source/EntwinePointTileSource';
66
import EntwinePointTileLayer from 'Layer/EntwinePointTileLayer';
77
import EntwinePointTileNode from 'Core/EntwinePointTileNode';
8+
import LASParser from 'Parser/LASParser';
89
import sinon from 'sinon';
910
import Fetcher from 'Provider/Fetcher';
1011
import Renderer from './bootstrap';
@@ -33,14 +34,16 @@ describe('Entwine Point Tile', function () {
3334
.callsFake(() => Promise.resolve(new ArrayBuffer()));
3435
// currently no test on data fetched...
3536

37+
LASParser.enableLazPerf('./examples/libs/laz-perf');
3638
source = new EntwinePointTileSource({
3739
url: 'https://raw.githubusercontent.com/iTowns/iTowns2-sample-data/master/pointclouds/entwine',
3840
});
3941
});
4042

41-
after(function () {
43+
after(async function () {
4244
stubFetcherJson.restore();
4345
stubFetcherArrayBuf.restore();
46+
await LASParser.terminate();
4447
});
4548

4649
it('loads the EPT structure', (done) => {

test/unit/lasparser.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,9 @@ describe('LASParser', function () {
6060
assert.ok(compareWithEpsilon(bufferGeometry.boundingBox.max.y + origin.y, header.max[1], epsilon));
6161
assert.ok(compareWithEpsilon(bufferGeometry.boundingBox.max.z + origin.z, header.max[2], epsilon));
6262
});
63+
64+
afterEach(async function () {
65+
await LASParser.terminate();
66+
});
6367
});
6468
});

webpack.config.cjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ module.exports = () => {
6161
itowns_potree2worker: {
6262
import: './src/Worker/Potree2Worker.js',
6363
},
64+
itowns_lasworker: {
65+
import: './src/Worker/LASLoaderWorker.js',
66+
},
6467
},
6568
devtool: 'source-map',
6669
output: {

0 commit comments

Comments
 (0)