DecoderWorker.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /**
  2. * Some types of possible point attribute data formats
  3. *
  4. * @class
  5. */
  6. const PointAttributeTypes = {
  7. DATA_TYPE_DOUBLE: {ordinal: 0, name: "double", size: 8},
  8. DATA_TYPE_FLOAT: {ordinal: 1, name: "float", size: 4},
  9. DATA_TYPE_INT8: {ordinal: 2, name: "int8", size: 1},
  10. DATA_TYPE_UINT8: {ordinal: 3, name: "uint8", size: 1},
  11. DATA_TYPE_INT16: {ordinal: 4, name: "int16", size: 2},
  12. DATA_TYPE_UINT16: {ordinal: 5, name: "uint16", size: 2},
  13. DATA_TYPE_INT32: {ordinal: 6, name: "int32", size: 4},
  14. DATA_TYPE_UINT32: {ordinal: 7, name: "uint32", size: 4},
  15. DATA_TYPE_INT64: {ordinal: 8, name: "int64", size: 8},
  16. DATA_TYPE_UINT64: {ordinal: 9, name: "uint64", size: 8}
  17. };
  18. let i = 0;
  19. for (let obj in PointAttributeTypes) {
  20. PointAttributeTypes[i] = PointAttributeTypes[obj];
  21. i++;
  22. }
  23. class PointAttribute{
  24. constructor(name, type, numElements){
  25. this.name = name;
  26. this.type = type;
  27. this.numElements = numElements;
  28. this.byteSize = this.numElements * this.type.size;
  29. this.description = "";
  30. this.range = [Infinity, -Infinity];
  31. }
  32. }
  33. PointAttribute.POSITION_CARTESIAN = new PointAttribute(
  34. "POSITION_CARTESIAN", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
  35. PointAttribute.RGBA_PACKED = new PointAttribute(
  36. "COLOR_PACKED", PointAttributeTypes.DATA_TYPE_INT8, 4);
  37. PointAttribute.COLOR_PACKED = PointAttribute.RGBA_PACKED;
  38. PointAttribute.RGB_PACKED = new PointAttribute(
  39. "COLOR_PACKED", PointAttributeTypes.DATA_TYPE_INT8, 3);
  40. PointAttribute.NORMAL_FLOATS = new PointAttribute(
  41. "NORMAL_FLOATS", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
  42. PointAttribute.INTENSITY = new PointAttribute(
  43. "INTENSITY", PointAttributeTypes.DATA_TYPE_UINT16, 1);
  44. PointAttribute.CLASSIFICATION = new PointAttribute(
  45. "CLASSIFICATION", PointAttributeTypes.DATA_TYPE_UINT8, 1);
  46. PointAttribute.NORMAL_SPHEREMAPPED = new PointAttribute(
  47. "NORMAL_SPHEREMAPPED", PointAttributeTypes.DATA_TYPE_UINT8, 2);
  48. PointAttribute.NORMAL_OCT16 = new PointAttribute(
  49. "NORMAL_OCT16", PointAttributeTypes.DATA_TYPE_UINT8, 2);
  50. PointAttribute.NORMAL = new PointAttribute(
  51. "NORMAL", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
  52. PointAttribute.RETURN_NUMBER = new PointAttribute(
  53. "RETURN_NUMBER", PointAttributeTypes.DATA_TYPE_UINT8, 1);
  54. PointAttribute.NUMBER_OF_RETURNS = new PointAttribute(
  55. "NUMBER_OF_RETURNS", PointAttributeTypes.DATA_TYPE_UINT8, 1);
  56. PointAttribute.SOURCE_ID = new PointAttribute(
  57. "SOURCE_ID", PointAttributeTypes.DATA_TYPE_UINT16, 1);
  58. PointAttribute.INDICES = new PointAttribute(
  59. "INDICES", PointAttributeTypes.DATA_TYPE_UINT32, 1);
  60. PointAttribute.SPACING = new PointAttribute(
  61. "SPACING", PointAttributeTypes.DATA_TYPE_FLOAT, 1);
  62. PointAttribute.GPS_TIME = new PointAttribute(
  63. "GPS_TIME", PointAttributeTypes.DATA_TYPE_DOUBLE, 1);
  64. const typedArrayMapping = {
  65. "int8": Int8Array,
  66. "int16": Int16Array,
  67. "int32": Int32Array,
  68. "int64": Float64Array,
  69. "uint8": Uint8Array,
  70. "uint16": Uint16Array,
  71. "uint32": Uint32Array,
  72. "uint64": Float64Array,
  73. "float": Float32Array,
  74. "double": Float64Array,
  75. };
  76. Potree = {};
  77. onmessage = function (event) {
  78. let {buffer, pointAttributes, scale, name, min, max, size, offset, numPoints} = event.data;
  79. let tStart = performance.now();
  80. let view = new DataView(buffer);
  81. let attributeBuffers = {};
  82. let attributeOffset = 0;
  83. let bytesPerPoint = 0;
  84. for (let pointAttribute of pointAttributes.attributes) {
  85. bytesPerPoint += pointAttribute.byteSize;
  86. }
  87. let gridSize = 32;
  88. let grid = new Uint32Array(gridSize ** 3);
  89. let toIndex = (x, y, z) => {
  90. // let dx = gridSize * (x - min.x) / size.x;
  91. // let dy = gridSize * (y - min.y) / size.y;
  92. // let dz = gridSize * (z - min.z) / size.z;
  93. // min is already subtracted
  94. let dx = gridSize * x / size.x;
  95. let dy = gridSize * y / size.y;
  96. let dz = gridSize * z / size.z;
  97. let ix = Math.min(parseInt(dx), gridSize - 1);
  98. let iy = Math.min(parseInt(dy), gridSize - 1);
  99. let iz = Math.min(parseInt(dz), gridSize - 1);
  100. let index = ix + iy * gridSize + iz * gridSize * gridSize;
  101. return index;
  102. };
  103. let numOccupiedCells = 0;
  104. for (let pointAttribute of pointAttributes.attributes) {
  105. if(["POSITION_CARTESIAN", "position"].includes(pointAttribute.name)){
  106. let buff = new ArrayBuffer(numPoints * 4 * 3);
  107. let positions = new Float32Array(buff);
  108. for (let j = 0; j < numPoints; j++) {
  109. let pointOffset = j * bytesPerPoint;
  110. let x = (view.getInt32(pointOffset + attributeOffset + 0, true) * scale[0]) + offset[0] - min.x;
  111. let y = (view.getInt32(pointOffset + attributeOffset + 4, true) * scale[1]) + offset[1] - min.y;
  112. let z = (view.getInt32(pointOffset + attributeOffset + 8, true) * scale[2]) + offset[2] - min.z;
  113. let index = toIndex(x, y, z);
  114. let count = grid[index]++;
  115. if(count === 0){
  116. numOccupiedCells++;
  117. }
  118. positions[3 * j + 0] = x;
  119. positions[3 * j + 1] = y;
  120. positions[3 * j + 2] = z;
  121. }
  122. attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute };
  123. }else if(["RGBA", "rgba"].includes(pointAttribute.name)){
  124. let buff = new ArrayBuffer(numPoints * 4);
  125. let colors = new Uint8Array(buff);
  126. for (let j = 0; j < numPoints; j++) {
  127. let pointOffset = j * bytesPerPoint;
  128. let r = view.getUint16(pointOffset + attributeOffset + 0, true);
  129. let g = view.getUint16(pointOffset + attributeOffset + 2, true);
  130. let b = view.getUint16(pointOffset + attributeOffset + 4, true);
  131. colors[4 * j + 0] = r > 255 ? r / 256 : r;
  132. colors[4 * j + 1] = g > 255 ? g / 256 : g;
  133. colors[4 * j + 2] = b > 255 ? b / 256 : b;
  134. }
  135. attributeBuffers[pointAttribute.name] = { buffer: buff, attribute: pointAttribute };
  136. }else {
  137. let buff = new ArrayBuffer(numPoints * 4);
  138. let f32 = new Float32Array(buff);
  139. let TypedArray = typedArrayMapping[pointAttribute.type.name];
  140. preciseBuffer = new TypedArray(numPoints);
  141. let [offset, scale] = [0, 1];
  142. const getterMap = {
  143. "int8": view.getInt8,
  144. "int16": view.getInt16,
  145. "int32": view.getInt32,
  146. // "int64": view.getInt64,
  147. "uint8": view.getUint8,
  148. "uint16": view.getUint16,
  149. "uint32": view.getUint32,
  150. // "uint64": view.getUint64,
  151. "float": view.getFloat32,
  152. "double": view.getFloat64,
  153. };
  154. const getter = getterMap[pointAttribute.type.name].bind(view);
  155. // compute offset and scale to pack larger types into 32 bit floats
  156. if(pointAttribute.type.size > 4){
  157. let [amin, amax] = pointAttribute.range;
  158. offset = amin;
  159. scale = 1 / (amax - amin);
  160. }
  161. for(let j = 0; j < numPoints; j++){
  162. let pointOffset = j * bytesPerPoint;
  163. let value = getter(pointOffset + attributeOffset, true);
  164. f32[j] = (value - offset) * scale;
  165. preciseBuffer[j] = value;
  166. }
  167. attributeBuffers[pointAttribute.name] = {
  168. buffer: buff,
  169. preciseBuffer: preciseBuffer,
  170. attribute: pointAttribute,
  171. offset: offset,
  172. scale: scale,
  173. };
  174. }
  175. attributeOffset += pointAttribute.byteSize;
  176. }
  177. let occupancy = parseInt(numPoints / numOccupiedCells);
  178. // console.log(`${name}: #points: ${numPoints}: #occupiedCells: ${numOccupiedCells}, occupancy: ${occupancy} points/cell`);
  179. { // add indices
  180. let buff = new ArrayBuffer(numPoints * 4);
  181. let indices = new Uint32Array(buff);
  182. for (let i = 0; i < numPoints; i++) {
  183. indices[i] = i;
  184. }
  185. attributeBuffers["INDICES"] = { buffer: buff, attribute: PointAttribute.INDICES };
  186. }
  187. { // handle attribute vectors
  188. let vectors = pointAttributes.vectors;
  189. for(let vector of vectors){
  190. let {name, attributes} = vector;
  191. let numVectorElements = attributes.length;
  192. let buffer = new ArrayBuffer(numVectorElements * numPoints * 4);
  193. let f32 = new Float32Array(buffer);
  194. let iElement = 0;
  195. for(let sourceName of attributes){
  196. let sourceBuffer = attributeBuffers[sourceName];
  197. let {offset, scale} = sourceBuffer;
  198. let view = new DataView(sourceBuffer.buffer);
  199. const getter = view.getFloat32.bind(view);
  200. for(let j = 0; j < numPoints; j++){
  201. let value = getter(j * 4, true);
  202. f32[j * numVectorElements + iElement] = (value / scale) + offset;
  203. }
  204. iElement++;
  205. }
  206. let vecAttribute = new PointAttribute(name, PointAttributeTypes.DATA_TYPE_FLOAT, 3);
  207. attributeBuffers[name] = {
  208. buffer: buffer,
  209. attribute: vecAttribute,
  210. };
  211. }
  212. }
  213. // let duration = performance.now() - tStart;
  214. // let pointsPerMs = numPoints / duration;
  215. // console.log(`duration: ${duration.toFixed(1)}ms, #points: ${numPoints}, points/ms: ${pointsPerMs.toFixed(1)}`);
  216. let message = {
  217. buffer: buffer,
  218. attributeBuffers: attributeBuffers,
  219. density: occupancy,
  220. };
  221. let transferables = [];
  222. for (let property in message.attributeBuffers) {
  223. transferables.push(message.attributeBuffers[property].buffer);
  224. }
  225. transferables.push(buffer);
  226. postMessage(message, transferables);
  227. };