UNPKG

angular-3d-viewer

Version:
244 lines (228 loc) 9.79 kB
import { Coord3D } from '../geometry/coord3d.js'; import { Direction } from '../geometry/geometry.js'; import { Matrix } from '../geometry/matrix.js'; import { Transformation } from '../geometry/transformation.js'; import { LoadExternalLibrary } from '../io/externallibs.js'; import { RGBColorFromFloatComponents } from '../model/color.js'; import { Mesh } from '../model/mesh.js'; import { Property, PropertyGroup, PropertyType } from '../model/property.js'; import { Triangle } from '../model/triangle.js'; import { ImporterBase } from './importerbase.js'; import { ColorToMaterialConverter } from './importerutils.js'; export class ImporterIfc extends ImporterBase { constructor () { super (); this.ifc = null; } CanImportExtension (extension) { return extension === 'ifc'; } GetUpDirection () { return Direction.Y; } ClearContent () { this.expressIDToMesh = null; this.colorToMaterial = null; } ResetContent () { this.expressIDToMesh = new Map (); this.colorToMaterial = new ColorToMaterialConverter (this.model); } ImportContent (fileContent, onFinish) { if (this.ifc === null) { LoadExternalLibrary ('loaders/web-ifc-api-browser.js').then (() => { this.ifc = new WebIFC.IfcAPI (); this.ifc.Init ().then (() => { this.ImportIfcContent (fileContent); onFinish (); }); }).catch (() => { this.SetError ('Failed to load web-ifc.'); onFinish (); }); } else { this.ImportIfcContent (fileContent); onFinish (); } } ImportIfcContent (fileContent) { const fileBuffer = new Uint8Array (fileContent); const modelID = this.ifc.OpenModel (fileBuffer, { COORDINATE_TO_ORIGIN : true }); const ifcMeshes = this.ifc.LoadAllGeometry (modelID); for (let meshIndex = 0; meshIndex < ifcMeshes.size (); meshIndex++) { const ifcMesh = ifcMeshes.get (meshIndex); if (ifcMesh.geometries.size () > 0) { this.ImportIfcMesh (modelID, ifcMesh); } } this.ImportProperties (modelID); this.ifc.CloseModel (modelID); } ImportIfcMesh (modelID, ifcMesh) { let mesh = new Mesh (); mesh.SetName ('Mesh ' + ifcMesh.expressID.toString ()); let vertexOffset = 0; const ifcGeometries = ifcMesh.geometries; for (let geometryIndex = 0; geometryIndex < ifcGeometries.size (); geometryIndex++) { const ifcGeometry = ifcGeometries.get (geometryIndex); const ifcGeometryData = this.ifc.GetGeometry (modelID, ifcGeometry.geometryExpressID); const ifcVertices = this.ifc.GetVertexArray (ifcGeometryData.GetVertexData (), ifcGeometryData.GetVertexDataSize ()); const ifcIndices = this.ifc.GetIndexArray (ifcGeometryData.GetIndexData (), ifcGeometryData.GetIndexDataSize ()); const materialIndex = this.GetMaterialIndexByColor (ifcGeometry.color); const matrix = new Matrix (ifcGeometry.flatTransformation); const transformation = new Transformation (matrix); for (let i = 0; i < ifcVertices.length; i += 6) { const x = ifcVertices[i]; const y = ifcVertices[i + 1]; const z = ifcVertices[i + 2]; const coord = new Coord3D (x, y, z); const transformed = transformation.TransformCoord3D (coord); mesh.AddVertex (transformed); } // TODO: normals for (let i = 0; i < ifcIndices.length; i += 3) { const v0 = ifcIndices[i]; const v1 = ifcIndices[i + 1]; const v2 = ifcIndices[i + 2]; const triangle = new Triangle ( vertexOffset + v0, vertexOffset + v1, vertexOffset + v2 ); triangle.SetMaterial (materialIndex); mesh.AddTriangle (triangle); } vertexOffset += ifcVertices.length / 6; } this.expressIDToMesh.set (ifcMesh.expressID, mesh); this.model.AddMeshToRootNode (mesh); } ImportProperties (modelID) { const lines = this.ifc.GetLineIDsWithType (modelID, WebIFC.IFCRELDEFINESBYPROPERTIES); for (let i = 0; i < lines.size (); i++) { const relID = lines.get (i); const rel = this.ifc.GetLine (modelID, relID); if (Array.isArray (rel.RelatingPropertyDefinition)) { continue; } rel.RelatedObjects.forEach ((objectRelID) => { let element = null; if (this.expressIDToMesh.has (objectRelID.value)) { element = this.expressIDToMesh.get (objectRelID.value); } else { let propSetOwner = this.ifc.GetLine (modelID, objectRelID.value, true); if (propSetOwner.type === WebIFC.IFCBUILDING) { element = this.model; } } if (element === null) { return; } let propSetDef = rel.RelatingPropertyDefinition; let propSet = this.ifc.GetLine (modelID, propSetDef.value, true); if (!propSet || !propSet.HasProperties) { return; } let propertyGroup = new PropertyGroup (propSet.Name.value); propSet.HasProperties.forEach ((property) => { if (!property || !property.Name) { return; } if (!property.NominalValue || !property.NominalValue.constructor) { return; } if (property.type !== WebIFC.IFCPROPERTYSINGLEVALUE) { return; } let propertyName = this.GetIFCString (property.Name.value); let elemProperty = null; let strValue = null; switch (property.NominalValue.constructor.name) { case 'IfcText': case 'IfcLabel': case 'IfcIdentifier': case WebIFC.IFCLABEL: elemProperty = new Property (PropertyType.Text, propertyName, this.GetIFCString (property.NominalValue.value)); break; case 'IfcBoolean': case 'IfcLogical': strValue = 'Unknown'; if (property.NominalValue.value === 'T') { strValue = 'True'; } else if (property.NominalValue.value === 'F') { strValue = 'False'; } elemProperty = new Property (PropertyType.Text, propertyName, strValue); break; case 'IfcInteger': case 'IfcCountMeasure': elemProperty = new Property (PropertyType.Integer, propertyName, property.NominalValue.value); break; case 'IfcReal': case 'IfcLengthMeasure': case 'IfcPositiveLengthMeasure': case 'IfcAreaMeasure': case 'IfcVolumeMeasure': case 'IfcRatioMeasure': case 'IfcPositiveRATIOMeasure': case 'IfcMassMeasure': case 'IfcMassPerLengthMeasure': case 'IfcPlaneAngleMeasure': case 'IfcThermalTransmittanceMeasure': elemProperty = new Property (PropertyType.Number, propertyName, property.NominalValue.value); break; default: // TODO console.log (property); break; } if (elemProperty !== null) { propertyGroup.AddProperty (elemProperty); } }); if (propertyGroup.PropertyCount () > 0) { element.AddPropertyGroup (propertyGroup); } }); } } GetMaterialIndexByColor (ifcColor) { const color = RGBColorFromFloatComponents (ifcColor.x, ifcColor.y, ifcColor.z); const alpha = parseInt (ifcColor.w * 255.0, 10); return this.colorToMaterial.GetMaterialIndex (color.r, color.g, color.b, alpha); } GetIFCString (ifcString) { let decoded = this.DecodeIFCString (ifcString); if (decoded.length === 0) { decoded = '-'; } return decoded; } DecodeIFCString (ifcString) { // TODO: https://github.com/tomvandig/web-ifc/issues/58 const ifcUnicodeRegEx = /\\X2\\(.*?)\\X0\\/uig; let resultString = ifcString; let match = ifcUnicodeRegEx.exec (ifcString); while (match) { const unicodeChar = String.fromCharCode (parseInt (match[1], 16)); resultString = resultString.replace (match[0], unicodeChar); match = ifcUnicodeRegEx.exec (ifcString); } return resultString; } }