itowns
Version:
A JS/WebGL framework for 3D geospatial data visualization
92 lines • 3.18 kB
JavaScript
import * as THREE from 'three';
import { spawn, Thread, Transfer } from 'threads';
let _thread;
function workerInstance() {
return new Worker(/* webpackChunkName: "itowns_potree2worker" */
new URL('../Worker/Potree2Worker.js', import.meta.url), {
type: 'module'
});
}
async function loader() {
if (_thread) {
return _thread;
}
_thread = await spawn(workerInstance());
return _thread;
}
function decoder(w, metadata) {
return metadata.encoding === 'BROTLI' ? w.parseBrotli : w.parse;
}
export default {
/**
* @return {Promise<void>}
*/
terminate() {
const currentThread = _thread;
_thread = undefined;
return Thread.terminate(currentThread);
},
/** @module Potree2BinParser */
/** Parse .bin PotreeConverter 2.0 format and convert to a THREE.BufferGeometry
* @function parse
* @param {ArrayBuffer} buffer - the bin buffer.
* @param {Object} options
* @param {string[]} options.in.pointAttributes - the point attributes information contained in metadata.js
* @return {Promise} - a promise that resolves with a THREE.BufferGeometry.
*
*/
parse: async function (buffer, options) {
const metadata = options.in.source.metadata;
const layer = options.out;
const pointAttributes = layer.pointAttributes;
const scale = metadata.scale;
const box = options.in.bbox;
const min = box.min;
const size = box.max.clone().sub(box.min);
const max = box.max;
const offset = metadata.offset;
const numPoints = options.in.numPoints;
const potreeLoader = await loader();
const decode = decoder(potreeLoader, metadata);
const data = await decode(Transfer(buffer), {
pointAttributes,
scale,
min,
max,
size,
offset,
numPoints
});
const buffers = data.attributeBuffers;
const geometry = new THREE.BufferGeometry();
Object.keys(buffers).forEach(property => {
const buffer = buffers[property].buffer;
if (property === 'position') {
geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(buffer), 3));
} else if (property === 'rgba') {
geometry.setAttribute('color', new THREE.BufferAttribute(new Uint8Array(buffer), 4, true));
} else if (property === 'NORMAL') {
geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(buffer), 3));
} else if (property === 'INDICES') {
const bufferAttribute = new THREE.BufferAttribute(new Uint8Array(buffer), 4);
bufferAttribute.normalized = true;
geometry.setAttribute('indices', bufferAttribute);
} else {
const bufferAttribute = new THREE.BufferAttribute(new Float32Array(buffer), 1);
const batchAttribute = buffers[property].attribute;
bufferAttribute.potree = {
offset: buffers[property].offset,
scale: buffers[property].scale,
preciseBuffer: buffers[property].preciseBuffer,
range: batchAttribute.range
};
geometry.setAttribute(property, bufferAttribute);
}
});
geometry.computeBoundingBox();
return {
geometry,
density: data.density
};
}
};