function parseEpt(event) { let buffer = event.data.buffer; let view = new DataView(buffer); let schema = event.data.schema; let scale = event.data.scale; let offset = event.data.offset; let mins = event.data.mins; let dimensions = schema.reduce((p, c) => { p[c.name] = c; return p; }, { }); let dimOffset = (name) => { let offset = 0; for (var i = 0; i < schema.length; ++i) { if (schema[i].name == name) return offset; offset += schema[i].size; } return undefined; }; let getExtractor = (name) => { let offset = dimOffset(name); let type = dimensions[name].type; let size = dimensions[name].size; if (type == 'signed') switch (size) { case 1: return (p) => view.getInt8(p + offset); case 2: return (p) => view.getInt16(p + offset, true); case 4: return (p) => view.getInt32(p + offset, true); case 8: return (p) => view.getInt64(p + offset, true); } if (type == 'unsigned') switch (size) { case 1: return (p) => view.getUint8(p + offset); case 2: return (p) => view.getUint16(p + offset, true); case 4: return (p) => view.getUint32(p + offset, true); case 8: return (p) => view.getUint64(p + offset, true); } if (type == 'float') switch (size) { case 4: return (p) => view.getFloat32(p + offset, true); case 8: return (p) => view.getFloat64(p + offset, true); } let str = JSON.stringify(dimensions[name]); throw new Error(`Invalid dimension specification for ${name}: ${str}`); }; let pointSize = schema.reduce((p, c) => p + c.size, 0); let numPoints = buffer.byteLength / pointSize; let xyzBuffer, rgbBuffer, intensityBuffer, classificationBuffer, returnNumberBuffer, numberOfReturnsBuffer, pointSourceIdBuffer; let xyz, rgb, intensity, classification, returnNumber, numberOfReturns, pointSourceId; let xyzExtractor, rgbExtractor, intensityExtractor, classificationExtractor, returnNumberExtractor, numberOfReturnsExtractor, pointSourceIdExtractor; let twoByteColor = false; if (dimensions['X'] && dimensions['Y'] && dimensions['Z']) { xyzBuffer = new ArrayBuffer(numPoints * 4 * 3); xyz = new Float32Array(xyzBuffer); xyzExtractor = [ getExtractor('X'), getExtractor('Y'), getExtractor('Z') ]; } if (dimensions['Red'] && dimensions['Green'] && dimensions['Blue']) { rgbBuffer = new ArrayBuffer(numPoints * 4); rgb = new Uint8Array(rgbBuffer); rgbExtractor = [ getExtractor('Red'), getExtractor('Green'), getExtractor('Blue') ]; let r, g, b, pos; for (let i = 0; i < numPoints && !twoByteColor; ++i) { pos = i * pointSize; r = rgbExtractor[0](pos); g = rgbExtractor[1](pos); b = rgbExtractor[2](pos); if (r > 255 || g > 255 || b > 255) twoByteColor = true; } } if (dimensions['Intensity']) { intensityBuffer = new ArrayBuffer(numPoints * 4); intensity = new Float32Array(intensityBuffer); intensityExtractor = getExtractor('Intensity'); } if (dimensions['Classification']) { classificationBuffer = new ArrayBuffer(numPoints); classification = new Uint8Array(classificationBuffer); classificationExtractor = getExtractor('Classification'); } if (dimensions['ReturnNumber']) { returnNumberBuffer = new ArrayBuffer(numPoints); returnNumber = new Uint8Array(returnNumberBuffer); returnNumberExtractor = getExtractor('ReturnNumber'); } if (dimensions['NumberOfReturns']) { numberOfReturnsBuffer = new ArrayBuffer(numPoints); numberOfReturns = new Uint8Array(numberOfReturnsBuffer); numberOfReturnsExtractor = getExtractor('NumberOfReturns'); } if (dimensions['PointSourceId']) { pointSourceIdBuffer = new ArrayBuffer(numPoints * 2); pointSourceId = new Uint16Array(pointSourceIdBuffer); pointSourceIdExtractor = getExtractor('PointSourceId'); } let mean = [0, 0, 0]; let bounds = { min: [Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE], max: [-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE], }; let x, y, z, r, g, b; for (let i = 0; i < numPoints; ++i) { let pos = i * pointSize; if (xyz) { x = xyzExtractor[0](pos) * scale.x + offset.x - mins[0]; y = xyzExtractor[1](pos) * scale.y + offset.y - mins[1]; z = xyzExtractor[2](pos) * scale.z + offset.z - mins[2]; mean[0] += x / numPoints; mean[1] += y / numPoints; mean[2] += z / numPoints; bounds.min[0] = Math.min(bounds.min[0], x); bounds.min[1] = Math.min(bounds.min[1], y); bounds.min[2] = Math.min(bounds.min[2], z); bounds.max[0] = Math.max(bounds.max[0], x); bounds.max[1] = Math.max(bounds.max[1], y); bounds.max[2] = Math.max(bounds.max[2], z); xyz[3 * i + 0] = x; xyz[3 * i + 1] = y; xyz[3 * i + 2] = z; } if (rgb) { r = rgbExtractor[0](pos); g = rgbExtractor[1](pos); b = rgbExtractor[2](pos); if (twoByteColor) { r /= 256; g /= 256; b /= 256; } rgb[4 * i + 0] = r; rgb[4 * i + 1] = g; rgb[4 * i + 2] = b; } if (intensity) intensity[i] = intensityExtractor(pos); if (classification) classification[i] = classificationExtractor(pos); if (returnNumber) returnNumber[i] = returnNumberExtractor(pos); if (numberOfReturns) numberOfReturns[i] = numberOfReturnsExtractor(pos); if (pointSourceId) pointSourceId[i] = pointSourceIdExtractor(pos); } let indicesBuffer = new ArrayBuffer(numPoints * 4); let indices = new Uint32Array(indicesBuffer); for (let i = 0; i < numPoints; ++i) { indices[i] = i; } let message = { numPoints: numPoints, tightBoundingBox: bounds, mean: mean, position: xyzBuffer, color: rgbBuffer, intensity: intensityBuffer, classification: classificationBuffer, returnNumber: returnNumberBuffer, numberOfReturns: numberOfReturnsBuffer, pointSourceId: pointSourceIdBuffer, indices: indicesBuffer }; let transferables = [ message.position, message.color, message.intensity, message.classification, message.returnNumber, message.numberOfReturns, message.pointSourceId, message.indices ].filter((v) => v); postMessage(message, transferables); }