BinaryDecoderWorker.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. class Version {
  2. constructor(version) {
  3. this.version = version;
  4. var vmLength = version.indexOf('.') === -1 ? version.length : version.indexOf('.');
  5. this.versionMajor = parseInt(version.substr(0, vmLength));
  6. this.versionMinor = parseInt(version.substr(vmLength + 1));
  7. if (this.versionMinor.length === 0) {
  8. this.versionMinor = 0;
  9. }
  10. }
  11. newerThan(version) {
  12. var v = new Version(version);
  13. if (this.versionMajor > v.versionMajor) {
  14. return true;
  15. } else if (this.versionMajor === v.versionMajor && this.versionMinor > v.versionMinor) {
  16. return true;
  17. } else {
  18. return false;
  19. }
  20. }
  21. equalOrHigher(version) {
  22. var v = new Version(version);
  23. if (this.versionMajor > v.versionMajor) {
  24. return true;
  25. } else if (this.versionMajor === v.versionMajor && this.versionMinor >= v.versionMinor) {
  26. return true;
  27. } else {
  28. return false;
  29. }
  30. }
  31. upTo(version) {
  32. return !this.newerThan(version);
  33. }
  34. }
  35. /**
  36. * Some types of possible point attribute data formats
  37. *
  38. * @class
  39. */
  40. var PointAttributeTypes = {
  41. DATA_TYPE_DOUBLE: {
  42. ordinal: 0,
  43. name: "double",
  44. size: 8
  45. },
  46. DATA_TYPE_FLOAT: {
  47. ordinal: 1,
  48. name: "float",
  49. size: 4
  50. },
  51. DATA_TYPE_INT8: {
  52. ordinal: 2,
  53. name: "int8",
  54. size: 1
  55. },
  56. DATA_TYPE_UINT8: {
  57. ordinal: 3,
  58. name: "uint8",
  59. size: 1
  60. },
  61. DATA_TYPE_INT16: {
  62. ordinal: 4,
  63. name: "int16",
  64. size: 2
  65. },
  66. DATA_TYPE_UINT16: {
  67. ordinal: 5,
  68. name: "uint16",
  69. size: 2
  70. },
  71. DATA_TYPE_INT32: {
  72. ordinal: 6,
  73. name: "int32",
  74. size: 4
  75. },
  76. DATA_TYPE_UINT32: {
  77. ordinal: 7,
  78. name: "uint32",
  79. size: 4
  80. },
  81. DATA_TYPE_INT64: {
  82. ordinal: 8,
  83. name: "int64",
  84. size: 8
  85. },
  86. DATA_TYPE_UINT64: {
  87. ordinal: 9,
  88. name: "uint64",
  89. size: 8
  90. }
  91. };
  92. var i = 0;
  93. for (var obj in PointAttributeTypes) {
  94. PointAttributeTypes[i] = PointAttributeTypes[obj];
  95. i++;
  96. }
  97. class PointAttribute {
  98. constructor(name, type, numElements) {
  99. this.name = name;
  100. this.type = type;
  101. this.numElements = numElements;
  102. this.byteSize = this.numElements * this.type.size;
  103. this.description = "";
  104. this.range = [Infinity, -Infinity];
  105. }
  106. }
  107. PointAttribute.POSITION_CARTESIAN = new PointAttribute("POSITION_CARTESIAN", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
  108. PointAttribute.RGBA_PACKED = new PointAttribute("COLOR_PACKED", PointAttributeTypes.DATA_TYPE_INT8, 4);
  109. PointAttribute.COLOR_PACKED = PointAttribute.RGBA_PACKED;
  110. PointAttribute.RGB_PACKED = new PointAttribute("COLOR_PACKED", PointAttributeTypes.DATA_TYPE_INT8, 3);
  111. PointAttribute.NORMAL_FLOATS = new PointAttribute("NORMAL_FLOATS", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
  112. PointAttribute.INTENSITY = new PointAttribute("INTENSITY", PointAttributeTypes.DATA_TYPE_UINT16, 1);
  113. PointAttribute.CLASSIFICATION = new PointAttribute("CLASSIFICATION", PointAttributeTypes.DATA_TYPE_UINT8, 1);
  114. PointAttribute.NORMAL_SPHEREMAPPED = new PointAttribute("NORMAL_SPHEREMAPPED", PointAttributeTypes.DATA_TYPE_UINT8, 2);
  115. PointAttribute.NORMAL_OCT16 = new PointAttribute("NORMAL_OCT16", PointAttributeTypes.DATA_TYPE_UINT8, 2);
  116. PointAttribute.NORMAL = new PointAttribute("NORMAL", PointAttributeTypes.DATA_TYPE_FLOAT, 3);
  117. PointAttribute.RETURN_NUMBER = new PointAttribute("RETURN_NUMBER", PointAttributeTypes.DATA_TYPE_UINT8, 1);
  118. PointAttribute.NUMBER_OF_RETURNS = new PointAttribute("NUMBER_OF_RETURNS", PointAttributeTypes.DATA_TYPE_UINT8, 1);
  119. PointAttribute.SOURCE_ID = new PointAttribute("SOURCE_ID", PointAttributeTypes.DATA_TYPE_UINT16, 1);
  120. PointAttribute.INDICES = new PointAttribute("INDICES", PointAttributeTypes.DATA_TYPE_UINT32, 1);
  121. PointAttribute.SPACING = new PointAttribute("SPACING", PointAttributeTypes.DATA_TYPE_FLOAT, 1);
  122. PointAttribute.GPS_TIME = new PointAttribute("GPS_TIME", PointAttributeTypes.DATA_TYPE_DOUBLE, 1);
  123. var typedArrayMapping = {
  124. "int8": Int8Array,
  125. "int16": Int16Array,
  126. "int32": Int32Array,
  127. "int64": Float64Array,
  128. "uint8": Uint8Array,
  129. "uint16": Uint16Array,
  130. "uint32": Uint32Array,
  131. "uint64": Float64Array,
  132. "float": Float32Array,
  133. "double": Float64Array
  134. };
  135. Potree = {};
  136. onmessage = function onmessage(event) {
  137. performance.mark("binary-decoder-start");
  138. var buffer = event.data.buffer;
  139. var pointAttributes = event.data.pointAttributes;
  140. var numPoints = buffer.byteLength / pointAttributes.byteSize;
  141. var view = new DataView(buffer);
  142. var version = new Version(event.data.version);
  143. var nodeOffset = event.data.offset;
  144. var scale = event.data.scale;
  145. var spacing = event.data.spacing;
  146. var hasChildren = event.data.hasChildren;
  147. var name = event.data.name;
  148. var tightBoxMin = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY];
  149. var tightBoxMax = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY];
  150. var mean = [0, 0, 0];
  151. var attributeBuffers = {};
  152. var inOffset = 0;
  153. for (var pointAttribute of pointAttributes.attributes) {
  154. if (pointAttribute.name === "POSITION_CARTESIAN") {
  155. var buff = new ArrayBuffer(numPoints * 4 * 3);
  156. var positions = new Float32Array(buff);
  157. for (var j = 0; j < numPoints; j++) {
  158. var x = void 0,
  159. y = void 0,
  160. z = void 0;
  161. if (version.newerThan('1.3')) {
  162. x = view.getUint32(inOffset + j * pointAttributes.byteSize + 0, true) * scale;
  163. y = view.getUint32(inOffset + j * pointAttributes.byteSize + 4, true) * scale;
  164. z = view.getUint32(inOffset + j * pointAttributes.byteSize + 8, true) * scale;
  165. } else {
  166. x = view.getFloat32(j * pointAttributes.byteSize + 0, true) + nodeOffset[0];
  167. y = view.getFloat32(j * pointAttributes.byteSize + 4, true) + nodeOffset[1];
  168. z = view.getFloat32(j * pointAttributes.byteSize + 8, true) + nodeOffset[2];
  169. }
  170. positions[3 * j + 0] = x;
  171. positions[3 * j + 1] = y;
  172. positions[3 * j + 2] = z;
  173. mean[0] += x / numPoints;
  174. mean[1] += y / numPoints;
  175. mean[2] += z / numPoints;
  176. tightBoxMin[0] = Math.min(tightBoxMin[0], x);
  177. tightBoxMin[1] = Math.min(tightBoxMin[1], y);
  178. tightBoxMin[2] = Math.min(tightBoxMin[2], z);
  179. tightBoxMax[0] = Math.max(tightBoxMax[0], x);
  180. tightBoxMax[1] = Math.max(tightBoxMax[1], y);
  181. tightBoxMax[2] = Math.max(tightBoxMax[2], z);
  182. }
  183. attributeBuffers[pointAttribute.name] = {
  184. buffer: buff,
  185. attribute: pointAttribute
  186. };
  187. } else if (pointAttribute.name === "rgba") {
  188. var _buff = new ArrayBuffer(numPoints * 4);
  189. var colors = new Uint8Array(_buff);
  190. for (var _j = 0; _j < numPoints; _j++) {
  191. colors[4 * _j + 0] = view.getUint8(inOffset + _j * pointAttributes.byteSize + 0);
  192. colors[4 * _j + 1] = view.getUint8(inOffset + _j * pointAttributes.byteSize + 1);
  193. colors[4 * _j + 2] = view.getUint8(inOffset + _j * pointAttributes.byteSize + 2);
  194. }
  195. attributeBuffers[pointAttribute.name] = {
  196. buffer: _buff,
  197. attribute: pointAttribute
  198. };
  199. } else if (pointAttribute.name === "NORMAL_SPHEREMAPPED") {
  200. var _buff2 = new ArrayBuffer(numPoints * 4 * 3);
  201. var normals = new Float32Array(_buff2);
  202. for (var _j2 = 0; _j2 < numPoints; _j2++) {
  203. var bx = view.getUint8(inOffset + _j2 * pointAttributes.byteSize + 0);
  204. var by = view.getUint8(inOffset + _j2 * pointAttributes.byteSize + 1);
  205. var ex = bx / 255;
  206. var ey = by / 255;
  207. var nx = ex * 2 - 1;
  208. var ny = ey * 2 - 1;
  209. var nz = 1;
  210. var nw = -1;
  211. var l = nx * -nx + ny * -ny + nz * -nw;
  212. nz = l;
  213. nx = nx * Math.sqrt(l);
  214. ny = ny * Math.sqrt(l);
  215. nx = nx * 2;
  216. ny = ny * 2;
  217. nz = nz * 2 - 1;
  218. normals[3 * _j2 + 0] = nx;
  219. normals[3 * _j2 + 1] = ny;
  220. normals[3 * _j2 + 2] = nz;
  221. }
  222. attributeBuffers[pointAttribute.name] = {
  223. buffer: _buff2,
  224. attribute: pointAttribute
  225. };
  226. } else if (pointAttribute.name === "NORMAL_OCT16") {
  227. var _buff3 = new ArrayBuffer(numPoints * 4 * 3);
  228. var _normals = new Float32Array(_buff3);
  229. for (var _j3 = 0; _j3 < numPoints; _j3++) {
  230. var _bx = view.getUint8(inOffset + _j3 * pointAttributes.byteSize + 0);
  231. var _by = view.getUint8(inOffset + _j3 * pointAttributes.byteSize + 1);
  232. var u = _bx / 255 * 2 - 1;
  233. var v = _by / 255 * 2 - 1;
  234. var _z = 1 - Math.abs(u) - Math.abs(v);
  235. var _x = 0;
  236. var _y = 0;
  237. if (_z >= 0) {
  238. _x = u;
  239. _y = v;
  240. } else {
  241. _x = -(v / Math.sign(v) - 1) / Math.sign(u);
  242. _y = -(u / Math.sign(u) - 1) / Math.sign(v);
  243. }
  244. var length = Math.sqrt(_x * _x + _y * _y + _z * _z);
  245. _x = _x / length;
  246. _y = _y / length;
  247. _z = _z / length;
  248. _normals[3 * _j3 + 0] = _x;
  249. _normals[3 * _j3 + 1] = _y;
  250. _normals[3 * _j3 + 2] = _z;
  251. }
  252. attributeBuffers[pointAttribute.name] = {
  253. buffer: _buff3,
  254. attribute: pointAttribute
  255. };
  256. } else if (pointAttribute.name === "NORMAL") {
  257. var _buff4 = new ArrayBuffer(numPoints * 4 * 3);
  258. var _normals2 = new Float32Array(_buff4);
  259. for (var _j4 = 0; _j4 < numPoints; _j4++) {
  260. var _x2 = view.getFloat32(inOffset + _j4 * pointAttributes.byteSize + 0, true);
  261. var _y2 = view.getFloat32(inOffset + _j4 * pointAttributes.byteSize + 4, true);
  262. var _z2 = view.getFloat32(inOffset + _j4 * pointAttributes.byteSize + 8, true);
  263. _normals2[3 * _j4 + 0] = _x2;
  264. _normals2[3 * _j4 + 1] = _y2;
  265. _normals2[3 * _j4 + 2] = _z2;
  266. }
  267. attributeBuffers[pointAttribute.name] = {
  268. buffer: _buff4,
  269. attribute: pointAttribute
  270. };
  271. } else {
  272. var _buff5 = new ArrayBuffer(numPoints * 4);
  273. var f32 = new Float32Array(_buff5);
  274. var TypedArray = typedArrayMapping[pointAttribute.type.name];
  275. preciseBuffer = new TypedArray(numPoints);
  276. var [min, max] = [Infinity, -Infinity];
  277. var [offset, _scale] = [0, 1];
  278. var getterMap = {
  279. "int8": view.getInt8,
  280. "int16": view.getInt16,
  281. "int32": view.getInt32,
  282. "int64": view.getInt64,
  283. "uint8": view.getUint8,
  284. "uint16": view.getUint16,
  285. "uint32": view.getUint32,
  286. "uint64": view.getUint64,
  287. "float": view.getFloat32,
  288. "double": view.getFloat64
  289. };
  290. var getter = getterMap[pointAttribute.type.name].bind(view);
  291. // compute offset and scale to pack larger types into 32 bit floats
  292. if (pointAttribute.type.size > 4) {
  293. for (var _j5 = 0; _j5 < numPoints; _j5++) {
  294. var value = getter(inOffset + _j5 * pointAttributes.byteSize, true);
  295. if (!Number.isNaN(value)) {
  296. min = Math.min(min, value);
  297. max = Math.max(max, value);
  298. }
  299. }
  300. if (pointAttribute.initialRange != null) {
  301. offset = pointAttribute.initialRange[0];
  302. _scale = 1 / (pointAttribute.initialRange[1] - pointAttribute.initialRange[0]);
  303. } else {
  304. offset = min;
  305. _scale = 1 / (max - min);
  306. }
  307. }
  308. for (var _j6 = 0; _j6 < numPoints; _j6++) {
  309. var _value = getter(inOffset + _j6 * pointAttributes.byteSize, true);
  310. if (!Number.isNaN(_value)) {
  311. min = Math.min(min, _value);
  312. max = Math.max(max, _value);
  313. }
  314. f32[_j6] = (_value - offset) * _scale;
  315. preciseBuffer[_j6] = _value;
  316. }
  317. pointAttribute.range = [min, max];
  318. attributeBuffers[pointAttribute.name] = {
  319. buffer: _buff5,
  320. preciseBuffer: preciseBuffer,
  321. attribute: pointAttribute,
  322. offset: offset,
  323. scale: _scale
  324. };
  325. }
  326. inOffset += pointAttribute.byteSize;
  327. }
  328. {
  329. // add indices
  330. var _buff6 = new ArrayBuffer(numPoints * 4);
  331. var indices = new Uint32Array(_buff6);
  332. for (var i = 0; i < numPoints; i++) {
  333. indices[i] = i;
  334. }
  335. attributeBuffers["INDICES"] = {
  336. buffer: _buff6,
  337. attribute: PointAttribute.INDICES
  338. };
  339. }
  340. {
  341. // handle attribute vectors
  342. var vectors = pointAttributes.vectors;
  343. for (var vector of vectors) {
  344. var {
  345. name: _name,
  346. attributes
  347. } = vector;
  348. var numVectorElements = attributes.length;
  349. var _buffer = new ArrayBuffer(numVectorElements * numPoints * 4);
  350. var _f = new Float32Array(_buffer);
  351. var iElement = 0;
  352. for (var sourceName of attributes) {
  353. var sourceBuffer = attributeBuffers[sourceName];
  354. var {
  355. offset: _offset,
  356. scale: _scale2
  357. } = sourceBuffer;
  358. var _view = new DataView(sourceBuffer.buffer);
  359. var _getter = _view.getFloat32.bind(_view);
  360. for (var _j7 = 0; _j7 < numPoints; _j7++) {
  361. var _value2 = _getter(_j7 * 4, true);
  362. _f[_j7 * numVectorElements + iElement] = _value2 / _scale2 + _offset;
  363. }
  364. iElement++;
  365. }
  366. var vecAttribute = new PointAttribute(_name, PointAttributeTypes.DATA_TYPE_FLOAT, 3);
  367. attributeBuffers[_name] = {
  368. buffer: _buffer,
  369. attribute: vecAttribute
  370. };
  371. }
  372. }
  373. performance.mark("binary-decoder-end");
  374. // { // print timings
  375. // //performance.measure("spacing", "spacing-start", "spacing-end");
  376. // performance.measure("binary-decoder", "binary-decoder-start", "binary-decoder-end");
  377. // let measure = performance.getEntriesByType("measure")[0];
  378. // let dpp = 1000 * measure.duration / numPoints;
  379. // let pps = parseInt(numPoints / (measure.duration / 1000));
  380. // let debugMessage = `${measure.duration.toFixed(3)} ms, ${numPoints} points, ${pps.toLocaleString()} points/sec`;
  381. // console.log(debugMessage);
  382. // }
  383. performance.clearMarks();
  384. performance.clearMeasures();
  385. var message = {
  386. buffer: buffer,
  387. mean: mean,
  388. attributeBuffers: attributeBuffers,
  389. tightBoundingBox: {
  390. min: tightBoxMin,
  391. max: tightBoxMax
  392. }
  393. };
  394. var transferables = [];
  395. for (var property in message.attributeBuffers) {
  396. transferables.push(message.attributeBuffers[property].buffer);
  397. }
  398. transferables.push(buffer);
  399. postMessage(message, transferables);
  400. };