|
@@ -3,317 +3,284 @@
|
|
|
*
|
|
|
* @class
|
|
|
*/
|
|
|
-const PointAttributeTypes = {
|
|
|
- DATA_TYPE_DOUBLE: {ordinal: 0, name: "double", size: 8},
|
|
|
- DATA_TYPE_FLOAT: {ordinal: 1, name: "float", size: 4},
|
|
|
- DATA_TYPE_INT8: {ordinal: 2, name: "int8", size: 1},
|
|
|
- DATA_TYPE_UINT8: {ordinal: 3, name: "uint8", size: 1},
|
|
|
- DATA_TYPE_INT16: {ordinal: 4, name: "int16", size: 2},
|
|
|
- DATA_TYPE_UINT16: {ordinal: 5, name: "uint16", size: 2},
|
|
|
- DATA_TYPE_INT32: {ordinal: 6, name: "int32", size: 4},
|
|
|
- DATA_TYPE_UINT32: {ordinal: 7, name: "uint32", size: 4},
|
|
|
- DATA_TYPE_INT64: {ordinal: 8, name: "int64", size: 8},
|
|
|
- DATA_TYPE_UINT64: {ordinal: 9, name: "uint64", size: 8}
|
|
|
+var PointAttributeTypes = {
|
|
|
+ DATA_TYPE_DOUBLE: {
|
|
|
+ ordinal: 0,
|
|
|
+ name: "double",
|
|
|
+ size: 8
|
|
|
+ },
|
|
|
+ DATA_TYPE_FLOAT: {
|
|
|
+ ordinal: 1,
|
|
|
+ name: "float",
|
|
|
+ size: 4
|
|
|
+ },
|
|
|
+ DATA_TYPE_INT8: {
|
|
|
+ ordinal: 2,
|
|
|
+ name: "int8",
|
|
|
+ size: 1
|
|
|
+ },
|
|
|
+ DATA_TYPE_UINT8: {
|
|
|
+ ordinal: 3,
|
|
|
+ name: "uint8",
|
|
|
+ size: 1
|
|
|
+ },
|
|
|
+ DATA_TYPE_INT16: {
|
|
|
+ ordinal: 4,
|
|
|
+ name: "int16",
|
|
|
+ size: 2
|
|
|
+ },
|
|
|
+ DATA_TYPE_UINT16: {
|
|
|
+ ordinal: 5,
|
|
|
+ name: "uint16",
|
|
|
+ size: 2
|
|
|
+ },
|
|
|
+ DATA_TYPE_INT32: {
|
|
|
+ ordinal: 6,
|
|
|
+ name: "int32",
|
|
|
+ size: 4
|
|
|
+ },
|
|
|
+ DATA_TYPE_UINT32: {
|
|
|
+ ordinal: 7,
|
|
|
+ name: "uint32",
|
|
|
+ size: 4
|
|
|
+ },
|
|
|
+ DATA_TYPE_INT64: {
|
|
|
+ ordinal: 8,
|
|
|
+ name: "int64",
|
|
|
+ size: 8
|
|
|
+ },
|
|
|
+ DATA_TYPE_UINT64: {
|
|
|
+ ordinal: 9,
|
|
|
+ name: "uint64",
|
|
|
+ size: 8
|
|
|
+ }
|
|
|
};
|
|
|
-
|
|
|
-let i = 0;
|
|
|
-for (let obj in PointAttributeTypes) {
|
|
|
- PointAttributeTypes[i] = PointAttributeTypes[obj];
|
|
|
- i++;
|
|
|
+var i = 0;
|
|
|
+for (var obj in PointAttributeTypes) {
|
|
|
+ PointAttributeTypes[i] = PointAttributeTypes[obj];
|
|
|
+ i++;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
-class PointAttribute{
|
|
|
-
|
|
|
- constructor(name, type, numElements){
|
|
|
- this.name = name;
|
|
|
- this.type = type;
|
|
|
- this.numElements = numElements;
|
|
|
- this.byteSize = this.numElements * this.type.size;
|
|
|
- this.description = "";
|
|
|
- this.range = [Infinity, -Infinity];
|
|
|
- }
|
|
|
-
|
|
|
-}//add
|
|
|
-const replacements = {
|
|
|
- "COLOR_PACKED": "rgba",
|
|
|
- "RGBA": "rgba",
|
|
|
- "INTENSITY": "intensity",
|
|
|
- "CLASSIFICATION": "classification",
|
|
|
- "GPS_TIME": "gps-time",
|
|
|
-};
|
|
|
-const replaceOldNames = (old) => {
|
|
|
- if(replacements[old]){
|
|
|
- return replacements[old];
|
|
|
- }else {
|
|
|
- return old;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-PointAttribute.POSITION_CARTESIAN = new PointAttribute(
|
|
|
- "POSITION_CARTESIAN", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
|
|
|
-
|
|
|
-PointAttribute.RGBA_PACKED = new PointAttribute(
|
|
|
- replaceOldNames("COLOR_PACKED"), PointAttributeTypes.DATA_TYPE_INT8, 4);
|
|
|
-
|
|
|
+class PointAttribute {
|
|
|
+ constructor(name, type, numElements) {
|
|
|
+ this.name = name;
|
|
|
+ this.type = type;
|
|
|
+ this.numElements = numElements;
|
|
|
+ this.byteSize = this.numElements * this.type.size;
|
|
|
+ this.description = "";
|
|
|
+ this.range = [Infinity, -Infinity];
|
|
|
+ }
|
|
|
+}
|
|
|
+PointAttribute.POSITION_CARTESIAN = new PointAttribute("POSITION_CARTESIAN", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
|
|
|
+PointAttribute.RGBA_PACKED = new PointAttribute("COLOR_PACKED", PointAttributeTypes.DATA_TYPE_INT8, 4);
|
|
|
PointAttribute.COLOR_PACKED = PointAttribute.RGBA_PACKED;
|
|
|
-
|
|
|
-PointAttribute.RGB_PACKED = new PointAttribute(
|
|
|
- "COLOR_PACKED", PointAttributeTypes.DATA_TYPE_INT8, 3);
|
|
|
-
|
|
|
-PointAttribute.NORMAL_FLOATS = new PointAttribute(
|
|
|
- "NORMAL_FLOATS", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
|
|
|
-
|
|
|
-PointAttribute.INTENSITY = new PointAttribute(
|
|
|
- replaceOldNames("INTENSITY"), PointAttributeTypes.DATA_TYPE_UINT16, 1);
|
|
|
-
|
|
|
-PointAttribute.CLASSIFICATION = new PointAttribute(
|
|
|
- replaceOldNames("CLASSIFICATION"), PointAttributeTypes.DATA_TYPE_UINT8, 1);
|
|
|
-
|
|
|
-PointAttribute.NORMAL_SPHEREMAPPED = new PointAttribute(
|
|
|
- "NORMAL_SPHEREMAPPED", PointAttributeTypes.DATA_TYPE_UINT8, 2);
|
|
|
-
|
|
|
-PointAttribute.NORMAL_OCT16 = new PointAttribute(
|
|
|
- "NORMAL_OCT16", PointAttributeTypes.DATA_TYPE_UINT8, 2);
|
|
|
-
|
|
|
-PointAttribute.NORMAL = new PointAttribute(
|
|
|
- "NORMAL", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
|
|
|
-
|
|
|
-PointAttribute.RETURN_NUMBER = new PointAttribute(
|
|
|
- "RETURN_NUMBER", PointAttributeTypes.DATA_TYPE_UINT8, 1);
|
|
|
-
|
|
|
-PointAttribute.NUMBER_OF_RETURNS = new PointAttribute(
|
|
|
- "NUMBER_OF_RETURNS", PointAttributeTypes.DATA_TYPE_UINT8, 1);
|
|
|
-
|
|
|
-PointAttribute.SOURCE_ID = new PointAttribute(
|
|
|
- "SOURCE_ID", PointAttributeTypes.DATA_TYPE_UINT16, 1);
|
|
|
-
|
|
|
-PointAttribute.INDICES = new PointAttribute(
|
|
|
- "INDICES", PointAttributeTypes.DATA_TYPE_UINT32, 1);
|
|
|
-
|
|
|
-PointAttribute.SPACING = new PointAttribute(
|
|
|
- "SPACING", PointAttributeTypes.DATA_TYPE_FLOAT, 1);
|
|
|
-
|
|
|
-PointAttribute.GPS_TIME = new PointAttribute(
|
|
|
- replaceOldNames("GPS_TIME"), PointAttributeTypes.DATA_TYPE_DOUBLE, 1);
|
|
|
-
|
|
|
-const typedArrayMapping = {
|
|
|
- "int8": Int8Array,
|
|
|
- "int16": Int16Array,
|
|
|
- "int32": Int32Array,
|
|
|
- "int64": Float64Array,
|
|
|
- "uint8": Uint8Array,
|
|
|
- "uint16": Uint16Array,
|
|
|
- "uint32": Uint32Array,
|
|
|
- "uint64": Float64Array,
|
|
|
- "float": Float32Array,
|
|
|
- "double": Float64Array,
|
|
|
+PointAttribute.RGB_PACKED = new PointAttribute("COLOR_PACKED", PointAttributeTypes.DATA_TYPE_INT8, 3);
|
|
|
+PointAttribute.NORMAL_FLOATS = new PointAttribute("NORMAL_FLOATS", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
|
|
|
+PointAttribute.INTENSITY = new PointAttribute("INTENSITY", PointAttributeTypes.DATA_TYPE_UINT16, 1);
|
|
|
+PointAttribute.CLASSIFICATION = new PointAttribute("CLASSIFICATION", PointAttributeTypes.DATA_TYPE_UINT8, 1);
|
|
|
+PointAttribute.NORMAL_SPHEREMAPPED = new PointAttribute("NORMAL_SPHEREMAPPED", PointAttributeTypes.DATA_TYPE_UINT8, 2);
|
|
|
+PointAttribute.NORMAL_OCT16 = new PointAttribute("NORMAL_OCT16", PointAttributeTypes.DATA_TYPE_UINT8, 2);
|
|
|
+PointAttribute.NORMAL = new PointAttribute("NORMAL", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
|
|
|
+PointAttribute.RETURN_NUMBER = new PointAttribute("RETURN_NUMBER", PointAttributeTypes.DATA_TYPE_UINT8, 1);
|
|
|
+PointAttribute.NUMBER_OF_RETURNS = new PointAttribute("NUMBER_OF_RETURNS", PointAttributeTypes.DATA_TYPE_UINT8, 1);
|
|
|
+PointAttribute.SOURCE_ID = new PointAttribute("SOURCE_ID", PointAttributeTypes.DATA_TYPE_UINT16, 1);
|
|
|
+PointAttribute.INDICES = new PointAttribute("INDICES", PointAttributeTypes.DATA_TYPE_UINT32, 1);
|
|
|
+PointAttribute.SPACING = new PointAttribute("SPACING", PointAttributeTypes.DATA_TYPE_FLOAT, 1);
|
|
|
+PointAttribute.GPS_TIME = new PointAttribute("GPS_TIME", PointAttributeTypes.DATA_TYPE_DOUBLE, 1);
|
|
|
+
|
|
|
+// import {Version} from "../../Version.js";
|
|
|
+var typedArrayMapping = {
|
|
|
+ "int8": Int8Array,
|
|
|
+ "int16": Int16Array,
|
|
|
+ "int32": Int32Array,
|
|
|
+ "int64": Float64Array,
|
|
|
+ "uint8": Uint8Array,
|
|
|
+ "uint16": Uint16Array,
|
|
|
+ "uint32": Uint32Array,
|
|
|
+ "uint64": Float64Array,
|
|
|
+ "float": Float32Array,
|
|
|
+ "double": Float64Array
|
|
|
};
|
|
|
-
|
|
|
Potree = {};
|
|
|
-
|
|
|
-onmessage = function (event) {
|
|
|
-
|
|
|
- let {buffer, pointAttributes, scale, name, min, max, size, offset, numPoints} = event.data;
|
|
|
-
|
|
|
- let tStart = performance.now();
|
|
|
-
|
|
|
- let view = new DataView(buffer);
|
|
|
-
|
|
|
- let attributeBuffers = {};
|
|
|
- let attributeOffset = 0;
|
|
|
-
|
|
|
- let bytesPerPoint = 0;
|
|
|
- for (let pointAttribute of pointAttributes.attributes) {
|
|
|
- bytesPerPoint += pointAttribute.byteSize;
|
|
|
- }
|
|
|
-
|
|
|
- let gridSize = 32;
|
|
|
- let grid = new Uint32Array(gridSize ** 3);
|
|
|
- let toIndex = (x, y, z) => {
|
|
|
- // let dx = gridSize * (x - min.x) / size.x;
|
|
|
- // let dy = gridSize * (y - min.y) / size.y;
|
|
|
- // let dz = gridSize * (z - min.z) / size.z;
|
|
|
-
|
|
|
- // min is already subtracted
|
|
|
- let dx = gridSize * x / size.x;
|
|
|
- let dy = gridSize * y / size.y;
|
|
|
- let dz = gridSize * z / size.z;
|
|
|
-
|
|
|
- let ix = Math.min(parseInt(dx), gridSize - 1);
|
|
|
- let iy = Math.min(parseInt(dy), gridSize - 1);
|
|
|
- let iz = Math.min(parseInt(dz), gridSize - 1);
|
|
|
-
|
|
|
- let index = ix + iy * gridSize + iz * gridSize * gridSize;
|
|
|
-
|
|
|
- return index;
|
|
|
- };
|
|
|
-
|
|
|
- let numOccupiedCells = 0;
|
|
|
- for (let pointAttribute of pointAttributes.attributes) {
|
|
|
-
|
|
|
- if(["POSITION_CARTESIAN", "position"].includes(pointAttribute.name)){
|
|
|
- let buff = new ArrayBuffer(numPoints * 4 * 3);
|
|
|
- let positions = new Float32Array(buff);
|
|
|
-
|
|
|
- for (let j = 0; j < numPoints; j++) {
|
|
|
-
|
|
|
- let pointOffset = j * bytesPerPoint;
|
|
|
-
|
|
|
- let x = (view.getInt32(pointOffset + attributeOffset + 0, true) * scale[0]) + offset[0] - min.x;
|
|
|
- let y = (view.getInt32(pointOffset + attributeOffset + 4, true) * scale[1]) + offset[1] - min.y;
|
|
|
- let z = (view.getInt32(pointOffset + attributeOffset + 8, true) * scale[2]) + offset[2] - min.z;
|
|
|
-
|
|
|
- let index = toIndex(x, y, z);
|
|
|
- let count = grid[index]++;
|
|
|
- if(count === 0){
|
|
|
- numOccupiedCells++;
|
|
|
- }
|
|
|
-
|
|
|
- positions[3 * j + 0] = x;
|
|
|
- positions[3 * j + 1] = y;
|
|
|
- positions[3 * j + 2] = z;
|
|
|
- }
|
|
|
-
|
|
|
- attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute };
|
|
|
- }else if(["RGBA", "rgba"].includes(pointAttribute.name)){
|
|
|
- let buff = new ArrayBuffer(numPoints * 4);
|
|
|
- let colors = new Uint8Array(buff);
|
|
|
-
|
|
|
- for (let j = 0; j < numPoints; j++) {
|
|
|
- let pointOffset = j * bytesPerPoint;
|
|
|
-
|
|
|
- let r = view.getUint16(pointOffset + attributeOffset + 0, true);
|
|
|
- let g = view.getUint16(pointOffset + attributeOffset + 2, true);
|
|
|
- let b = view.getUint16(pointOffset + attributeOffset + 4, true);
|
|
|
-
|
|
|
- colors[4 * j + 0] = r > 255 ? r / 256 : r;
|
|
|
- colors[4 * j + 1] = g > 255 ? g / 256 : g;
|
|
|
- colors[4 * j + 2] = b > 255 ? b / 256 : b;
|
|
|
- }
|
|
|
-
|
|
|
- attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute };
|
|
|
- }else {
|
|
|
- let buff = new ArrayBuffer(numPoints * 4);
|
|
|
- let f32 = new Float32Array(buff);
|
|
|
-
|
|
|
- let TypedArray = typedArrayMapping[pointAttribute.type.name];
|
|
|
- preciseBuffer = new TypedArray(numPoints);
|
|
|
-
|
|
|
- let [offset, scale] = [0, 1];
|
|
|
-
|
|
|
- const getterMap = {
|
|
|
- "int8": view.getInt8,
|
|
|
- "int16": view.getInt16,
|
|
|
- "int32": view.getInt32,
|
|
|
- // "int64": view.getInt64,
|
|
|
- "uint8": view.getUint8,
|
|
|
- "uint16": view.getUint16,
|
|
|
- "uint32": view.getUint32,
|
|
|
- // "uint64": view.getUint64,
|
|
|
- "float": view.getFloat32,
|
|
|
- "double": view.getFloat64,
|
|
|
- };
|
|
|
- const getter = getterMap[pointAttribute.type.name].bind(view);
|
|
|
-
|
|
|
- // compute offset and scale to pack larger types into 32 bit floats
|
|
|
- if(pointAttribute.type.size > 4){
|
|
|
- let [amin, amax] = pointAttribute.range;
|
|
|
- offset = amin;
|
|
|
- scale = 1 / (amax - amin);
|
|
|
- }
|
|
|
-
|
|
|
- for(let j = 0; j < numPoints; j++){
|
|
|
- let pointOffset = j * bytesPerPoint;
|
|
|
- let value = getter(pointOffset + attributeOffset, true);
|
|
|
-
|
|
|
- f32[j] = (value - offset) * scale;
|
|
|
- preciseBuffer[j] = value;
|
|
|
- }
|
|
|
-
|
|
|
- attributeBuffers[pointAttribute.name] = {
|
|
|
- buffer: buff,
|
|
|
- preciseBuffer: preciseBuffer,
|
|
|
- attribute: pointAttribute,
|
|
|
- offset: offset,
|
|
|
- scale: scale,
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- attributeOffset += pointAttribute.byteSize;
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- let occupancy = parseInt(numPoints / numOccupiedCells);
|
|
|
- // console.log(`${name}: #points: ${numPoints}: #occupiedCells: ${numOccupiedCells}, occupancy: ${occupancy} points/cell`);
|
|
|
-
|
|
|
- { // add indices
|
|
|
- let buff = new ArrayBuffer(numPoints * 4);
|
|
|
- let indices = new Uint32Array(buff);
|
|
|
-
|
|
|
- for (let i = 0; i < numPoints; i++) {
|
|
|
- indices[i] = i;
|
|
|
- }
|
|
|
-
|
|
|
- attributeBuffers["INDICES"] = { buffer: buff, attribute: PointAttribute.INDICES };
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- { // handle attribute vectors
|
|
|
- let vectors = pointAttributes.vectors;
|
|
|
-
|
|
|
- for(let vector of vectors){
|
|
|
-
|
|
|
- let {name, attributes} = vector;
|
|
|
- let numVectorElements = attributes.length;
|
|
|
- let buffer = new ArrayBuffer(numVectorElements * numPoints * 4);
|
|
|
- let f32 = new Float32Array(buffer);
|
|
|
-
|
|
|
- let iElement = 0;
|
|
|
- for(let sourceName of attributes){
|
|
|
- let sourceBuffer = attributeBuffers[sourceName];
|
|
|
- let {offset, scale} = sourceBuffer;
|
|
|
- let view = new DataView(sourceBuffer.buffer);
|
|
|
-
|
|
|
- const getter = view.getFloat32.bind(view);
|
|
|
-
|
|
|
- for(let j = 0; j < numPoints; j++){
|
|
|
- let value = getter(j * 4, true);
|
|
|
-
|
|
|
- f32[j * numVectorElements + iElement] = (value / scale) + offset;
|
|
|
- }
|
|
|
-
|
|
|
- iElement++;
|
|
|
- }
|
|
|
-
|
|
|
- let vecAttribute = new PointAttribute(name, PointAttributeTypes.DATA_TYPE_FLOAT, 3);
|
|
|
-
|
|
|
- attributeBuffers[name] = {
|
|
|
- buffer: buffer,
|
|
|
- attribute: vecAttribute,
|
|
|
- };
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- // let duration = performance.now() - tStart;
|
|
|
- // let pointsPerMs = numPoints / duration;
|
|
|
- // console.log(`duration: ${duration.toFixed(1)}ms, #points: ${numPoints}, points/ms: ${pointsPerMs.toFixed(1)}`);
|
|
|
-
|
|
|
- let message = {
|
|
|
- buffer: buffer,
|
|
|
- attributeBuffers: attributeBuffers,
|
|
|
- density: occupancy,
|
|
|
- };
|
|
|
-
|
|
|
- let transferables = [];
|
|
|
- for (let property in message.attributeBuffers) {
|
|
|
- transferables.push(message.attributeBuffers[property].buffer);
|
|
|
- }
|
|
|
- transferables.push(buffer);
|
|
|
-
|
|
|
- postMessage(message, transferables);
|
|
|
+onmessage = function onmessage(event) {
|
|
|
+ var {
|
|
|
+ buffer,
|
|
|
+ pointAttributes,
|
|
|
+ scale,
|
|
|
+ name,
|
|
|
+ min,
|
|
|
+ max,
|
|
|
+ size,
|
|
|
+ offset,
|
|
|
+ numPoints
|
|
|
+ } = event.data;
|
|
|
+ var tStart = performance.now();
|
|
|
+ var view = new DataView(buffer);
|
|
|
+ var attributeBuffers = {};
|
|
|
+ var attributeOffset = 0;
|
|
|
+ var bytesPerPoint = 0;
|
|
|
+ for (var pointAttribute of pointAttributes.attributes) {
|
|
|
+ bytesPerPoint += pointAttribute.byteSize;
|
|
|
+ }
|
|
|
+ var gridSize = 32;
|
|
|
+ var grid = new Uint32Array(gridSize ** 3);
|
|
|
+ var toIndex = (x, y, z) => {
|
|
|
+ // let dx = gridSize * (x - min.x) / size.x;
|
|
|
+ // let dy = gridSize * (y - min.y) / size.y;
|
|
|
+ // let dz = gridSize * (z - min.z) / size.z;
|
|
|
+
|
|
|
+ // min is already subtracted
|
|
|
+ var dx = gridSize * x / size.x;
|
|
|
+ var dy = gridSize * y / size.y;
|
|
|
+ var dz = gridSize * z / size.z;
|
|
|
+ var ix = Math.min(parseInt(dx), gridSize - 1);
|
|
|
+ var iy = Math.min(parseInt(dy), gridSize - 1);
|
|
|
+ var iz = Math.min(parseInt(dz), gridSize - 1);
|
|
|
+ var index = ix + iy * gridSize + iz * gridSize * gridSize;
|
|
|
+ return index;
|
|
|
+ };
|
|
|
+ var numOccupiedCells = 0;
|
|
|
+ for (var _pointAttribute of pointAttributes.attributes) {
|
|
|
+ if (["POSITION_CARTESIAN", "position"].includes(_pointAttribute.name)) {
|
|
|
+ var buff = new ArrayBuffer(numPoints * 4 * 3);
|
|
|
+ var positions = new Float32Array(buff);
|
|
|
+ for (var j = 0; j < numPoints; j++) {
|
|
|
+ var pointOffset = j * bytesPerPoint;
|
|
|
+ var x = view.getInt32(pointOffset + attributeOffset + 0, true) * scale[0] + offset[0] - min.x;
|
|
|
+ var y = view.getInt32(pointOffset + attributeOffset + 4, true) * scale[1] + offset[1] - min.y;
|
|
|
+ var z = view.getInt32(pointOffset + attributeOffset + 8, true) * scale[2] + offset[2] - min.z;
|
|
|
+ var index = toIndex(x, y, z);
|
|
|
+ var count = grid[index]++;
|
|
|
+ if (count === 0) {
|
|
|
+ numOccupiedCells++;
|
|
|
+ }
|
|
|
+ positions[3 * j + 0] = x;
|
|
|
+ positions[3 * j + 1] = y;
|
|
|
+ positions[3 * j + 2] = z;
|
|
|
+ }
|
|
|
+ attributeBuffers[_pointAttribute.name] = {
|
|
|
+ buffer: buff,
|
|
|
+ attribute: _pointAttribute
|
|
|
+ };
|
|
|
+ } else if (["RGBA", "rgba"].includes(_pointAttribute.name)) {
|
|
|
+ var _buff = new ArrayBuffer(numPoints * 4);
|
|
|
+ var colors = new Uint8Array(_buff);
|
|
|
+ for (var _j = 0; _j < numPoints; _j++) {
|
|
|
+ var _pointOffset = _j * bytesPerPoint;
|
|
|
+ var r = view.getUint16(_pointOffset + attributeOffset + 0, true);
|
|
|
+ var g = view.getUint16(_pointOffset + attributeOffset + 2, true);
|
|
|
+ var b = view.getUint16(_pointOffset + attributeOffset + 4, true);
|
|
|
+ colors[4 * _j + 0] = r > 255 ? r / 256 : r;
|
|
|
+ colors[4 * _j + 1] = g > 255 ? g / 256 : g;
|
|
|
+ colors[4 * _j + 2] = b > 255 ? b / 256 : b;
|
|
|
+ }
|
|
|
+ attributeBuffers[_pointAttribute.name] = {
|
|
|
+ buffer: _buff,
|
|
|
+ attribute: _pointAttribute
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ var _buff2 = new ArrayBuffer(numPoints * 4);
|
|
|
+ var f32 = new Float32Array(_buff2);
|
|
|
+ var TypedArray = typedArrayMapping[_pointAttribute.type.name];
|
|
|
+ preciseBuffer = new TypedArray(numPoints);
|
|
|
+ var [_offset, _scale] = [0, 1];
|
|
|
+ var getterMap = {
|
|
|
+ "int8": view.getInt8,
|
|
|
+ "int16": view.getInt16,
|
|
|
+ "int32": view.getInt32,
|
|
|
+ // "int64": view.getInt64,
|
|
|
+ "uint8": view.getUint8,
|
|
|
+ "uint16": view.getUint16,
|
|
|
+ "uint32": view.getUint32,
|
|
|
+ // "uint64": view.getUint64,
|
|
|
+ "float": view.getFloat32,
|
|
|
+ "double": view.getFloat64
|
|
|
+ };
|
|
|
+ var getter = getterMap[_pointAttribute.type.name].bind(view);
|
|
|
+
|
|
|
+ // compute offset and scale to pack larger types into 32 bit floats
|
|
|
+ if (_pointAttribute.type.size > 4) {
|
|
|
+ var [amin, amax] = _pointAttribute.range;
|
|
|
+ _offset = amin;
|
|
|
+ _scale = 1 / (amax - amin);
|
|
|
+ }
|
|
|
+ for (var _j2 = 0; _j2 < numPoints; _j2++) {
|
|
|
+ var _pointOffset2 = _j2 * bytesPerPoint;
|
|
|
+ var value = getter(_pointOffset2 + attributeOffset, true);
|
|
|
+ f32[_j2] = (value - _offset) * _scale;
|
|
|
+ preciseBuffer[_j2] = value;
|
|
|
+ }
|
|
|
+ attributeBuffers[_pointAttribute.name] = {
|
|
|
+ buffer: _buff2,
|
|
|
+ preciseBuffer: preciseBuffer,
|
|
|
+ attribute: _pointAttribute,
|
|
|
+ offset: _offset,
|
|
|
+ scale: _scale
|
|
|
+ };
|
|
|
+ }
|
|
|
+ attributeOffset += _pointAttribute.byteSize;
|
|
|
+ }
|
|
|
+ var occupancy = parseInt(numPoints / numOccupiedCells);
|
|
|
+ // console.log(`${name}: #points: ${numPoints}: #occupiedCells: ${numOccupiedCells}, occupancy: ${occupancy} points/cell`);
|
|
|
+
|
|
|
+ {
|
|
|
+ // add indices
|
|
|
+ var _buff3 = new ArrayBuffer(numPoints * 4);
|
|
|
+ var indices = new Uint32Array(_buff3);
|
|
|
+ for (var i = 0; i < numPoints; i++) {
|
|
|
+ indices[i] = i;
|
|
|
+ }
|
|
|
+ attributeBuffers["INDICES"] = {
|
|
|
+ buffer: _buff3,
|
|
|
+ attribute: PointAttribute.INDICES
|
|
|
+ };
|
|
|
+ }
|
|
|
+ {
|
|
|
+ // handle attribute vectors
|
|
|
+ var vectors = pointAttributes.vectors;
|
|
|
+ for (var vector of vectors) {
|
|
|
+ var {
|
|
|
+ name: _name,
|
|
|
+ attributes
|
|
|
+ } = vector;
|
|
|
+ var numVectorElements = attributes.length;
|
|
|
+ var _buffer = new ArrayBuffer(numVectorElements * numPoints * 4);
|
|
|
+ var _f = new Float32Array(_buffer);
|
|
|
+ var iElement = 0;
|
|
|
+ for (var sourceName of attributes) {
|
|
|
+ var sourceBuffer = attributeBuffers[sourceName];
|
|
|
+ var {
|
|
|
+ offset: _offset2,
|
|
|
+ scale: _scale2
|
|
|
+ } = sourceBuffer;
|
|
|
+ var _view = new DataView(sourceBuffer.buffer);
|
|
|
+ var _getter = _view.getFloat32.bind(_view);
|
|
|
+ for (var _j3 = 0; _j3 < numPoints; _j3++) {
|
|
|
+ var _value = _getter(_j3 * 4, true);
|
|
|
+ _f[_j3 * numVectorElements + iElement] = _value / _scale2 + _offset2;
|
|
|
+ }
|
|
|
+ iElement++;
|
|
|
+ }
|
|
|
+ var vecAttribute = new PointAttribute(_name, PointAttributeTypes.DATA_TYPE_FLOAT, 3);
|
|
|
+ attributeBuffers[_name] = {
|
|
|
+ buffer: _buffer,
|
|
|
+ attribute: vecAttribute
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // let duration = performance.now() - tStart;
|
|
|
+ // let pointsPerMs = numPoints / duration;
|
|
|
+ // console.log(`duration: ${duration.toFixed(1)}ms, #points: ${numPoints}, points/ms: ${pointsPerMs.toFixed(1)}`);
|
|
|
+
|
|
|
+ var message = {
|
|
|
+ buffer: buffer,
|
|
|
+ attributeBuffers: attributeBuffers,
|
|
|
+ density: occupancy
|
|
|
+ };
|
|
|
+ var transferables = [];
|
|
|
+ for (var property in message.attributeBuffers) {
|
|
|
+ transferables.push(message.attributeBuffers[property].buffer);
|
|
|
+ }
|
|
|
+ transferables.push(buffer);
|
|
|
+ postMessage(message, transferables);
|
|
|
};
|