python
This commit is contained in:
Andreas Wilms
2025-09-08 16:25:55 +02:00
commit 78481ca337
617 changed files with 345831 additions and 0 deletions

View File

@@ -0,0 +1,669 @@
/* global onmessage:true postMessage:false */
/* exported onmessage */
// http://jsperf.com/uint8array-vs-dataview3/3
function CustomView (buffer) {
this.buffer = buffer;
this.u8 = new Uint8Array(buffer);
let tmp = new ArrayBuffer(4);
let tmpf = new Float32Array(tmp);
let tmpu8 = new Uint8Array(tmp);
this.getUint32 = function (i) {
return (this.u8[i + 3] << 24) | (this.u8[i + 2] << 16) | (this.u8[i + 1] << 8) | this.u8[i];
};
this.getUint16 = function (i) {
return (this.u8[i + 1] << 8) | this.u8[i];
};
this.getFloat32 = function (i) {
tmpu8[0] = this.u8[i + 0];
tmpu8[1] = this.u8[i + 1];
tmpu8[2] = this.u8[i + 2];
tmpu8[3] = this.u8[i + 3];
return tmpf[0];
};
this.getUint8 = function (i) {
return this.u8[i];
};
}
Potree = {};
onmessage = function (event) {
performance.mark("binary-decoder-start");
let buffer = event.data.buffer;
let pointAttributes = event.data.pointAttributes;
let numPoints = buffer.byteLength / pointAttributes.byteSize;
let cv = new CustomView(buffer);
let version = new Potree.Version(event.data.version);
let nodeOffset = event.data.offset;
let scale = event.data.scale;
let spacing = event.data.spacing;
let hasChildren = event.data.hasChildren;
let name = event.data.name;
let tightBoxMin = [ Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY ];
let tightBoxMax = [ Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY ];
let mean = [0, 0, 0];
let attributeBuffers = {};
let inOffset = 0;
for (let pointAttribute of pointAttributes.attributes) {
if (pointAttribute.name === Potree.PointAttribute.POSITION_CARTESIAN.name) {
let buff = new ArrayBuffer(numPoints * 4 * 3);
let positions = new Float32Array(buff);
for (let j = 0; j < numPoints; j++) {
let x, y, z;
if (version.newerThan('1.3')) {
x = (cv.getUint32(inOffset + j * pointAttributes.byteSize + 0, true) * scale);
y = (cv.getUint32(inOffset + j * pointAttributes.byteSize + 4, true) * scale);
z = (cv.getUint32(inOffset + j * pointAttributes.byteSize + 8, true) * scale);
} else {
x = cv.getFloat32(j * pointAttributes.byteSize + 0, true) + nodeOffset[0];
y = cv.getFloat32(j * pointAttributes.byteSize + 4, true) + nodeOffset[1];
z = cv.getFloat32(j * pointAttributes.byteSize + 8, true) + nodeOffset[2];
}
positions[3 * j + 0] = x;
positions[3 * j + 1] = y;
positions[3 * j + 2] = z;
mean[0] += x / numPoints;
mean[1] += y / numPoints;
mean[2] += z / numPoints;
tightBoxMin[0] = Math.min(tightBoxMin[0], x);
tightBoxMin[1] = Math.min(tightBoxMin[1], y);
tightBoxMin[2] = Math.min(tightBoxMin[2], z);
tightBoxMax[0] = Math.max(tightBoxMax[0], x);
tightBoxMax[1] = Math.max(tightBoxMax[1], y);
tightBoxMax[2] = Math.max(tightBoxMax[2], z);
}
attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute };
} else if (pointAttribute.name === Potree.PointAttribute.COLOR_PACKED.name) {
let buff = new ArrayBuffer(numPoints * 4);
let colors = new Uint8Array(buff);
for (let j = 0; j < numPoints; j++) {
colors[4 * j + 0] = cv.getUint8(inOffset + j * pointAttributes.byteSize + 0);
colors[4 * j + 1] = cv.getUint8(inOffset + j * pointAttributes.byteSize + 1);
colors[4 * j + 2] = cv.getUint8(inOffset + j * pointAttributes.byteSize + 2);
}
attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute };
} else if (pointAttribute.name === Potree.PointAttribute.INTENSITY.name) {
let buff = new ArrayBuffer(numPoints * 4);
let intensities = new Float32Array(buff);
for (let j = 0; j < numPoints; j++) {
let intensity = cv.getUint16(inOffset + j * pointAttributes.byteSize, true);
intensities[j] = intensity;
}
attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute };
} else if (pointAttribute.name === Potree.PointAttribute.CLASSIFICATION.name) {
let buff = new ArrayBuffer(numPoints);
let classifications = new Uint8Array(buff);
for (let j = 0; j < numPoints; j++) {
let classification = cv.getUint8(inOffset + j * pointAttributes.byteSize);
classifications[j] = classification;
}
attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute };
} else if (pointAttribute.name === Potree.PointAttribute.NORMAL_SPHEREMAPPED.name) {
let buff = new ArrayBuffer(numPoints * 4 * 3);
let normals = new Float32Array(buff);
for (let j = 0; j < numPoints; j++) {
let bx = cv.getUint8(inOffset + j * pointAttributes.byteSize + 0);
let by = cv.getUint8(inOffset + j * pointAttributes.byteSize + 1);
let ex = bx / 255;
let ey = by / 255;
let nx = ex * 2 - 1;
let ny = ey * 2 - 1;
let nz = 1;
let nw = -1;
let l = (nx * (-nx)) + (ny * (-ny)) + (nz * (-nw));
nz = l;
nx = nx * Math.sqrt(l);
ny = ny * Math.sqrt(l);
nx = nx * 2;
ny = ny * 2;
nz = nz * 2 - 1;
normals[3 * j + 0] = nx;
normals[3 * j + 1] = ny;
normals[3 * j + 2] = nz;
}
attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute };
} else if (pointAttribute.name === Potree.PointAttribute.NORMAL_OCT16.name) {
let buff = new ArrayBuffer(numPoints * 4 * 3);
let normals = new Float32Array(buff);
for (let j = 0; j < numPoints; j++) {
let bx = cv.getUint8(inOffset + j * pointAttributes.byteSize + 0);
let by = cv.getUint8(inOffset + j * pointAttributes.byteSize + 1);
let u = (bx / 255) * 2 - 1;
let v = (by / 255) * 2 - 1;
let z = 1 - Math.abs(u) - Math.abs(v);
let x = 0;
let y = 0;
if (z >= 0) {
x = u;
y = v;
} else {
x = -(v / Math.sign(v) - 1) / Math.sign(u);
y = -(u / Math.sign(u) - 1) / Math.sign(v);
}
let length = Math.sqrt(x * x + y * y + z * z);
x = x / length;
y = y / length;
z = z / length;
normals[3 * j + 0] = x;
normals[3 * j + 1] = y;
normals[3 * j + 2] = z;
}
attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute };
} else if (pointAttribute.name === Potree.PointAttribute.NORMAL.name) {
let buff = new ArrayBuffer(numPoints * 4 * 3);
let normals = new Float32Array(buff);
for (let j = 0; j < numPoints; j++) {
let x = cv.getFloat32(inOffset + j * pointAttributes.byteSize + 0, true);
let y = cv.getFloat32(inOffset + j * pointAttributes.byteSize + 4, true);
let z = cv.getFloat32(inOffset + j * pointAttributes.byteSize + 8, true);
normals[3 * j + 0] = x;
normals[3 * j + 1] = y;
normals[3 * j + 2] = z;
}
attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute };
}
inOffset += pointAttribute.byteSize;
}
//let debugNodes = ["r026", "r0226","r02274"];
//if(debugNodes.includes(name)){
if(false){
console.log("estimate spacing!");
let sparseGrid = new Map();
let gridSize = 16;
let tightBoxSize = tightBoxMax.map( (a, i) => a - tightBoxMin[i]);
let cubeLength = Math.max(...tightBoxSize);
let cube = {
min: tightBoxMin,
max: tightBoxMin.map(v => v + cubeLength)
};
let positions = new Float32Array(attributeBuffers[Potree.PointAttribute.POSITION_CARTESIAN.name].buffer);
for(let i = 0; i < numPoints; i++){
let x = positions[3 * i + 0];
let y = positions[3 * i + 1];
let z = positions[3 * i + 2];
let ix = Math.max(0, Math.min(gridSize * (x - cube.min[0]) / cubeLength, gridSize - 1));
let iy = Math.max(0, Math.min(gridSize * (y - cube.min[1]) / cubeLength, gridSize - 1));
let iz = Math.max(0, Math.min(gridSize * (z - cube.min[2]) / cubeLength, gridSize - 1));
ix = Math.floor(ix);
iy = Math.floor(iy);
iz = Math.floor(iz);
let cellIndex = ix | (iy << 8) | (iz << 16);
if(!sparseGrid.has(cellIndex)){
sparseGrid.set(cellIndex, []);
}
sparseGrid.get(cellIndex).push(i);
}
let kNearest = (pointIndex, candidates, numNearest) => {
let x = positions[3 * pointIndex + 0];
let y = positions[3 * pointIndex + 1];
let z = positions[3 * pointIndex + 2];
let candidateDistances = [];
for(let candidateIndex of candidates){
if(candidateIndex === pointIndex){
continue;
}
let cx = positions[3 * candidateIndex + 0];
let cy = positions[3 * candidateIndex + 1];
let cz = positions[3 * candidateIndex + 2];
let squaredDistance = (cx - x) ** 2 + (cy - y) ** 2 + (cz - z) ** 2;
candidateDistances.push({candidateInde: candidateIndex, squaredDistance: squaredDistance});
}
candidateDistances.sort( (a, b) => a.squaredDistance - b.squaredDistance);
let nearest = candidateDistances.slice(0, numNearest);
return nearest;
};
let meansBuffer = new ArrayBuffer(numPoints * 4);
let means = new Float32Array(meansBuffer);
for(let [key, value] of sparseGrid){
for(let pointIndex of value){
if(value.length === 1){
means[pointIndex] = 0;
continue;
}
let [ix, iy, iz] = [(key & 255), ((key >> 8) & 255), ((key >> 16) & 255)];
//let candidates = value;
let candidates = [];
for(let i of [-1, 0, 1]){
for(let j of [-1, 0, 1]){
for(let k of [-1, 0, 1]){
let cellIndex = (ix + i) | ((iy + j) << 8) | ((iz + k) << 16);
if(sparseGrid.has(cellIndex)){
candidates.push(...sparseGrid.get(cellIndex));
}
}
}
}
let nearestNeighbors = kNearest(pointIndex, candidates, 10);
let sum = 0;
for(let neighbor of nearestNeighbors){
sum += Math.sqrt(neighbor.squaredDistance);
}
//let mean = sum / nearestNeighbors.length;
let mean = Math.sqrt(Math.max(...nearestNeighbors.map(n => n.squaredDistance)));
if(Number.isNaN(mean)){
debugger;
}
means[pointIndex] = mean;
}
}
let maxMean = Math.max(...means);
let minMean = Math.min(...means);
//let colors = new Uint8Array(attributeBuffers[Potree.PointAttribute.COLOR_PACKED.name].buffer);
//for(let i = 0; i < numPoints; i++){
// let v = means[i] / 0.05;
// colors[4 * i + 0] = 255 * v;
// colors[4 * i + 1] = 255 * v;
// colors[4 * i + 2] = 255 * v;
//}
attributeBuffers[Potree.PointAttribute.SPACING.name] = { buffer: meansBuffer, attribute: Potree.PointAttribute.SPACING };
}
{ // add indices
let buff = new ArrayBuffer(numPoints * 4);
let indices = new Uint32Array(buff);
for (let i = 0; i < numPoints; i++) {
indices[i] = i;
}
attributeBuffers[Potree.PointAttribute.INDICES.name] = { buffer: buff, attribute: Potree.PointAttribute.INDICES };
}
performance.mark("binary-decoder-end");
//{ // print timings
// //performance.measure("spacing", "spacing-start", "spacing-end");
// performance.measure("binary-decoder", "binary-decoder-start", "binary-decoder-end");
// let measure = performance.getEntriesByType("measure")[0];
// let dpp = 1000 * measure.duration / numPoints;
// let debugMessage = `${measure.duration.toFixed(3)} ms, ${numPoints} points, ${dpp.toFixed(3)} µs / point`;
// console.log(debugMessage);
//}
performance.clearMarks();
performance.clearMeasures();
let message = {
buffer: buffer,
mean: mean,
attributeBuffers: attributeBuffers,
tightBoundingBox: { min: tightBoxMin, max: tightBoxMax },
//estimatedSpacing: estimatedSpacing,
};
let transferables = [];
for (let property in message.attributeBuffers) {
transferables.push(message.attributeBuffers[property].buffer);
}
transferables.push(buffer);
postMessage(message, transferables);
};
Potree.Version = function (version) {
this.version = version;
let vmLength = (version.indexOf('.') === -1) ? version.length : version.indexOf('.');
this.versionMajor = parseInt(version.substr(0, vmLength));
this.versionMinor = parseInt(version.substr(vmLength + 1));
if (this.versionMinor.length === 0) {
this.versionMinor = 0;
}
};
Potree.Version.prototype.newerThan = function (version) {
let v = new Potree.Version(version);
if (this.versionMajor > v.versionMajor) {
return true;
} else if (this.versionMajor === v.versionMajor && this.versionMinor > v.versionMinor) {
return true;
} else {
return false;
}
};
Potree.Version.prototype.equalOrHigher = function (version) {
let v = new Potree.Version(version);
if (this.versionMajor > v.versionMajor) {
return true;
} else if (this.versionMajor === v.versionMajor && this.versionMinor >= v.versionMinor) {
return true;
} else {
return false;
}
};
Potree.Version.prototype.upTo = function (version) {
return !this.newerThan(version);
};
Potree.PointAttributeNames = {};
Potree.PointAttributeNames.POSITION_CARTESIAN = 0; // float x, y, z;
Potree.PointAttributeNames.COLOR_PACKED = 1; // byte r, g, b, a; I = [0,1]
Potree.PointAttributeNames.COLOR_FLOATS_1 = 2; // float r, g, b; I = [0,1]
Potree.PointAttributeNames.COLOR_FLOATS_255 = 3; // float r, g, b; I = [0,255]
Potree.PointAttributeNames.NORMAL_FLOATS = 4; // float x, y, z;
Potree.PointAttributeNames.FILLER = 5;
Potree.PointAttributeNames.INTENSITY = 6;
Potree.PointAttributeNames.CLASSIFICATION = 7;
Potree.PointAttributeNames.NORMAL_SPHEREMAPPED = 8;
Potree.PointAttributeNames.NORMAL_OCT16 = 9;
Potree.PointAttributeNames.NORMAL = 10;
Potree.PointAttributeNames.RETURN_NUMBER = 11;
Potree.PointAttributeNames.NUMBER_OF_RETURNS = 12;
Potree.PointAttributeNames.SOURCE_ID = 13;
Potree.PointAttributeNames.INDICES = 14;
Potree.PointAttributeNames.SPACING = 15;
/**
* Some types of possible point attribute data formats
*
* @class
*/
Potree.PointAttributeTypes = {
DATA_TYPE_DOUBLE: {ordinal: 0, size: 8},
DATA_TYPE_FLOAT: {ordinal: 1, size: 4},
DATA_TYPE_INT8: {ordinal: 2, size: 1},
DATA_TYPE_UINT8: {ordinal: 3, size: 1},
DATA_TYPE_INT16: {ordinal: 4, size: 2},
DATA_TYPE_UINT16: {ordinal: 5, size: 2},
DATA_TYPE_INT32: {ordinal: 6, size: 4},
DATA_TYPE_UINT32: {ordinal: 7, size: 4},
DATA_TYPE_INT64: {ordinal: 8, size: 8},
DATA_TYPE_UINT64: {ordinal: 9, size: 8}
};
let i = 0;
for (let obj in Potree.PointAttributeTypes) {
Potree.PointAttributeTypes[i] = Potree.PointAttributeTypes[obj];
i++;
}
/**
* A single point attribute such as color/normal/.. and its data format/number of elements/...
*
* @class
* @param name
* @param type
* @param size
* @returns
*/
Potree.PointAttribute = function (name, type, numElements) {
this.name = name;
this.type = type;
this.numElements = numElements;
this.byteSize = this.numElements * this.type.size;
};
Potree.PointAttribute.POSITION_CARTESIAN = new Potree.PointAttribute(
Potree.PointAttributeNames.POSITION_CARTESIAN,
Potree.PointAttributeTypes.DATA_TYPE_FLOAT, 3);
Potree.PointAttribute.RGBA_PACKED = new Potree.PointAttribute(
Potree.PointAttributeNames.COLOR_PACKED,
Potree.PointAttributeTypes.DATA_TYPE_INT8, 4);
Potree.PointAttribute.COLOR_PACKED = Potree.PointAttribute.RGBA_PACKED;
Potree.PointAttribute.RGB_PACKED = new Potree.PointAttribute(
Potree.PointAttributeNames.COLOR_PACKED,
Potree.PointAttributeTypes.DATA_TYPE_INT8, 3);
Potree.PointAttribute.NORMAL_FLOATS = new Potree.PointAttribute(
Potree.PointAttributeNames.NORMAL_FLOATS,
Potree.PointAttributeTypes.DATA_TYPE_FLOAT, 3);
Potree.PointAttribute.FILLER_1B = new Potree.PointAttribute(
Potree.PointAttributeNames.FILLER,
Potree.PointAttributeTypes.DATA_TYPE_UINT8, 1);
Potree.PointAttribute.INTENSITY = new Potree.PointAttribute(
Potree.PointAttributeNames.INTENSITY,
Potree.PointAttributeTypes.DATA_TYPE_UINT16, 1);
Potree.PointAttribute.CLASSIFICATION = new Potree.PointAttribute(
Potree.PointAttributeNames.CLASSIFICATION,
Potree.PointAttributeTypes.DATA_TYPE_UINT8, 1);
Potree.PointAttribute.NORMAL_SPHEREMAPPED = new Potree.PointAttribute(
Potree.PointAttributeNames.NORMAL_SPHEREMAPPED,
Potree.PointAttributeTypes.DATA_TYPE_UINT8, 2);
Potree.PointAttribute.NORMAL_OCT16 = new Potree.PointAttribute(
Potree.PointAttributeNames.NORMAL_OCT16,
Potree.PointAttributeTypes.DATA_TYPE_UINT8, 2);
Potree.PointAttribute.NORMAL = new Potree.PointAttribute(
Potree.PointAttributeNames.NORMAL,
Potree.PointAttributeTypes.DATA_TYPE_FLOAT, 3);
Potree.PointAttribute.RETURN_NUMBER = new Potree.PointAttribute(
Potree.PointAttributeNames.RETURN_NUMBER,
Potree.PointAttributeTypes.DATA_TYPE_UINT8, 1);
Potree.PointAttribute.NUMBER_OF_RETURNS = new Potree.PointAttribute(
Potree.PointAttributeNames.NUMBER_OF_RETURNS,
Potree.PointAttributeTypes.DATA_TYPE_UINT8, 1);
Potree.PointAttribute.SOURCE_ID = new Potree.PointAttribute(
Potree.PointAttributeNames.SOURCE_ID,
Potree.PointAttributeTypes.DATA_TYPE_UINT8, 1);
Potree.PointAttribute.INDICES = new Potree.PointAttribute(
Potree.PointAttributeNames.INDICES,
Potree.PointAttributeTypes.DATA_TYPE_UINT32, 1);
Potree.PointAttribute.SPACING = new Potree.PointAttribute(
Potree.PointAttributeNames.SPACING,
Potree.PointAttributeTypes.DATA_TYPE_FLOAT, 1);
/**
* Ordered list of PointAttributes used to identify how points are aligned in a buffer.
*
* @class
*
*/
Potree.PointAttributes = function (pointAttributes) {
this.attributes = [];
this.byteSize = 0;
this.size = 0;
if (pointAttributes != null) {
for (let i = 0; i < pointAttributes.length; i++) {
let pointAttributeName = pointAttributes[i];
let pointAttribute = Potree.PointAttribute[pointAttributeName];
this.attributes.push(pointAttribute);
this.byteSize += pointAttribute.byteSize;
this.size++;
}
}
};
Potree.PointAttributes.prototype.add = function (pointAttribute) {
this.attributes.push(pointAttribute);
this.byteSize += pointAttribute.byteSize;
this.size++;
};
Potree.PointAttributes.prototype.hasColors = function () {
for (let name in this.attributes) {
let pointAttribute = this.attributes[name];
if (pointAttribute.name === Potree.PointAttributeNames.COLOR_PACKED) {
return true;
}
}
return false;
};
Potree.PointAttributes.prototype.hasNormals = function () {
for (let name in this.attributes) {
let pointAttribute = this.attributes[name];
if (
pointAttribute === Potree.PointAttribute.NORMAL_SPHEREMAPPED ||
pointAttribute === Potree.PointAttribute.NORMAL_FLOATS ||
pointAttribute === Potree.PointAttribute.NORMAL ||
pointAttribute === Potree.PointAttribute.NORMAL_OCT16) {
return true;
}
}
return false;
};
Potree.InterleavedBufferAttribute = class InterleavedBufferAttribute{
constructor(name, bytes, numElements, type, normalized){
this.name = name;
this.bytes = bytes;
this.numElements = numElements;
this.normalized = normalized;
this.type = type; // gl type without prefix, e.g. "FLOAT", "UNSIGNED_INT"
}
};
Potree.InterleavedBuffer = class InterleavedBuffer{
constructor(data, attributes, numElements){
this.data = data;
this.attributes = attributes;
this.stride = attributes.reduce( (a, att) => a + att.bytes, 0);
this.stride = Math.ceil(this.stride / 4) * 4;
this.numElements = numElements;
}
offset(name){
let offset = 0;
for(let att of this.attributes){
if(att.name === name){
return offset;
}
offset += att.bytes;
}
return null;
}
};
Potree.toInterleavedBufferAttribute = function toInterleavedBufferAttribute(pointAttribute){
let att = null;
if (pointAttribute.name === Potree.PointAttribute.POSITION_CARTESIAN.name) {
att = new Potree.InterleavedBufferAttribute("position", 12, 3, "FLOAT", false);
} else if (pointAttribute.name === Potree.PointAttribute.COLOR_PACKED.name) {
att = new Potree.InterleavedBufferAttribute("color", 4, 4, "UNSIGNED_BYTE", true);
} else if (pointAttribute.name === Potree.PointAttribute.INTENSITY.name) {
att = new Potree.InterleavedBufferAttribute("intensity", 4, 1, "FLOAT", false);
} else if (pointAttribute.name === Potree.PointAttribute.CLASSIFICATION.name) {
att = new Potree.InterleavedBufferAttribute("classification", 4, 1, "FLOAT", false);
} else if (pointAttribute.name === Potree.PointAttribute.RETURN_NUMBER.name) {
att = new Potree.InterleavedBufferAttribute("returnNumber", 4, 1, "FLOAT", false);
} else if (pointAttribute.name === Potree.PointAttribute.NUMBER_OF_RETURNS.name) {
att = new Potree.InterleavedBufferAttribute("numberOfReturns", 4, 1, "FLOAT", false);
} else if (pointAttribute.name === Potree.PointAttribute.SOURCE_ID.name) {
att = new Potree.InterleavedBufferAttribute("pointSourceID", 4, 1, "FLOAT", false);
} else if (pointAttribute.name === Potree.PointAttribute.NORMAL_SPHEREMAPPED.name) {
att = new Potree.InterleavedBufferAttribute("normal", 12, 3, "FLOAT", false);
} else if (pointAttribute.name === Potree.PointAttribute.NORMAL_OCT16.name) {
att = new Potree.InterleavedBufferAttribute("normal", 12, 3, "FLOAT", false);
} else if (pointAttribute.name === Potree.PointAttribute.NORMAL.name) {
att = new Potree.InterleavedBufferAttribute("normal", 12, 3, "FLOAT", false);
}
return att;
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,368 @@
// let pointFormatReaders = {
// 0: function(dv) {
// return {
// "position": [ dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
// "intensity": dv.getUint16(12, true),
// "classification": dv.getUint8(16, true)
// };
// },
// 1: function(dv) {
// return {
// "position": [ dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
// "intensity": dv.getUint16(12, true),
// "classification": dv.getUint8(16, true)
// };
// },
// 2: function(dv) {
// return {
// "position": [ dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
// "intensity": dv.getUint16(12, true),
// "classification": dv.getUint8(16, true),
// "color": [dv.getUint16(20, true), dv.getUint16(22, true), dv.getUint16(24, true)]
// };
// },
// 3: function(dv) {
// return {
// "position": [ dv.getInt32(0, true), dv.getInt32(4, true), dv.getInt32(8, true)],
// "intensity": dv.getUint16(12, true),
// "classification": dv.getUint8(16, true),
// "color": [dv.getUint16(28, true), dv.getUint16(30, true), dv.getUint16(32, true)]
// };
// }
// };
//
//
function readUsingTempArrays(event) {
performance.mark("laslaz-start");
let buffer = event.data.buffer;
let numPoints = event.data.numPoints;
let sourcePointSize = event.data.pointSize;
let pointFormatID = event.data.pointFormatID;
let scale = event.data.scale;
let offset = event.data.offset;
let temp = new ArrayBuffer(4);
let tempUint8 = new Uint8Array(temp);
let tempUint16 = new Uint16Array(temp);
let tempInt32 = new Int32Array(temp);
let sourceUint8 = new Uint8Array(buffer);
let sourceView = new DataView(buffer);
let targetPointSize = 20;
let targetBuffer = new ArrayBuffer(numPoints * targetPointSize);
let targetView = new DataView(targetBuffer);
let tightBoundingBox = {
min: [ Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY ],
max: [ Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY ]
};
let mean = [0, 0, 0];
let pBuff = new ArrayBuffer(numPoints * 3 * 4);
let cBuff = new ArrayBuffer(numPoints * 4);
let iBuff = new ArrayBuffer(numPoints * 4);
let clBuff = new ArrayBuffer(numPoints);
let rnBuff = new ArrayBuffer(numPoints);
let nrBuff = new ArrayBuffer(numPoints);
let psBuff = new ArrayBuffer(numPoints * 2);
let positions = new Float32Array(pBuff);
let colors = new Uint8Array(cBuff);
let intensities = new Float32Array(iBuff);
let classifications = new Uint8Array(clBuff);
let returnNumbers = new Uint8Array(rnBuff);
let numberOfReturns = new Uint8Array(nrBuff);
let pointSourceIDs = new Uint16Array(psBuff);
for (let i = 0; i < numPoints; i++) {
// POSITION
tempUint8[0] = sourceUint8[i * sourcePointSize + 0];
tempUint8[1] = sourceUint8[i * sourcePointSize + 1];
tempUint8[2] = sourceUint8[i * sourcePointSize + 2];
tempUint8[3] = sourceUint8[i * sourcePointSize + 3];
let x = tempInt32[0];
tempUint8[0] = sourceUint8[i * sourcePointSize + 4];
tempUint8[1] = sourceUint8[i * sourcePointSize + 5];
tempUint8[2] = sourceUint8[i * sourcePointSize + 6];
tempUint8[3] = sourceUint8[i * sourcePointSize + 7];
let y = tempInt32[0];
tempUint8[0] = sourceUint8[i * sourcePointSize + 8];
tempUint8[1] = sourceUint8[i * sourcePointSize + 9];
tempUint8[2] = sourceUint8[i * sourcePointSize + 10];
tempUint8[3] = sourceUint8[i * sourcePointSize + 11];
let z = tempInt32[0];
x = x * scale[0] + offset[0] - event.data.mins[0];
y = y * scale[1] + offset[1] - event.data.mins[1];
z = z * scale[2] + offset[2] - event.data.mins[2];
positions[3 * i + 0] = x;
positions[3 * i + 1] = y;
positions[3 * i + 2] = z;
mean[0] += x / numPoints;
mean[1] += y / numPoints;
mean[2] += z / numPoints;
tightBoundingBox.min[0] = Math.min(tightBoundingBox.min[0], x);
tightBoundingBox.min[1] = Math.min(tightBoundingBox.min[1], y);
tightBoundingBox.min[2] = Math.min(tightBoundingBox.min[2], z);
tightBoundingBox.max[0] = Math.max(tightBoundingBox.max[0], x);
tightBoundingBox.max[1] = Math.max(tightBoundingBox.max[1], y);
tightBoundingBox.max[2] = Math.max(tightBoundingBox.max[2], z);
// INTENSITY
tempUint8[0] = sourceUint8[i * sourcePointSize + 12];
tempUint8[1] = sourceUint8[i * sourcePointSize + 13];
let intensity = tempUint16[0];
intensities[i] = intensity;
// RETURN NUMBER, stored in the first 3 bits - 00000111
let returnNumber = sourceUint8[i * sourcePointSize + 14] & 0b111;
returnNumbers[i] = returnNumber;
// NUMBER OF RETURNS, stored in 00111000
numberOfReturns[i] = (sourceUint8[i * pointSize + 14] & 0b111000) >> 3;
debugger;
// CLASSIFICATION
let classification = sourceUint8[i * sourcePointSize + 15];
classifications[i] = classification;
// POINT SOURCE ID
tempUint8[0] = sourceUint8[i * sourcePointSize + 18];
tempUint8[1] = sourceUint8[i * sourcePointSize + 19];
let pointSourceID = tempUint16[0];
pointSourceIDs[i] = pointSourceID;
// COLOR, if available
if (pointFormatID === 2) {
tempUint8[0] = sourceUint8[i * sourcePointSize + 20];
tempUint8[1] = sourceUint8[i * sourcePointSize + 21];
let r = tempUint16[0];
tempUint8[0] = sourceUint8[i * sourcePointSize + 22];
tempUint8[1] = sourceUint8[i * sourcePointSize + 23];
let g = tempUint16[0];
tempUint8[0] = sourceUint8[i * sourcePointSize + 24];
tempUint8[1] = sourceUint8[i * sourcePointSize + 25];
let b = tempUint16[0];
r = r / 256;
g = g / 256;
b = b / 256;
colors[4 * i + 0] = r;
colors[4 * i + 1] = g;
colors[4 * i + 2] = b;
}
}
let indices = new ArrayBuffer(numPoints * 4);
let iIndices = new Uint32Array(indices);
for (let i = 0; i < numPoints; i++) {
iIndices[i] = i;
}
performance.mark("laslaz-end");
performance.measure("laslaz", "laslaz-start", "laslaz-end");
let measure = performance.getEntriesByType("measure")[0];
let dpp = 1000 * measure.duration / numPoints;
let debugMessage = `${measure.duration.toFixed(3)} ms, ${numPoints} points, ${dpp.toFixed(3)} micros / point`;
console.log(debugMessage);
performance.clearMarks();
performance.clearMeasures();
let message = {
mean: mean,
position: pBuff,
color: cBuff,
intensity: iBuff,
classification: clBuff,
returnNumber: rnBuff,
numberOfReturns: nrBuff,
pointSourceID: psBuff,
tightBoundingBox: tightBoundingBox,
indices: indices
};
let transferables = [
message.position,
message.color,
message.intensity,
message.classification,
message.returnNumber,
message.numberOfReturns,
message.pointSourceID,
message.indices];
debugger;
postMessage(message, transferables);
};
function readUsingDataView(event) {
performance.mark("laslaz-start");
let buffer = event.data.buffer;
let numPoints = event.data.numPoints;
let sourcePointSize = event.data.pointSize;
let pointFormatID = event.data.pointFormatID;
let scale = event.data.scale;
let offset = event.data.offset;
let sourceUint8 = new Uint8Array(buffer);
let sourceView = new DataView(buffer);
let targetPointSize = 40;
let targetBuffer = new ArrayBuffer(numPoints * targetPointSize);
let targetView = new DataView(targetBuffer);
let tightBoundingBox = {
min: [ Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY ],
max: [ Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY ]
};
let mean = [0, 0, 0];
let pBuff = new ArrayBuffer(numPoints * 3 * 4);
let cBuff = new ArrayBuffer(numPoints * 4);
let iBuff = new ArrayBuffer(numPoints * 4);
let clBuff = new ArrayBuffer(numPoints);
let rnBuff = new ArrayBuffer(numPoints);
let nrBuff = new ArrayBuffer(numPoints);
let psBuff = new ArrayBuffer(numPoints * 2);
let positions = new Float32Array(pBuff);
let colors = new Uint8Array(cBuff);
let intensities = new Float32Array(iBuff);
let classifications = new Uint8Array(clBuff);
let returnNumbers = new Uint8Array(rnBuff);
let numberOfReturns = new Uint8Array(nrBuff);
let pointSourceIDs = new Uint16Array(psBuff);
for (let i = 0; i < numPoints; i++) {
// POSITION
let ux = sourceView.getInt32(i * sourcePointSize + 0, true);
let uy = sourceView.getInt32(i * sourcePointSize + 4, true);
let uz = sourceView.getInt32(i * sourcePointSize + 8, true);
x = ux * scale[0] + offset[0] - event.data.mins[0];
y = uy * scale[1] + offset[1] - event.data.mins[1];
z = uz * scale[2] + offset[2] - event.data.mins[2];
//x = ux * scale[0];
//y = uy * scale[1];
//z = uz * scale[2];
positions[3 * i + 0] = x;
positions[3 * i + 1] = y;
positions[3 * i + 2] = z;
mean[0] += x / numPoints;
mean[1] += y / numPoints;
mean[2] += z / numPoints;
tightBoundingBox.min[0] = Math.min(tightBoundingBox.min[0], x);
tightBoundingBox.min[1] = Math.min(tightBoundingBox.min[1], y);
tightBoundingBox.min[2] = Math.min(tightBoundingBox.min[2], z);
tightBoundingBox.max[0] = Math.max(tightBoundingBox.max[0], x);
tightBoundingBox.max[1] = Math.max(tightBoundingBox.max[1], y);
tightBoundingBox.max[2] = Math.max(tightBoundingBox.max[2], z);
// INTENSITY
let intensity = sourceView.getUint16(i * sourcePointSize + 12, true);
intensities[i] = intensity;
// RETURN NUMBER, stored in the first 3 bits - 00000111
// number of returns stored in next 3 bits - 00111000
let returnNumberAndNumberOfReturns = sourceView.getUint8(i * sourcePointSize + 14, true);
let returnNumber = returnNumberAndNumberOfReturns & 0b0111;
let numberOfReturn = (returnNumberAndNumberOfReturns & 0b00111000) >> 3;
returnNumbers[i] = returnNumber;
numberOfReturns[i] = numberOfReturn;
// CLASSIFICATION
let classification = sourceView.getUint8(i * sourcePointSize + 15, true);
classifications[i] = classification;
// POINT SOURCE ID
let pointSourceID = sourceView.getUint16(i * sourcePointSize + 18, true);
pointSourceIDs[i] = pointSourceID;
// COLOR, if available
if (pointFormatID === 2) {
let r = sourceView.getUint16(i * sourcePointSize + 20, true) / 256;
let g = sourceView.getUint16(i * sourcePointSize + 22, true) / 256;
let b = sourceView.getUint16(i * sourcePointSize + 24, true) / 256;
colors[4 * i + 0] = r;
colors[4 * i + 1] = g;
colors[4 * i + 2] = b;
colors[4 * i + 3] = 255;
}
}
let indices = new ArrayBuffer(numPoints * 4);
let iIndices = new Uint32Array(indices);
for (let i = 0; i < numPoints; i++) {
iIndices[i] = i;
}
performance.mark("laslaz-end");
//{ // print timings
// performance.measure("laslaz", "laslaz-start", "laslaz-end");
// let measure = performance.getEntriesByType("measure")[0];
// let dpp = 1000 * measure.duration / numPoints;
// let debugMessage = `${measure.duration.toFixed(3)} ms, ${numPoints} points, ${dpp.toFixed(3)} µs / point`;
// console.log(debugMessage);
//}
performance.clearMarks();
performance.clearMeasures();
let message = {
mean: mean,
position: pBuff,
color: cBuff,
intensity: iBuff,
classification: clBuff,
returnNumber: rnBuff,
numberOfReturns: nrBuff,
pointSourceID: psBuff,
tightBoundingBox: tightBoundingBox,
indices: indices
};
let transferables = [
message.position,
message.color,
message.intensity,
message.classification,
message.returnNumber,
message.numberOfReturns,
message.pointSourceID,
message.indices];
postMessage(message, transferables);
};
onmessage = readUsingDataView;
//onmessage = readUsingTempArrays;

File diff suppressed because one or more lines are too long