diff --git a/packages/las/src/index.ts b/packages/las/src/index.ts index 1c26beb6c..7d14bee8c 100644 --- a/packages/las/src/index.ts +++ b/packages/las/src/index.ts @@ -49,22 +49,21 @@ * * Within the Scene, we will create a {@link @xeokit/scene!SceneModel | SceneModel} to hold model geometry and materials. * - * We will then use - * {@link @xeokit/las!loadLAS | loadLAS} to load an LAS/LAZ file into our SceneModel. - * - * The {@link @xeokit/core!SDKError | SDKError} class will be used to handle any errors that may occur during this process. + * We will then use {@link @xeokit/las!loadLAS | loadLAS} to load an LAS/LAZ file into our SceneModel. * * * [Run this example]() * * ````javascript * import {SDKError} from "@xeokit/core"; * import {Scene} from "@xeokit/scene"; + * import {Data} from "@xeokit/data"; * import {WebGLRenderer} from "@xeokit/webglrenderer"; * import {Viewer} from "@xeokit/viewer"; * import {CameraControl} from "@xeokit/cameracontrol"; * import {loadLAS} from "@xeokit/las"; * * const scene = new Scene(); + * const data = new Data(); * * const renderer = new WebGLRenderer({}); * @@ -79,63 +78,57 @@ * elementId: "myCanvas" // << Ensure that this HTMLElement exists in the page * }); * - * if (view instanceof SDKError) { - * console.error(`Error creating View: ${view.message}`); + * view.camera.eye = [1841982.93, 10.03, -5173286.74]; + * view.camera.look = [1842009.49, 9.68, -5173295.85]; + * view.camera.up = [0.0, 1.0, 0.0]; * - * } else { + * new CameraControl(view, {}); * - * view.camera.eye = [1841982.93, 10.03, -5173286.74]; - * view.camera.look = [1842009.49, 9.68, -5173295.85]; - * view.camera.up = [0.0, 1.0, 0.0]; + * const sceneModel = scene.createModel({ + * id: "myModel" + * }); * - * new CameraControl(view, {}); + * const dataModel = data.createModel({ + * id: "myModel" + * }); * - * const sceneModel = scene.createModel({ - * id: "myModel" + * fetch("model.las").then(response => { + * + * response.arrayBuffer().then(fileData => { + * + * loadLAS({ + * fileData, + * sceneModel, + * dataModel, // Optional DataModel + * }, + * {, + * fp64: false, // Expect points as 64-bit floats? (optional, default is true) + * colorDepth: "auto", // 8, 16 or "auto" (optional, default is "auto) + * skip: 1, // Load every nth point (optional, default is 1) + * center: false, // Whether to center the points (optional, default is false) + * transform: [ // Transform the points (optional) + * 1,0,0,0, + * 0,1,0,0, + * 0,0,1,0, + * 0,0,0,1 + * ], + * }).then(() => { + * sceneModel.build(); + * dataModel.build(); + * + * }).catch(err => { + * + * sceneModel.destroy(); + * dataModel.destroy(); + * + * console.error(`Error loading LAS/LAZ file: ${err}`); + * }); + * }).catch(err => { + * console.error(`Error creating ArrayBuffer: ${err}`); + * }); + * }).catch(err => { + * console.error(`Error fetching model: ${err}`); * }); - * - * if (sceneModel instanceof SDKError) { - * console.error(`Error creating SceneModel: ${sceneModel.message}`); - * - * } else { - * fetch("model.las").then(response => { - * - * response.arrayBuffer().then(fileData => { - * - * loadLAS({ - * fileData, - * sceneModel - * }, - * {, - * fp64: false, // Expect points as 64-bit floats? (optional, default is true) - * colorDepth: "auto", // 8, 16 or "auto" (optional, default is "auto) - * skip: 1, // Load every nth point (optional, default is 1) - * center: false, // Whether to center the points (optional, default is false) - * transform: [ // Transform the points (optional) - * 1,0,0,0, - * 0,1,0,0, - * 0,0,1,0, - * 0,0,0,1 - * ], - * }).then(() => { - * sceneModel.build(); - * - * }).catch(sdkError => { - * sceneModel.destroy(); - * console.error(`Error loading LAS/LAZ file: ${sdkError.message}`); - * }); - * - * }).catch(message => { - * console.error(`Error creating ArrayBuffer: ${message}`); - * }); - * - * }).catch(message => { - * console.error(`Error fetching model: ${message}`); - * }); - * }).catch(message => { - * console.error(`Error initializing WebIFC.IfcAPI: ${message}`); - * }); - * } * ```` * * @module @xeokit/las diff --git a/packages/las/src/loadLAS.ts b/packages/las/src/loadLAS.ts index 944b7423e..578c45d01 100644 --- a/packages/las/src/loadLAS.ts +++ b/packages/las/src/loadLAS.ts @@ -1,5 +1,5 @@ -import type {SceneModel} from "@xeokit/scene"; -import type {DataModel} from "@xeokit/data"; +import {SceneModel} from "@xeokit/scene"; +import {DataModel} from "@xeokit/data"; import {SDKError} from "@xeokit/core"; import {createMat4, createVec3, transformPoint3} from "@xeokit/matrix"; import {BasicAggregation, BasicEntity} from "@xeokit/basictypes"; @@ -48,169 +48,147 @@ export function loadLAS(params: { skip?: number; fp64?: boolean; colorDepth?: string | number, - } = {}): Promise { - - return new Promise(function (resolve, reject) { - - const {dataModel, sceneModel, fileData} = params; + } = {}): Promise { + return new Promise(function (resolve, reject) { + const {sceneModel, dataModel, fileData} = params; if (!fileData) { - return Promise.reject("Parameter expected: fileData"); - } - - if (!sceneModel) { - return Promise.reject("Parameter expected: sceneModel"); + return reject("Argument expected: fileData"); } - - if (sceneModel?.destroyed) { - return Promise.reject("SceneModel already destroyed"); - } - - if (sceneModel?.built) { - return Promise.reject("SceneModel already built"); + // if (!(fileData instanceof ArrayBuffer)) { + // return reject("Argument type mismatch: params.fileData should be an ArrayBuffer"); + // } + if (sceneModel) { + if (!(sceneModel instanceof SceneModel)) { + return reject("Argument type mismatch: params.sceneModel should be a SceneModel"); + } + if (sceneModel.destroyed) { + return reject("SceneModel already destroyed"); + } + if (sceneModel.built) { + return reject("SceneModel already built"); + } } - - if (dataModel?.destroyed) { - return Promise.reject("DataModel already destroyed"); + if (dataModel) { + if (!(dataModel instanceof DataModel)) { + return reject("Argument type mismatch: params.dataModel should be a DataModel"); + } + if (dataModel.destroyed) { + return reject("DataModel already destroyed"); + } + if (dataModel.built) { + return reject("DataModel already built"); + } } - - if (dataModel?.built) { - return Promise.reject("DataModel already built"); + if (!sceneModel && !dataModel) { + return resolve(); } - const skip = options.skip || 1; - const log = (msg) => { if (params.log) { params.log(msg); } } - parse(params.fileData, LASLoader, { las: { colorDepth: options.colorDepth || "auto", fp64: options.fp64 !== undefined ? options.fp64 : false } - }).then((parsedData) => { - - const attributes = parsedData.attributes; - - const loaderData = parsedData.loaderData; - const pointsFormatId = loaderData.pointsFormatId !== undefined ? loaderData.pointsFormatId : -1; - - if (!attributes.POSITION) { - log("No positions found in file (expected for all LAS point formats)"); - return; - } - - let readAttributes: any = {}; - - switch (pointsFormatId) { - case 0: - if (!attributes.intensity) { - log("No intensities found in file (expected for LAS point format 0)"); - return; - } - - readAttributes = readIntensities(attributes.POSITION, attributes.intensity); - break; - case 1: - if (!attributes.intensity) { - log("No intensities found in file (expected for LAS point format 1)"); - return; - } - readAttributes = readIntensities(attributes.POSITION, attributes.intensity); - break; - case 2: - if (!attributes.intensity) { - log("No intensities found in file (expected for LAS point format 2)"); - return; - } - - readAttributes = readColorsAndIntensities(attributes.POSITION, attributes.COLOR_0, attributes.intensity); - break; - case 3: - if (!attributes.intensity) { - log("No intensities found in file (expected for LAS point format 3)"); - return; - } - readAttributes = readColorsAndIntensities(attributes.POSITION, attributes.COLOR_0, attributes.intensity); - break; - } - - const pointsChunks = chunkArray(readPositions(readAttributes.positions), MAX_VERTICES * 3); - const colorsChunks = chunkArray(readAttributes.colors, MAX_VERTICES * 4); - - const meshIds = []; - - for (let j = 0, lenj = pointsChunks.length; j < lenj; j++) { - - const geometryId = `geometry-${j}`; - - const geometry = sceneModel.createGeometry({ - id: geometryId, - primitive: PointsPrimitive, - positions: pointsChunks[j], - colors: colorsChunks[j] - }); - - if (geometry instanceof SDKError) { - log(`[ERROR] Failed to load point cloud: ${geometry.message}`); - } else { - - const meshId = `mesh-${j}`; - meshIds.push(meshId); - - const mesh = sceneModel.createMesh({ - id: meshId, - geometryId + const entityId = createUUID(); + if (sceneModel) { + const meshIds = []; + const attributes = parsedData.attributes; + const loaderData = parsedData.loaderData; + const pointsFormatId = loaderData.pointsFormatId !== undefined ? loaderData.pointsFormatId : -1; + if (!attributes.POSITION) { + log("No positions found in file (expected for all LAS point formats)"); + return; + } + let readAttributes: any = {}; + switch (pointsFormatId) { + case 0: + if (!attributes.intensity) { + log("No intensities found in file (expected for LAS point format 0)"); + return; + } + readAttributes = readIntensities(attributes.POSITION, attributes.intensity); + break; + case 1: + if (!attributes.intensity) { + log("No intensities found in file (expected for LAS point format 1)"); + return; + } + readAttributes = readIntensities(attributes.POSITION, attributes.intensity); + break; + case 2: + if (!attributes.intensity) { + log("No intensities found in file (expected for LAS point format 2)"); + return; + } + readAttributes = readColorsAndIntensities(attributes.POSITION, attributes.COLOR_0, attributes.intensity); + break; + case 3: + if (!attributes.intensity) { + log("No intensities found in file (expected for LAS point format 3)"); + return; + } + readAttributes = readColorsAndIntensities(attributes.POSITION, attributes.COLOR_0, attributes.intensity); + break; + } + const pointsChunks = chunkArray(readPositions(readAttributes.positions), MAX_VERTICES * 3); + const colorsChunks = chunkArray(readAttributes.colors, MAX_VERTICES * 4); + for (let j = 0, lenj = pointsChunks.length; j < lenj; j++) { + const geometryId = `geometry-${j}`; + const geometry = sceneModel.createGeometry({ + id: geometryId, + primitive: PointsPrimitive, + positions: pointsChunks[j], + colors: colorsChunks[j] }); - - if (mesh instanceof SDKError) { - log(`[ERROR] Failed to load point cloud: ${mesh.message}`); + if (geometry instanceof SDKError) { + log(`[ERROR] Failed to load point cloud: ${geometry.message}`); + } else { + const meshId = `mesh-${j}`; + meshIds.push(meshId); + const mesh = sceneModel.createMesh({ + id: meshId, + geometryId + }); + if (mesh instanceof SDKError) { + log(`[ERROR] Failed to load point cloud: ${mesh.message}`); + } } } + sceneModel.createObject({ + id: entityId, + meshIds + }); } - - const entityId = createUUID(); - - sceneModel.createObject({ - id: entityId, - meshIds - }); - if (dataModel) { - const rootMetaObjectId = createUUID(); - dataModel.createObject({ id: rootMetaObjectId, type: BasicEntity, name: "Model", }); - dataModel.createObject({ id: entityId, type: BasicEntity, name: "PointCloud (LAZ)", }); - dataModel.createRelationship({ type: BasicAggregation, relatingObjectId: rootMetaObjectId, relatedObjectId: entityId }); } - resolve(); - }, (errMsg) => { - reject(errMsg); + return reject(`Error parsing LAS/LAZ data: ${errMsg}`); }); function readPositions(positionsValue) { - if (positionsValue) { if (options.center) { const centerPos = createVec3();