123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- //Docs: https://agviegas.github.io/ifcjs-docs/#/
- import * as WebIFC from './ifc/web-ifc-api.js';
- import {
- FileLoader,
- Loader,
- Mesh,
- Color,
- MeshBasicMaterial,
- MeshLambertMaterial,
- DoubleSide,
- Matrix4,
- BufferGeometry,
- BufferAttribute,
- } from '../../../build/three.module.js';
- import {BufferGeometryUtils} from "../utils/BufferGeometryUtils.js"
- const ifcAPI = new WebIFC.IfcAPI();
- class IFCLoader extends Loader {
- constructor( manager ) {
- super( manager );
- this.modelID = 0;
- this.mapFaceindexID = {};
- this.mapIDGeometry = {};
- this.selectedObjects = [];
- this.highlightMaterial = new MeshBasicMaterial({ color: 0xff0000, depthTest: false, side: DoubleSide });
- }
- load( url, onLoad, onProgress, onError ) {
- const scope = this;
- const loader = new FileLoader( scope.manager );
- loader.setPath( scope.path );
- loader.setResponseType( 'arraybuffer' );
- loader.setRequestHeader( scope.requestHeader );
- loader.setWithCredentials( scope.withCredentials );
- loader.load(
- url,
- async function ( buffer ) {
- try {
- onLoad( await scope.parse( buffer ) );
- } catch ( e ) {
- if ( onError ) {
- onError( e );
- } else {
- console.error( e );
- }
- scope.manager.itemError( url );
- }
- },
- onProgress,
- onError
- );
- }
- setWasmPath( path ) {
- ifcAPI.SetWasmPath( path );
- }
- getExpressId( faceIndex ) {
- for (let index in this.mapFaceindexID) {
- if (parseInt(index) >= faceIndex) return this.mapFaceindexID[index];
- }
- return -1;
- }
- highlightItems( expressIds, scene, material = this.highlightMaterial ) {
- this.removePreviousSelection(scene);
- expressIds.forEach((id) => {
- if (!this.mapIDGeometry[id]) return;
- var mesh = new Mesh(this.mapIDGeometry[id], material);
- mesh.renderOrder = 1;
- scene.add(mesh);
- this.selectedObjects.push(mesh);
- return;
- });
- }
- removePreviousSelection( scene ) {
- if (this.selectedObjects.length > 0){
- this.selectedObjects.forEach((object) => scene.remove(object));
- }
- }
- setItemsVisibility( expressIds, geometry, visible = false ) {
- this.setupVisibility(geometry);
- var previous = 0;
- for (var current in this.mapFaceindexID) {
- if (expressIds.includes(this.mapFaceindexID[current])) {
- for (var i = previous; i <= current; i++) this.setVertexVisibility(geometry, i, visible);
- }
- previous = current;
- }
- geometry.attributes.visibility.needsUpdate = true;
- }
- setVertexVisibility( geometry, index, visible ) {
- var isVisible = visible ? 0 : 1;
- var geoIndex = geometry.index.array;
- geometry.attributes.visibility.setX(geoIndex[3 * index], isVisible);
- geometry.attributes.visibility.setX(geoIndex[3 * index + 1], isVisible);
- geometry.attributes.visibility.setX(geoIndex[3 * index + 2], isVisible);
-
- }
- setupVisibility( geometry ) {
- if (!geometry.attributes.visibility) {
- var visible = new Float32Array(geometry.getAttribute('position').count);
- geometry.setAttribute('visibility', new BufferAttribute(visible, 1));
- }
- }
- getItemProperties( elementID, all = false ) {
- const properties = ifcAPI.GetLine(this.modelID, elementID);
-
- if (all) {
- const propSetIds = this.getAllRelatedItemsOfType(elementID, WebIFC.IFCRELDEFINESBYPROPERTIES, "RelatedObjects", "RelatingPropertyDefinition");
- properties.hasPropertySets = propSetIds.map((id) => ifcAPI.GetLine(this.modelID, id, true));
-
- const typeId = this.getAllRelatedItemsOfType(elementID, WebIFC.IFCRELDEFINESBYTYPE, "RelatedObjects", "RelatingType");
- properties.hasType = typeId.map((id) => ifcAPI.GetLine(this.modelID, id, true));
-
- }
-
- // properties.type = properties.constructor.name;
- return properties;
- }
- getSpatialStructure() {
- let lines = ifcAPI.GetLineIDsWithType(this.modelID, WebIFC.IFCPROJECT);
- let ifcProjectId = lines.get(0);
- let ifcProject = ifcAPI.GetLine(this.modelID, ifcProjectId);
- this.getAllSpatialChildren(ifcProject);
- return ifcProject;
- }
-
- getAllSpatialChildren( spatialElement ) {
- const id = spatialElement.expressID;
- const spatialChildrenID = this.getAllRelatedItemsOfType(id, WebIFC.IFCRELAGGREGATES, "RelatingObject", "RelatedObjects");
- spatialElement.hasSpatialChildren = spatialChildrenID.map((id) => ifcAPI.GetLine(this.modelID, id, false));
- spatialElement.hasChildren = this.getAllRelatedItemsOfType(id, WebIFC.IFCRELCONTAINEDINSPATIALSTRUCTURE, "RelatingStructure", "RelatedElements");
- spatialElement.hasSpatialChildren.forEach(child => this.getAllSpatialChildren(child));
-
- }
-
- getAllRelatedItemsOfType ( elementID, type, relation, relatedProperty ) {
- const lines = ifcAPI.GetLineIDsWithType(this.modelID, type);
- const IDs = [];
- for (let i = 0; i < lines.size(); i++) {
- const relID = lines.get(i);
- const rel = ifcAPI.GetLine(this.modelID, relID);
- const relatedItems = rel[relation];
- let foundElement = false;
-
- if (Array.isArray(relatedItems)){
- relatedItems.forEach((relID) => {
- if (relID.value === elementID) foundElement = true;
- });
- }
- else foundElement = (relatedItems.value === elementID);
-
- if (foundElement) {
- var element = rel[relatedProperty];
- if (!Array.isArray(element)) IDs.push(element.value);
- else element.forEach(ele => IDs.push(ele.value))
-
- }
- }
- return IDs;
- }
- async parse( buffer ) {
- const geometryByMaterials = {};
- const mapIDGeometry = this.mapIDGeometry;
- const mapFaceindexID = this.mapFaceindexID;
- if ( ifcAPI.wasmModule === undefined ) {
- await ifcAPI.Init();
- }
- const data = new Uint8Array( buffer );
- this.modelID = ifcAPI.OpenModel( 'example.ifc', data );
- return loadAllGeometry( this.modelID );
- function loadAllGeometry(modelID) {
- saveAllPlacedGeometriesByMaterial(modelID);
- return generateAllGeometriesByMaterial();
- }
-
- function generateAllGeometriesByMaterial() {
- const { materials, geometries } = getMaterialsAndGeometries();
- const allGeometry = BufferGeometryUtils.mergeBufferGeometries(geometries, true);
- return new Mesh(allGeometry, materials);
- }
-
- function getMaterialsAndGeometries() {
- const materials = [];
- const geometries = [];
- let totalFaceCount = 0;
- for (let i in geometryByMaterials) {
- materials.push(geometryByMaterials[i].material);
- const currentGeometries = geometryByMaterials[i].geometry;
- geometries.push(BufferGeometryUtils.mergeBufferGeometries(currentGeometries));
- for (let j in geometryByMaterials[i].indices) {
- const globalIndex = parseInt(j, 10) + parseInt(totalFaceCount, 10);
- mapFaceindexID[globalIndex] = geometryByMaterials[i].indices[j];
- }
- totalFaceCount += geometryByMaterials[i].lastIndex;
- }
- return { materials, geometries };
- }
-
- function saveAllPlacedGeometriesByMaterial(modelID) {
- const flatMeshes = ifcAPI.LoadAllGeometry(modelID);
- for (let i = 0; i < flatMeshes.size(); i++) {
- const flatMesh = flatMeshes.get(i);
- const productId = flatMesh.expressID;
- const placedGeometries = flatMesh.geometries;
- for (let j = 0; j < placedGeometries.size(); j++) {
- savePlacedGeometryByMaterial(modelID, placedGeometries.get(j), productId);
- }
- }
- }
- function savePlacedGeometryByMaterial(modelID, placedGeometry, productId) {
- const geometry = getBufferGeometry(modelID, placedGeometry);
- geometry.computeVertexNormals();
- const matrix = getMeshMatrix(placedGeometry.flatTransformation);
- geometry.applyMatrix4(matrix);
- storeGeometryForHighlight(productId, geometry);
- saveGeometryByMaterial(geometry, placedGeometry, productId);
- }
- function getBufferGeometry(modelID, placedGeometry) {
- const geometry = ifcAPI.GetGeometry(modelID, placedGeometry.geometryExpressID);
- const verts = ifcAPI.GetVertexArray(geometry.GetVertexData(), geometry.GetVertexDataSize());
- const indices = ifcAPI.GetIndexArray(geometry.GetIndexData(), geometry.GetIndexDataSize());
- return ifcGeometryToBuffer(verts, indices);
- }
- function getMeshMatrix(matrix) {
- const mat = new Matrix4();
- mat.fromArray(matrix);
- return mat;
- }
-
- function storeGeometryForHighlight(productId, geometry) {
- if (!mapIDGeometry[productId]) {
- mapIDGeometry[productId] = geometry;
- return;
- }
- const geometries = [mapIDGeometry[productId], geometry];
- mapIDGeometry[productId] = BufferGeometryUtils.mergeBufferGeometries(geometries, true);
- }
-
- function ifcGeometryToBuffer(vertexData, indexData) {
- const geometry = new BufferGeometry();
- const { vertices, normals } = extractVertexData(vertexData);
- geometry.setAttribute('position', new BufferAttribute(new Float32Array(vertices), 3));
- geometry.setAttribute('normal', new BufferAttribute(new Float32Array(normals), 3));
- geometry.setIndex(new BufferAttribute(indexData, 1));
- return geometry;
- }
-
- function extractVertexData(vertexData) {
- const vertices = [];
- const normals = [];
- let isNormalData = false;
- for (let i = 0; i < vertexData.length; i++) {
- isNormalData ? normals.push(vertexData[i]) : vertices.push(vertexData[i]);
- if ((i + 1) % 3 == 0) isNormalData = !isNormalData;
- }
- return { vertices, normals };
- }
-
- function saveGeometryByMaterial(geometry, placedGeometry, productId) {
- const color = placedGeometry.color;
- const id = `${color.x}${color.y}${color.z}${color.w}`;
- createMaterial(id, color);
- const currentGeometry = geometryByMaterials[id];
- currentGeometry.geometry.push(geometry);
- currentGeometry.lastIndex += geometry.index.count / 3;
- currentGeometry.indices[currentGeometry.lastIndex] = productId;
- }
-
- function createMaterial(id, color) {
- if (!geometryByMaterials[id]){
- const col = new Color(color.x, color.y, color.z);
- const newMaterial = new MeshLambertMaterial({ color: col, side: DoubleSide });
- newMaterial.onBeforeCompile = materialHider;
- newMaterial.transparent = color.w !== 1;
- if (newMaterial.transparent) newMaterial.opacity = color.w;
- geometryByMaterials[id] = initializeGeometryByMaterial(newMaterial);
- }
- }
-
- function initializeGeometryByMaterial(newMaterial) {
- return {
- material: newMaterial,
- geometry: [],
- indices: {},
- lastIndex: 0
- };
- }
- function materialHider(shader) {
- shader.vertexShader = `
- attribute float sizes;
- attribute float visibility;
- varying float vVisible;
- ${shader.vertexShader}`.replace(
- `#include <fog_vertex>`,
- `#include <fog_vertex>
- vVisible = visibility;
- `
- );
- shader.fragmentShader = `
- varying float vVisible;
- ${shader.fragmentShader}`.replace(
- `#include <clipping_planes_fragment>`,
- `
- if (vVisible > 0.5) discard;
- #include <clipping_planes_fragment>`
- );
- }
- }
- }
- export { IFCLoader };
|