Reference Source

src/parsers/parseLASIntoXKTModel.js

  1. import {parse} from '@loaders.gl/core';
  2. import {LASLoader} from '@loaders.gl/las';
  3. import {math} from "../lib/math.js";
  4.  
  5.  
  6. /**
  7. * @desc Parses LAS and LAZ point cloud data into an {@link XKTModel}.
  8. *
  9. * This parser handles both the LASER file format (LAS) and its compressed version (LAZ),
  10. * a public format for the interchange of 3-dimensional point cloud data data, developed
  11. * for LIDAR mapping purposes.
  12. *
  13. * ## Usage
  14. *
  15. * In the example below we'll create an {@link XKTModel}, then load an LAZ point cloud model into it.
  16. *
  17. * ````javascript
  18. * utils.loadArraybuffer("./models/laz/autzen.laz", async (data) => {
  19. *
  20. * const xktModel = new XKTModel();
  21. *
  22. * await parseLASIntoXKTModel({
  23. * data,
  24. * xktModel,
  25. * log: (msg) => { console.log(msg); }
  26. * }).then(()=>{
  27. * xktModel.finalize();
  28. * },
  29. * (msg) => {
  30. * console.error(msg);
  31. * });
  32. * });
  33. * ````
  34. *
  35. * @param {Object} params Parsing params.
  36. * @param {ArrayBuffer} params.data LAS/LAZ file data.
  37. * @param {XKTModel} params.xktModel XKTModel to parse into.
  38. * @param {Boolean} [params.rotateX=true] Whether to rotate the model 90 degrees about the X axis to make the Y axis "up", if necessary.
  39. * @param {Object} [params.stats] Collects statistics.
  40. * @param {function} [params.log] Logging callback.
  41. */
  42. async function parseLASIntoXKTModel({data, xktModel, rotateX = true, stats, log}) {
  43.  
  44. if (!data) {
  45. throw "Argument expected: data";
  46. }
  47.  
  48. if (!xktModel) {
  49. throw "Argument expected: xktModel";
  50. }
  51.  
  52. if (log) {
  53. log("Converting LAZ/LAS");
  54. }
  55.  
  56. let parsedData;
  57. try {
  58. parsedData = await parse(data, LASLoader);
  59. } catch (e) {
  60. if (log) {
  61. log("Error: " + e);
  62. }
  63. return;
  64. }
  65.  
  66. const attributes = parsedData.attributes;
  67. const positionsValue = attributes.POSITION.value;
  68. const colorsValue = attributes.COLOR_0.value;
  69.  
  70. if (rotateX) {
  71. if (log) {
  72. log("Rotating model about X-axis");
  73. }
  74. if (positionsValue) {
  75. for (let i = 0, len = positionsValue.length; i < len; i += 3) {
  76. const temp = positionsValue[i + 1];
  77. positionsValue[i + 1] = positionsValue[i + 2];
  78. positionsValue[i + 2] = temp;
  79. }
  80. }
  81. }
  82.  
  83. xktModel.createGeometry({
  84. geometryId: "pointsGeometry",
  85. primitiveType: "points",
  86. positions: positionsValue,
  87. colorsCompressed: colorsValue
  88. });
  89.  
  90. xktModel.createMesh({
  91. meshId: "pointsMesh",
  92. geometryId: "pointsGeometry"
  93. });
  94.  
  95. const entityId = math.createUUID();
  96.  
  97. xktModel.createEntity({
  98. entityId: entityId,
  99. meshIds: ["pointsMesh"]
  100. });
  101.  
  102. const rootMetaObjectId = math.createUUID();
  103.  
  104. xktModel.createMetaObject({
  105. metaObjectId: rootMetaObjectId,
  106. metaObjectType: "Model",
  107. metaObjectName: "Model"
  108. });
  109.  
  110. xktModel.createMetaObject({
  111. metaObjectId: entityId,
  112. metaObjectType: "PointCloud",
  113. metaObjectName: "PointCloud (LAZ)",
  114. parentMetaObjectId: rootMetaObjectId
  115. });
  116.  
  117. if (stats) {
  118. stats.sourceFormat = "LAS";
  119. stats.schemaVersion = "";
  120. stats.title = "";
  121. stats.author = "";
  122. stats.created = "";
  123. stats.numMetaObjects = 2;
  124. stats.numPropertySets = 0;
  125. stats.numObjects = 1;
  126. stats.numGeometries = 1;
  127. stats.numVertices = positionsValue.length / 3;
  128. }
  129. }
  130.  
  131. export {parseLASIntoXKTModel};