UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

271 lines (265 loc) 9.36 kB
import { m as macro } from '../../macros2.js'; import '../Core/DataAccessHelper/LiteHttpDataAccessHelper.js'; import DataAccessHelper from '../Core/DataAccessHelper.js'; import vtkActor from '../../Rendering/Core/Actor.js'; import vtkMapper from '../../Rendering/Core/Mapper.js'; import vtkDataArray from '../../Common/Core/DataArray.js'; import vtkPolyData from '../../Common/DataModel/PolyData.js'; import vtkCellArray from '../../Common/Core/CellArray.js'; import vtkAppendPolyData from '../../Filters/General/AppendPolyData.js'; import vtkMatrixBuilder from '../../Common/Core/MatrixBuilder.js'; import { mat3 } from 'gl-matrix'; const { vtkErrorMacro } = macro; let WebIFC; /** * Set WebIFC api to be used by vtkIFCImporter * @param {object} ifcApi */ function setIFCAPI(ifcApi) { WebIFC = ifcApi; } function vtkIFCImporter(publicAPI, model) { model.classHierarchy.push('vtkIFCImporter'); const meshes = []; /** * Create a vtkPolyData from an IFC mesh object * @param {object} mesh the IFC web mesh object * @returns vtkPolyData */ function createPolyDataFromIFCMesh(mesh) { const { vertices, indices } = mesh; const pd = vtkPolyData.newInstance(); const cells = vtkCellArray.newInstance(); const pointValues = new Float32Array(vertices.length / 2); const normalsArray = new Float32Array(vertices.length / 2); for (let i = 0; i < vertices.length; i += 6) { pointValues[i / 2] = vertices[i]; pointValues[i / 2 + 1] = vertices[i + 1]; pointValues[i / 2 + 2] = vertices[i + 2]; normalsArray[i / 2] = vertices[i + 3]; normalsArray[i / 2 + 1] = vertices[i + 4]; normalsArray[i / 2 + 2] = vertices[i + 5]; } const nCells = indices.length; cells.resize(3 * nCells / 3); for (let cellId = 0; cellId < nCells; cellId += 3) { const cell = indices.slice(cellId, cellId + 3); cells.insertNextCell(cell); } pd.getPoints().setData(pointValues, 3); pd.setStrips(cells); pd.getPointData().setNormals(vtkDataArray.newInstance({ name: 'Normals', values: normalsArray, numberOfComponents: 3 })); return pd; } /** * Create a colored vtkPolyData from an IFC mesh object * @param {object} mesh the IFC mesh object * @returns vtkPolyData */ function createColoredPolyDataFromIFCMesh(mesh) { const { vertices, indices, color, userMatrix } = mesh; const pd = vtkPolyData.newInstance(); const cells = vtkCellArray.newInstance(); const pointValues = new Float32Array(vertices.length / 2); const normalsArray = new Float32Array(vertices.length / 2); const colorArray = new Float32Array(vertices.length / 2); if (userMatrix) { const transformMatrix = vtkMatrixBuilder.buildFromRadian().setMatrix(userMatrix); const normalMatrix = vtkMatrixBuilder.buildFromRadian().multiply3x3(mat3.fromMat4(mat3.create(), userMatrix)); for (let i = 0; i < vertices.length; i += 6) { const point = [vertices[i], vertices[i + 1], vertices[i + 2]]; const normal = [vertices[i + 3], vertices[i + 4], vertices[i + 5]]; transformMatrix.apply(point); normalMatrix.apply(normal); pointValues[i / 2] = point[0]; pointValues[i / 2 + 1] = point[1]; pointValues[i / 2 + 2] = point[2]; normalsArray[i / 2] = normal[0]; normalsArray[i / 2 + 1] = normal[1]; normalsArray[i / 2 + 2] = normal[2]; const colorIndex = i / 2; colorArray[colorIndex] = color.x; colorArray[colorIndex + 1] = color.y; colorArray[colorIndex + 2] = color.z; } } else { for (let i = 0; i < vertices.length; i += 6) { pointValues[i / 2] = vertices[i]; pointValues[i / 2 + 1] = vertices[i + 1]; pointValues[i / 2 + 2] = vertices[i + 2]; normalsArray[i / 2] = vertices[i + 3]; normalsArray[i / 2 + 1] = vertices[i + 4]; normalsArray[i / 2 + 2] = vertices[i + 5]; const colorIndex = i / 2; colorArray[colorIndex] = color.x; colorArray[colorIndex + 1] = color.y; colorArray[colorIndex + 2] = color.z; } } const nCells = indices.length; cells.resize(3 * nCells / 3); for (let cellId = 0; cellId < nCells; cellId += 3) { const cell = indices.slice(cellId, cellId + 3); cells.insertNextCell(cell); } pd.getPoints().setData(pointValues, 3); pd.setPolys(cells); pd.getPointData().setNormals(vtkDataArray.newInstance({ name: 'Normals', values: normalsArray, numberOfComponents: 3 })); pd.getPointData().setScalars(vtkDataArray.newInstance({ name: 'Colors', values: colorArray, numberOfComponents: 3 })); return pd; } function parseIfc(content) { const modelID = model._ifcApi.OpenModel(new Uint8Array(content), { COORDINATE_TO_ORIGIN: true, USE_FAST_BOOLS: true }); model._ifcApi.StreamAllMeshes(modelID, mesh => { const placedGeometries = mesh.geometries; for (let i = 0; i < placedGeometries.size(); i++) { const placedGeometry = placedGeometries.get(i); const ifcGeometryData = model._ifcApi.GetGeometry(modelID, placedGeometry.geometryExpressID); const ifcVertices = model._ifcApi.GetVertexArray(ifcGeometryData.GetVertexData(), ifcGeometryData.GetVertexDataSize()); const ifcIndices = model._ifcApi.GetIndexArray(ifcGeometryData.GetIndexData(), ifcGeometryData.GetIndexDataSize()); meshes.push({ vertices: ifcVertices, indices: ifcIndices, color: placedGeometry.color, userMatrix: placedGeometry.flatTransformation }); } }); model._ifcApi.CloseModel(modelID); } if (!model.dataAccessHelper) { model.dataAccessHelper = DataAccessHelper.get('http'); } function fetchData(url) { const { compression, progressCallback } = model; return model.dataAccessHelper.fetchBinary(url, { compression, progressCallback }); } publicAPI.setUrl = function (url) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { binary: true }; model.url = url; model.baseURL = url.split('/').slice(0, -1).join('/'); model.compression = options.compression; return publicAPI.loadData(options); }; publicAPI.loadData = function () { return fetchData(model.url).then(publicAPI.parse); }; publicAPI.parse = content => { publicAPI.parseAsArrayBuffer(content); }; publicAPI.parseAsArrayBuffer = content => { if (!content) { vtkErrorMacro('No content to parse.'); return; } if (!WebIFC) { vtkErrorMacro('vtkIFCImporter requires WebIFC API to be set.'); return; } model._ifcApi = new WebIFC.IfcAPI(); model._ifcApi.Init().then(() => { parseIfc(content); publicAPI.invokeReady(); }); }; publicAPI.importActors = renderer => { if (model.mergeGeometries) { const opaqueMeshes = meshes.filter(mesh => mesh.color.w === 1); const oapd = vtkAppendPolyData.newInstance(); opaqueMeshes.forEach(mesh => { const pd = createColoredPolyDataFromIFCMesh(mesh); oapd.addInputData(pd); }); let mapper = vtkMapper.newInstance(); mapper.setColorModeToDirectScalars(); mapper.setInputConnection(oapd.getOutputPort()); let actor = vtkActor.newInstance(); actor.setMapper(mapper); renderer.addActor(actor); const transparentMeshes = meshes.filter(mesh => mesh.color.w < 1); const tapd = vtkAppendPolyData.newInstance(); transparentMeshes.forEach(mesh => { const pd = createColoredPolyDataFromIFCMesh(mesh); tapd.addInputData(pd); }); mapper = vtkMapper.newInstance(); mapper.setColorModeToDirectScalars(); mapper.setInputConnection(tapd.getOutputPort()); actor = vtkActor.newInstance(); actor.setMapper(mapper); actor.getProperty().setOpacity(0.5); renderer.addActor(actor); } else { meshes.forEach(mesh => { const pd = createPolyDataFromIFCMesh(mesh); const mapper = vtkMapper.newInstance(); mapper.setInputData(pd); const actor = vtkActor.newInstance(); actor.setMapper(mapper); const { x, y, z, w } = mesh.color; actor.getProperty().setColor(x, y, z); actor.getProperty().setOpacity(w); actor.setUserMatrix(mesh.userMatrix); renderer.addActor(actor); }); } }; } const DEFAULT_VALUES = { mergeGeometries: false }; function extend(publicAPI, model) { let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; Object.assign(model, DEFAULT_VALUES, initialValues); macro.obj(publicAPI, model); macro.get(publicAPI, model, ['url', 'baseURL']); macro.setGet(publicAPI, model, ['dataAccessHelper', 'mergeGeometries']); macro.event(publicAPI, model, 'ready'); macro.algo(publicAPI, model, 0, 1); vtkIFCImporter(publicAPI, model); } const newInstance = macro.newInstance(extend, 'vtkIFCImporter'); var vtkIFCImporter$1 = { newInstance, extend, setIFCAPI }; export { vtkIFCImporter$1 as default, extend, newInstance };