DecoderWorker.js 9.0 KB

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