12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133 |
- import {
- IFCRELAGGREGATES,
- IFCRELCONTAINEDINSPATIALSTRUCTURE,
- IFCRELDEFINESBYPROPERTIES,
- IFCRELDEFINESBYTYPE,
- IFCPROJECT,
- IfcAPI,
- } from './ifc/web-ifc-api.js';
- import {
- BufferAttribute,
- BufferGeometry,
- Mesh,
- Matrix4,
- Color,
- MeshLambertMaterial,
- DoubleSide,
- Group,
- Loader,
- FileLoader,
- } from '../../../build/three.module.js';
- import * as BufferGeometryUtils from '../utils/BufferGeometryUtils.js';
- const IdAttrName = 'expressID';
- const merge = ( geoms, createGroups = false ) => {
- return BufferGeometryUtils.mergeBufferGeometries( geoms, createGroups );
- };
- const newFloatAttr = ( data, size ) => {
- return new BufferAttribute( new Float32Array( data ), size );
- };
- const newIntAttr = ( data, size ) => {
- return new BufferAttribute( new Uint32Array( data ), size );
- };
- const DEFAULT = 'default';
- const PropsNames = {
- aggregates: {
- name: IFCRELAGGREGATES,
- relating: 'RelatingObject',
- related: 'RelatedObjects',
- key: 'children',
- },
- spatial: {
- name: IFCRELCONTAINEDINSPATIALSTRUCTURE,
- relating: 'RelatingStructure',
- related: 'RelatedElements',
- key: 'children',
- },
- psets: {
- name: IFCRELDEFINESBYPROPERTIES,
- relating: 'RelatingPropertyDefinition',
- related: 'RelatedObjects',
- key: 'hasPsets',
- },
- type: {
- name: IFCRELDEFINESBYTYPE,
- relating: 'RelatingType',
- related: 'RelatedObjects',
- key: 'hasType',
- },
- };
- class IFCParser {
- constructor( state ) {
- this.currentID = - 1;
- this.state = state;
- }
- async parse( buffer ) {
- if ( this.state.api.wasmModule === undefined ) await this.state.api.Init();
- this.currentID = this.newIfcModel( buffer );
- return this.loadAllGeometry();
- }
- initializeMeshBVH( computeBoundsTree, disposeBoundsTree, acceleratedRaycast ) {
- this.computeBoundsTree = computeBoundsTree;
- this.disposeBoundsTree = disposeBoundsTree;
- this.acceleratedRaycast = acceleratedRaycast;
- this.setupThreeMeshBVH();
- }
- setupThreeMeshBVH() {
- if (
- ! this.computeBoundsTree ||
- ! this.disposeBoundsTree ||
- ! this.acceleratedRaycast
- )
- return;
- BufferGeometry.prototype.computeBoundsTree = this.computeBoundsTree;
- BufferGeometry.prototype.disposeBoundsTree = this.disposeBoundsTree;
- Mesh.prototype.raycast = this.acceleratedRaycast;
- }
- applyThreeMeshBVH( geometry ) {
- if ( this.computeBoundsTree ) geometry.computeBoundsTree();
- }
- newIfcModel( buffer ) {
- const data = new Uint8Array( buffer );
- const modelID = this.state.api.OpenModel( data );
- this.state.models[ modelID ] = {
- modelID,
- mesh: {},
- items: {},
- types: {},
- };
- return modelID;
- }
- loadAllGeometry() {
- this.saveAllPlacedGeometriesByMaterial();
- return this.generateAllGeometriesByMaterial();
- }
- generateAllGeometriesByMaterial() {
- const { geometry, materials } = this.getGeometryAndMaterials();
- this.applyThreeMeshBVH( geometry );
- const mesh = new Mesh( geometry, materials );
- mesh.modelID = this.currentID;
- this.state.models[ this.currentID ].mesh = mesh;
- return mesh;
- }
- getGeometryAndMaterials() {
- const items = this.state.models[ this.currentID ].items;
- const mergedByMaterial = [];
- const materials = [];
- for ( const materialID in items ) {
- materials.push( items[ materialID ].material );
- const geometries = Object.values( items[ materialID ].geometries );
- mergedByMaterial.push( merge( geometries ) );
- }
- const geometry = merge( mergedByMaterial, true );
- return {
- geometry,
- materials,
- };
- }
- saveAllPlacedGeometriesByMaterial() {
- const flatMeshes = this.state.api.LoadAllGeometry( this.currentID );
- for ( let i = 0; i < flatMeshes.size(); i ++ ) {
- const flatMesh = flatMeshes.get( i );
- const placedGeom = flatMesh.geometries;
- for ( let j = 0; j < placedGeom.size(); j ++ ) {
- this.savePlacedGeometry( placedGeom.get( j ), flatMesh.expressID );
- }
- }
- }
- savePlacedGeometry( placedGeometry, id ) {
- const geometry = this.getBufferGeometry( placedGeometry );
- geometry.computeVertexNormals();
- const matrix = this.getMeshMatrix( placedGeometry.flatTransformation );
- geometry.applyMatrix4( matrix );
- this.saveGeometryByMaterial( geometry, placedGeometry, id );
- }
- getBufferGeometry( placed ) {
- const geometry = this.state.api.GetGeometry(
- this.currentID,
- placed.geometryExpressID
- );
- const vertexData = this.getVertices( geometry );
- const indices = this.getIndices( geometry );
- const { vertices, normals } = this.extractVertexData( vertexData );
- return this.ifcGeomToBufferGeom( vertices, normals, indices );
- }
- getVertices( geometry ) {
- const vData = geometry.GetVertexData();
- const vDataSize = geometry.GetVertexDataSize();
- return this.state.api.GetVertexArray( vData, vDataSize );
- }
- getIndices( geometry ) {
- const iData = geometry.GetIndexData();
- const iDataSize = geometry.GetIndexDataSize();
- return this.state.api.GetIndexArray( iData, iDataSize );
- }
- getMeshMatrix( matrix ) {
- const mat = new Matrix4();
- mat.fromArray( matrix );
- return mat;
- }
- ifcGeomToBufferGeom( vertices, normals, indexData ) {
- const geometry = new BufferGeometry();
- geometry.setAttribute( 'position', newFloatAttr( vertices, 3 ) );
- geometry.setAttribute( 'normal', newFloatAttr( normals, 3 ) );
- geometry.setIndex( new BufferAttribute( indexData, 1 ) );
- return geometry;
- }
- 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,
- };
- }
- saveGeometryByMaterial( geom, placedGeom, id ) {
- const color = placedGeom.color;
- const colorID = `${color.x}${color.y}${color.z}${color.w}`;
- this.storeGeometryAttribute( id, geom );
- this.createMaterial( colorID, color );
- const item = this.state.models[ this.currentID ].items[ colorID ];
- const currentGeom = item.geometries[ id ];
- if ( ! currentGeom ) return ( item.geometries[ id ] = geom );
- const merged = merge( [ currentGeom, geom ] );
- item.geometries[ id ] = merged;
- }
- storeGeometryAttribute( id, geometry ) {
- const size = geometry.attributes.position.count;
- const idAttribute = new Array( size ).fill( id );
- geometry.setAttribute( IdAttrName, newIntAttr( idAttribute, 1 ) );
- }
- createMaterial( colorID, color ) {
- const items = this.state.models[ this.currentID ].items;
- if ( items[ colorID ] ) return;
- const col = new Color( color.x, color.y, color.z );
- const newMaterial = new MeshLambertMaterial( {
- color: col,
- side: DoubleSide,
- } );
- newMaterial.transparent = color.w !== 1;
- if ( newMaterial.transparent ) newMaterial.opacity = color.w;
- items[ colorID ] = {
- material: newMaterial,
- geometries: {},
- };
- }
- }
- class SubsetManager {
- constructor( state ) {
- this.state = state;
- this.selected = {};
- }
- getSubset( modelID, material ) {
- const currentMat = this.matIDNoConfig( modelID, material );
- if ( ! this.selected[ currentMat ] ) return null;
- return this.selected[ currentMat ].mesh;
- }
- removeSubset( modelID, scene, material ) {
- const currentMat = this.matIDNoConfig( modelID, material );
- if ( ! this.selected[ currentMat ] ) return;
- if ( scene ) scene.remove( this.selected[ currentMat ].mesh );
- delete this.selected[ currentMat ];
- }
- createSubset( config ) {
- if ( ! this.isConfigValid( config ) ) return;
- if ( this.isPreviousSelection( config ) ) return;
- if ( this.isEasySelection( config ) )
- return this.addToPreviousSelection( config );
- this.updatePreviousSelection( config.scene, config );
- return this.createSelectionInScene( config );
- }
- createSelectionInScene( config ) {
- const filtered = this.filter( config );
- const { geomsByMaterial, materials } = this.getGeomAndMat( filtered );
- const hasDefaultMaterial = this.matID( config ) == DEFAULT;
- const geometry = merge( geomsByMaterial, hasDefaultMaterial );
- const mats = hasDefaultMaterial ? materials : config.material;
- const mesh = new Mesh( geometry, mats );
- this.selected[ this.matID( config ) ].mesh = mesh;
- mesh.modelID = config.modelID;
- config.scene.add( mesh );
- return mesh;
- }
- isConfigValid( config ) {
- return (
- this.isValid( config.scene ) &&
- this.isValid( config.modelID ) &&
- this.isValid( config.ids ) &&
- this.isValid( config.removePrevious )
- );
- }
- isValid( item ) {
- return item != undefined && item != null;
- }
- getGeomAndMat( filtered ) {
- const geomsByMaterial = [];
- const materials = [];
- for ( const matID in filtered ) {
- const geoms = Object.values( filtered[ matID ].geometries );
- if ( ! geoms.length ) continue;
- materials.push( filtered[ matID ].material );
- if ( geoms.length > 1 ) geomsByMaterial.push( merge( geoms ) );
- else geomsByMaterial.push( ...geoms );
- }
- return {
- geomsByMaterial,
- materials,
- };
- }
- updatePreviousSelection( scene, config ) {
- const previous = this.selected[ this.matID( config ) ];
- if ( ! previous ) return this.newSelectionGroup( config );
- scene.remove( previous.mesh );
- config.removePrevious
- ? ( previous.ids = new Set( config.ids ) )
- : config.ids.forEach( ( id ) => previous.ids.add( id ) );
- }
- newSelectionGroup( config ) {
- this.selected[ this.matID( config ) ] = {
- ids: new Set( config.ids ),
- mesh: {},
- };
- }
- isPreviousSelection( config ) {
- if ( ! this.selected[ this.matID( config ) ] ) return false;
- if ( this.containsIds( config ) ) return true;
- const previousIds = this.selected[ this.matID( config ) ].ids;
- return JSON.stringify( config.ids ) === JSON.stringify( previousIds );
- }
- containsIds( config ) {
- const newIds = config.ids;
- const previous = Array.from( this.selected[ this.matID( config ) ].ids );
- return newIds.every(
- (
- ( i ) => ( v ) =>
- ( i = previous.indexOf( v, i ) + 1 )
- )( 0 )
- );
- }
- addToPreviousSelection( config ) {
- const previous = this.selected[ this.matID( config ) ];
- const filtered = this.filter( config );
- const geometries = Object.values( filtered )
- .map( ( i ) => Object.values( i.geometries ) )
- .flat();
- const previousGeom = previous.mesh.geometry;
- previous.mesh.geometry = merge( [ previousGeom, ...geometries ] );
- config.ids.forEach( ( id ) => previous.ids.add( id ) );
- }
- filter( config ) {
- const items = this.state.models[ config.modelID ].items;
- const filtered = {};
- for ( const matID in items ) {
- filtered[ matID ] = {
- material: items[ matID ].material,
- geometries: this.filterGeometries(
- new Set( config.ids ),
- items[ matID ].geometries
- ),
- };
- }
- return filtered;
- }
- filterGeometries( selectedIDs, geometries ) {
- const ids = Array.from( selectedIDs );
- return Object.keys( geometries )
- .filter( ( key ) => ids.includes( parseInt( key, 10 ) ) )
- .reduce( ( obj, key ) => {
- return {
- ...obj,
- [ key ]: geometries[ key ],
- };
- }, {} );
- }
- isEasySelection( config ) {
- const matID = this.matID( config );
- const def = this.matIDNoConfig( config.modelID );
- if ( ! config.removePrevious && matID != def && this.selected[ matID ] )
- return true;
- }
- matID( config ) {
- if ( ! config.material ) return DEFAULT;
- const name = config.material.uuid || DEFAULT;
- return name.concat( ' - ' ).concat( config.modelID.toString() );
- }
- matIDNoConfig( modelID, material ) {
- let name = DEFAULT;
- if ( material ) name = material.uuid;
- return name.concat( ' - ' ).concat( modelID.toString() );
- }
- }
- const IfcElements = {
- 103090709: 'IFCPROJECT',
- 4097777520: 'IFCSITE',
- 4031249490: 'IFCBUILDING',
- 3124254112: 'IFCBUILDINGSTOREY',
- 3856911033: 'IFCSPACE',
- 25142252: 'IFCCONTROLLER',
- 32344328: 'IFCBOILER',
- 76236018: 'IFCLAMP',
- 90941305: 'IFCPUMP',
- 177149247: 'IFCAIRTERMINALBOX',
- 182646315: 'IFCFLOWINSTRUMENT',
- 263784265: 'IFCFURNISHINGELEMENT',
- 264262732: 'IFCELECTRICGENERATOR',
- 277319702: 'IFCAUDIOVISUALAPPLIANCE',
- 310824031: 'IFCPIPEFITTING',
- 331165859: 'IFCSTAIR',
- 342316401: 'IFCDUCTFITTING',
- 377706215: 'IFCMECHANICALFASTENER',
- 395920057: 'IFCDOOR',
- 402227799: 'IFCELECTRICMOTOR',
- 413509423: 'IFCSYSTEMFURNITUREELEMENT',
- 484807127: 'IFCEVAPORATOR',
- 486154966: 'IFCWINDOWSTANDARDCASE',
- 629592764: 'IFCLIGHTFIXTURE',
- 630975310: 'IFCUNITARYCONTROLELEMENT',
- 635142910: 'IFCCABLECARRIERFITTING',
- 639361253: 'IFCCOIL',
- 647756555: 'IFCFASTENER',
- 707683696: 'IFCFLOWSTORAGEDEVICE',
- 738039164: 'IFCPROTECTIVEDEVICE',
- 753842376: 'IFCBEAM',
- 812556717: 'IFCTANK',
- 819412036: 'IFCFILTER',
- 843113511: 'IFCCOLUMN',
- 862014818: 'IFCELECTRICDISTRIBUTIONBOARD',
- 900683007: 'IFCFOOTING',
- 905975707: 'IFCCOLUMNSTANDARDCASE',
- 926996030: 'IFCVOIDINGFEATURE',
- 979691226: 'IFCREINFORCINGBAR',
- 987401354: 'IFCFLOWSEGMENT',
- 1003880860: 'IFCELECTRICTIMECONTROL',
- 1051757585: 'IFCCABLEFITTING',
- 1052013943: 'IFCDISTRIBUTIONCHAMBERELEMENT',
- 1062813311: 'IFCDISTRIBUTIONCONTROLELEMENT',
- 1073191201: 'IFCMEMBER',
- 1095909175: 'IFCBUILDINGELEMENTPROXY',
- 1156407060: 'IFCPLATESTANDARDCASE',
- 1162798199: 'IFCSWITCHINGDEVICE',
- 1329646415: 'IFCSHADINGDEVICE',
- 1335981549: 'IFCDISCRETEACCESSORY',
- 1360408905: 'IFCDUCTSILENCER',
- 1404847402: 'IFCSTACKTERMINAL',
- 1426591983: 'IFCFIRESUPPRESSIONTERMINAL',
- 1437502449: 'IFCMEDICALDEVICE',
- 1509553395: 'IFCFURNITURE',
- 1529196076: 'IFCSLAB',
- 1620046519: 'IFCTRANSPORTELEMENT',
- 1634111441: 'IFCAIRTERMINAL',
- 1658829314: 'IFCENERGYCONVERSIONDEVICE',
- 1677625105: 'IFCCIVILELEMENT',
- 1687234759: 'IFCPILE',
- 1904799276: 'IFCELECTRICAPPLIANCE',
- 1911478936: 'IFCMEMBERSTANDARDCASE',
- 1945004755: 'IFCDISTRIBUTIONELEMENT',
- 1973544240: 'IFCCOVERING',
- 1999602285: 'IFCSPACEHEATER',
- 2016517767: 'IFCROOF',
- 2056796094: 'IFCAIRTOAIRHEATRECOVERY',
- 2058353004: 'IFCFLOWCONTROLLER',
- 2068733104: 'IFCHUMIDIFIER',
- 2176052936: 'IFCJUNCTIONBOX',
- 2188021234: 'IFCFLOWMETER',
- 2223149337: 'IFCFLOWTERMINAL',
- 2262370178: 'IFCRAILING',
- 2272882330: 'IFCCONDENSER',
- 2295281155: 'IFCPROTECTIVEDEVICETRIPPINGUNIT',
- 2320036040: 'IFCREINFORCINGMESH',
- 2347447852: 'IFCTENDONANCHOR',
- 2391383451: 'IFCVIBRATIONISOLATOR',
- 2391406946: 'IFCWALL',
- 2474470126: 'IFCMOTORCONNECTION',
- 2769231204: 'IFCVIRTUALELEMENT',
- 2814081492: 'IFCENGINE',
- 2906023776: 'IFCBEAMSTANDARDCASE',
- 2938176219: 'IFCBURNER',
- 2979338954: 'IFCBUILDINGELEMENTPART',
- 3024970846: 'IFCRAMP',
- 3026737570: 'IFCTUBEBUNDLE',
- 3027962421: 'IFCSLABSTANDARDCASE',
- 3040386961: 'IFCDISTRIBUTIONFLOWELEMENT',
- 3053780830: 'IFCSANITARYTERMINAL',
- 3079942009: 'IFCOPENINGSTANDARDCASE',
- 3087945054: 'IFCALARM',
- 3101698114: 'IFCSURFACEFEATURE',
- 3127900445: 'IFCSLABELEMENTEDCASE',
- 3132237377: 'IFCFLOWMOVINGDEVICE',
- 3171933400: 'IFCPLATE',
- 3221913625: 'IFCCOMMUNICATIONSAPPLIANCE',
- 3242481149: 'IFCDOORSTANDARDCASE',
- 3283111854: 'IFCRAMPFLIGHT',
- 3296154744: 'IFCCHIMNEY',
- 3304561284: 'IFCWINDOW',
- 3310460725: 'IFCELECTRICFLOWSTORAGEDEVICE',
- 3319311131: 'IFCHEATEXCHANGER',
- 3415622556: 'IFCFAN',
- 3420628829: 'IFCSOLARDEVICE',
- 3493046030: 'IFCGEOGRAPHICELEMENT',
- 3495092785: 'IFCCURTAINWALL',
- 3508470533: 'IFCFLOWTREATMENTDEVICE',
- 3512223829: 'IFCWALLSTANDARDCASE',
- 3518393246: 'IFCDUCTSEGMENT',
- 3571504051: 'IFCCOMPRESSOR',
- 3588315303: 'IFCOPENINGELEMENT',
- 3612865200: 'IFCPIPESEGMENT',
- 3640358203: 'IFCCOOLINGTOWER',
- 3651124850: 'IFCPROJECTIONELEMENT',
- 3694346114: 'IFCOUTLET',
- 3747195512: 'IFCEVAPORATIVECOOLER',
- 3758799889: 'IFCCABLECARRIERSEGMENT',
- 3824725483: 'IFCTENDON',
- 3825984169: 'IFCTRANSFORMER',
- 3902619387: 'IFCCHILLER',
- 4074379575: 'IFCDAMPER',
- 4086658281: 'IFCSENSOR',
- 4123344466: 'IFCELEMENTASSEMBLY',
- 4136498852: 'IFCCOOLEDBEAM',
- 4156078855: 'IFCWALLELEMENTEDCASE',
- 4175244083: 'IFCINTERCEPTOR',
- 4207607924: 'IFCVALVE',
- 4217484030: 'IFCCABLESEGMENT',
- 4237592921: 'IFCWASTETERMINAL',
- 4252922144: 'IFCSTAIRFLIGHT',
- 4278956645: 'IFCFLOWFITTING',
- 4288193352: 'IFCACTUATOR',
- 4292641817: 'IFCUNITARYEQUIPMENT',
- };
- class PropertyManager {
- constructor( state ) {
- this.state = state;
- }
- getExpressId( geometry, faceIndex ) {
- if ( ! geometry.index ) return;
- const geoIndex = geometry.index.array;
- return geometry.attributes[ IdAttrName ].getX( geoIndex[ 3 * faceIndex ] );
- }
- getItemProperties( modelID, id, recursive = false ) {
- return this.state.api.GetLine( modelID, id, recursive );
- }
- getAllItemsOfType( modelID, type, verbose ) {
- const items = [];
- const lines = this.state.api.GetLineIDsWithType( modelID, type );
- for ( let i = 0; i < lines.size(); i ++ ) items.push( lines.get( i ) );
- if ( verbose ) return items.map( ( id ) => this.state.api.GetLine( modelID, id ) );
- return items;
- }
- getPropertySets( modelID, elementID, recursive = false ) {
- const propSetIds = this.getAllRelatedItemsOfType(
- modelID,
- elementID,
- PropsNames.psets
- );
- return propSetIds.map( ( id ) =>
- this.state.api.GetLine( modelID, id, recursive )
- );
- }
- getTypeProperties( modelID, elementID, recursive = false ) {
- const typeId = this.getAllRelatedItemsOfType(
- modelID,
- elementID,
- PropsNames.type
- );
- return typeId.map( ( id ) => this.state.api.GetLine( modelID, id, recursive ) );
- }
- getSpatialStructure( modelID ) {
- const chunks = this.getSpatialTreeChunks( modelID );
- const projectID = this.state.api
- .GetLineIDsWithType( modelID, IFCPROJECT )
- .get( 0 );
- const project = this.newIfcProject( projectID );
- this.getSpatialNode( modelID, project, chunks );
- return project;
- }
- newIfcProject( id ) {
- return {
- expressID: id,
- type: 'IFCPROJECT',
- children: [],
- };
- }
- getSpatialTreeChunks( modelID ) {
- const treeChunks = {};
- this.getChunks( modelID, treeChunks, PropsNames.aggregates );
- this.getChunks( modelID, treeChunks, PropsNames.spatial );
- return treeChunks;
- }
- getChunks( modelID, chunks, propNames ) {
- const relation = this.state.api.GetLineIDsWithType( modelID, propNames.name );
- for ( let i = 0; i < relation.size(); i ++ ) {
- const rel = this.state.api.GetLine( modelID, relation.get( i ), false );
- const relating = rel[ propNames.relating ].value;
- const related = rel[ propNames.related ].map( ( r ) => r.value );
- if ( chunks[ relating ] == undefined ) {
- chunks[ relating ] = related;
- } else {
- chunks[ relating ] = chunks[ relating ].concat( related );
- }
- }
- }
- getSpatialNode( modelID, node, treeChunks ) {
- this.getChildren( modelID, node, treeChunks, PropsNames.aggregates );
- this.getChildren( modelID, node, treeChunks, PropsNames.spatial );
- }
- getChildren( modelID, node, treeChunks, propNames ) {
- const children = treeChunks[ node.expressID ];
- if ( children == undefined || children == null ) return;
- const prop = propNames.key;
- node[ prop ] = children.map( ( child ) => {
- const node = this.newNode( modelID, child );
- this.getSpatialNode( modelID, node, treeChunks );
- return node;
- } );
- }
- newNode( modelID, id ) {
- const typeID = this.state.models[ modelID ].types[ id ].toString();
- const typeName = IfcElements[ typeID ];
- return {
- expressID: id,
- type: typeName,
- children: [],
- };
- }
- getAllRelatedItemsOfType( modelID, id, propNames ) {
- const lines = this.state.api.GetLineIDsWithType( modelID, propNames.name );
- const IDs = [];
- for ( let i = 0; i < lines.size(); i ++ ) {
- const rel = this.state.api.GetLine( modelID, lines.get( i ) );
- const isRelated = this.isRelated( id, rel, propNames );
- if ( isRelated ) this.getRelated( rel, propNames, IDs );
- }
- return IDs;
- }
- getRelated( rel, propNames, IDs ) {
- const element = rel[ propNames.relating ];
- if ( ! Array.isArray( element ) ) IDs.push( element.value );
- else element.forEach( ( ele ) => IDs.push( ele.value ) );
- }
- isRelated( id, rel, propNames ) {
- const relatedItems = rel[ propNames.related ];
- if ( Array.isArray( relatedItems ) ) {
- const values = relatedItems.map( ( item ) => item.value );
- return values.includes( id );
- }
- return relatedItems.value === id;
- }
- }
- class TypeManager {
- constructor( state ) {
- this.state = state;
- }
- getAllTypes() {
- for ( const modelID in this.state.models ) {
- const types = this.state.models[ modelID ].types;
- if ( Object.keys( types ).length == 0 )
- this.getAllTypesOfModel( parseInt( modelID ) );
- }
- }
- getAllTypesOfModel( modelID ) {
- this.state.models[ modelID ].types;
- const elements = Object.keys( IfcElements ).map( ( e ) => parseInt( e ) );
- const types = this.state.models[ modelID ].types;
- elements.forEach( ( type ) => {
- const lines = this.state.api.GetLineIDsWithType( modelID, type );
- for ( let i = 0; i < lines.size(); i ++ ) types[ lines.get( i ) ] = type;
- } );
- }
- }
- let modelIdCounter = 0;
- class IFCModel extends Group {
- constructor( mesh, ifc ) {
- super();
- this.mesh = mesh;
- this.ifc = ifc;
- this.modelID = modelIdCounter ++;
- }
- setWasmPath( path ) {
- this.ifc.setWasmPath( path );
- }
- close( scene ) {
- this.ifc.close( this.modelID, scene );
- }
- getExpressId( geometry, faceIndex ) {
- return this.ifc.getExpressId( geometry, faceIndex );
- }
- getAllItemsOfType( type, verbose ) {
- return this.ifc.getAllItemsOfType( this.modelID, type, verbose );
- }
- getItemProperties( id, recursive = false ) {
- return this.ifc.getItemProperties( this.modelID, id, recursive );
- }
- getPropertySets( id, recursive = false ) {
- return this.ifc.getPropertySets( this.modelID, id, recursive );
- }
- getTypeProperties( id, recursive = false ) {
- return this.ifc.getTypeProperties( this.modelID, id, recursive );
- }
- getIfcType( id ) {
- return this.ifc.getIfcType( this.modelID, id );
- }
- getSpatialStructure() {
- return this.ifc.getSpatialStructure( this.modelID );
- }
- getSubset( material ) {
- return this.ifc.getSubset( this.modelID, material );
- }
- removeSubset( scene, material ) {
- this.ifc.removeSubset( this.modelID, scene, material );
- }
- createSubset( config ) {
- const modelConfig = {
- ...config,
- modelID: this.modelID,
- };
- return this.ifc.createSubset( modelConfig );
- }
- }
- class IFCManager {
- constructor() {
- this.state = {
- models: [],
- api: new IfcAPI(),
- };
- this.parser = new IFCParser( this.state );
- this.subsets = new SubsetManager( this.state );
- this.properties = new PropertyManager( this.state );
- this.types = new TypeManager( this.state );
- }
- async parse( buffer ) {
- const mesh = await this.parser.parse( buffer );
- this.types.getAllTypes();
- return new IFCModel( mesh, this );
- }
- setWasmPath( path ) {
- this.state.api.SetWasmPath( path );
- }
- setupThreeMeshBVH( computeBoundsTree, disposeBoundsTree, acceleratedRaycast ) {
- this.parser.initializeMeshBVH(
- computeBoundsTree,
- disposeBoundsTree,
- acceleratedRaycast
- );
- }
- close( modelID, scene ) {
- this.state.api.CloseModel( modelID );
- if ( scene ) scene.remove( this.state.models[ modelID ].mesh );
- delete this.state.models[ modelID ];
- }
- getExpressId( geometry, faceIndex ) {
- return this.properties.getExpressId( geometry, faceIndex );
- }
- getAllItemsOfType( modelID, type, verbose ) {
- return this.properties.getAllItemsOfType( modelID, type, verbose );
- }
- getItemProperties( modelID, id, recursive = false ) {
- return this.properties.getItemProperties( modelID, id, recursive );
- }
- getPropertySets( modelID, id, recursive = false ) {
- return this.properties.getPropertySets( modelID, id, recursive );
- }
- getTypeProperties( modelID, id, recursive = false ) {
- return this.properties.getTypeProperties( modelID, id, recursive );
- }
- getIfcType( modelID, id ) {
- const typeID = this.state.models[ modelID ].types[ id ];
- return IfcElements[ typeID.toString() ];
- }
- getSpatialStructure( modelID ) {
- return this.properties.getSpatialStructure( modelID );
- }
- getSubset( modelID, material ) {
- return this.subsets.getSubset( modelID, material );
- }
- removeSubset( modelID, scene, material ) {
- this.subsets.removeSubset( modelID, scene, material );
- }
- createSubset( config ) {
- return this.subsets.createSubset( config );
- }
- }
- class IFCLoader extends Loader {
- constructor( manager ) {
- super( manager );
- this.ifcManager = new IFCManager();
- }
- 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 {
- if ( typeof buffer == 'string' ) {
- throw new Error( 'IFC files must be given as a buffer!' );
- }
- onLoad( await scope.parse( buffer ) );
- } catch ( e ) {
- if ( onError ) {
- onError( e );
- } else {
- console.error( e );
- }
- scope.manager.itemError( url );
- }
- },
- onProgress,
- onError
- );
- }
- parse( buffer ) {
- return this.ifcManager.parse( buffer );
- }
- }
- export { IFCLoader };
- //# sourceMappingURL=IFCLoader.js.map
|