Skip to main content

πŸ“ƒ Properties

Introduction#

🧊 One of the coolest thing you can do is traverse the IFC file and fetch the relevant information, web-ifc provides us with the capability to read and write IFC file from within the browser, In this tutorial we will Read Properties from IFC file and Output it on Frontend.

πŸ’Ύ This tutorial will help us to get the Analysis of IFC without a viewer😎.

πŸ‘‰ You can check out the final result deployed here and the full code here.

πŸ“š There are several types of properties in the IFC scheme, each with a specific purpose, and IFC.js can get all of them. Some of the most common are:

Native properties

Specific to each IFC class.

Type properties

Describe properties of all elements of the same type (e.g. all envelope walls of a particular type).

Material properties

Describes all the materials that make up the layers of that element.

Property sets

Arbitrary sets of user-defined properties. There may be multiple sets of properties associated with one or more elements. Each property set contains an arbitrary group of properties related to each other.

Quantity sets

Sets of properties describing the dimensions of the elements to which they refer. Although it would also be possible to infer element dimensions implicitly from the geometry definition, this explicit description makes it much easier to create applications that measure IFC models.

πŸš΄β€β™‚οΈ But enough theory! Let's get down to work.

How to do it#

Setting up#

Imports and Global Variables

import {
IfcAPI, IFCRELDEFINESBYPROPERTIES
} from "web-ifc/web-ifc-api";
..
// We will show our properties in table, we will talk about this in FrontEnd Section
const table = document.createElement("table");
..
..

Reading File

We will read file and call LoadFileData() and send IFC data as Text

fetch("../../../../IFC/01.ifc")
.then((response) => response.text())
.then((data) => {
// This will send the file data to our LoadFileData method
LoadFileData(data);
});

Creating a method which will be called for getting Element Properties All the code for getting Element Data goes inside it

function getPropertyWithExpressId(modelID=0) {
// Clearing if previous values present
const prop = document.getElementById("properties");
prop.innerHTML = "";
table.innerHTML = "";
// Getting the Element ID from User and parsing it to
const elementID = parseInt(document.getElementById("expressIDLabel").value);
..
// Getting Element Data - Refer Below
..
// Appending Table to our Div
prop.appendChild(table);
}

Getting Element Data#

GetAllLines() gives you all the lines, but what if you want to get a line according to that ElementID?

GetLines() can be used at times like these when we know ElementID and want the data for it.

πŸ”’ Getting Element Data by ElementID

// If third parameter is added as true, we get a flatten result
const element = ifcapi.GetLine(modelID, elementID);
// Now you can fetch GUID of that Element
const guid = element.GlobalId.value;

🀨 But what is Element?

Every Entity can be considered as an Element which has it's own unique ElementID, by using the above code we can get various values that are contained in that Element Data. Few values that you can get and what we will output on Frontend are

  • GUID : Globally Unique Identifier for the Element
  • Name - Name given to that Element
  • IfcType - It refers to the type of Element it is e.g. IFCWALL,IFCWINDOW
  • IfcObjectType - Defines the specific information about a type
  • Tag - The IFC tag feature lets you assign IFC properties to the objects when they are exported to IFC
  • and Many More

πŸ€– Element Data

Please Ignore createRowInTable() as of now, it will be covered in Frontend Section

Just remember 1st parameter is the Label and the 2nd parameter is the respected value.

// Now you can fetch GUID of that Element
const guid = element.GlobalId.value;
createRowInTable("GUID", guid);
const name = element.Name.value;
createRowInTable("Name", name);
const ifcType = element.__proto__.constructor.name;
createRowInTable("IfcType", ifcType);
const type = element.ObjectType.value;
createRowInTable("Object Type", type);
const tag = element.Tag.value;
createRowInTable("Tag", tag);

Element Properties#

Now that we have Element Data, we need to get the properties of that Element, the way IFC is structured we can't directly get Properties like we got Element Data, we have to fetch Lines which are Property Data and filter it according to the ExpressID we want.

Feels too hectic? Don't worry, web-ifc with it's Native Speed gets us the data easily.

1️⃣ Getting All Lines with Type

We will get all Lines that has relation as properties with Elements i.e IFCRELDEFINESBYPROPERTIES.

// Get all the propertyset lines in the IFC file
let lines = ifcapi.GetLineIDsWithType(modelID, IFCRELDEFINESBYPROPERTIES);

2️⃣ Get ElementID of Property Sets

  • After getting the lines we will fetch the ElementID from those lines, next we use those ElementID to get the Element Data same like what we have done above.
  • Next, we will go through the Element Data and find out the RelatedObjects and if those RelatedObjects contain the ElementID for which we are trying to find properties we save them in a local arrayπŸ₯³
// In the below array we will store the IDs of the Property Sets found
let propSetIds = [];
for (let i = 0; i < lines.size(); i++) {
// Getting the ElementID from Lines
let relatedID = lines.get(i);
// Getting Element Data using the relatedID
let relDefProps = ifcapi.GetLine(modelID, relatedID);
// Boolean for Getting the IDs if relevant IDs are present
let foundElement = false;
// RelatedObjects is a property that is an Array of Objects.
// The way IFC is structured, Entities that use same property are included inside RelatedObjects
// We Search inside RelatedObjects if our ElementID is present or not
relDefProps.RelatedObjects.forEach((relID) => {
if (relID.value === elementID) {
foundElement = true;
}
});
if (foundElement) {
// Relevant IDs are found we then we go to RelatingPropertyDefinition
// RelatingPropertyDefinition contain the IDs of Property Sets
// But they should not be array, hence using (!Array.isArray())
if (!Array.isArray(relDefProps.RelatingPropertyDefinition)) {
console.log("Found");
let handle = relDefProps.RelatingPropertyDefinition;
// Storing and pushing the IDs found in propSetIds Array
propSetIds.push(handle.value);
}
}
}

βš–οΈ The heavy lifting has been done, now we will repeat few of the steps.

3️⃣ Getting Property Sets from their ID

  • Yes you are right, getting Element Data using Element IDs!, now we will use the IDs from propSetIds and Get Data.
  • Then we will check whether they have properties i.e. check if they contain Nominal Values
  • If you want you can store Property Sets but in our case we will show them on Frontend, so no need to store.
// Getting the Property Sets from their IDs
let propsets = propSetIds.map((id) => ifcapi.GetLine(modelID, id, true));
propsets.forEach((set) => {
// There can multiple Property Sets
set.HasProperties.forEach((p) => {
// We will check if the Values that are present are not null
if (p.NominalValue != null) {
// This is an e.g. filter, you can write down your various conditions to modify the result
if (p.NominalValue.label === "IFCBOOLEAN") {
// We will talk about this function in Frontend Part
createRowInTable(p.Name.value, p.NominalValue.value);
} else {
// We will talk about this function in Frontend Part
createRowInTable(p.NominalValue.label, p.NominalValue.value);
}
}
});
});

Your complete code until now should look like this

FrontEnd#

We are using this example as a base and will be making additions to it

πŸ€– Method to Create Rows We will create a function to create rows dynamically, this will help us to insert data directly into table and show it on the FrontEnd.

  • We will now use the table variable we had created globally while doing the setup
function createRowInTable(label, value) {
// Create a New Row Element
const row = document.createElement("tr");
// Add Label to 1st Coloumn and Value to 2nd Coloumn
row.innerHTML = "<td>" + label + "</td><td>" + value + "</td>";
// Appending the Row to Table - It means inserting Row inside Table
table.appendChild(row);
}

πŸ”³ Your HTML Code inside <body> should like this

<div class="file-opener">
<a class="invisible" id="save-button">Save JSON</a>
<button class="basic-button" id="file-opener-button">Open IFC</button>
</div>
<input class="invisible" id="file-input" type="file" />
<div class="general-container">
<div class="container" id="left-container"></div>
<div class="separator"></div>
<div class="container" id="right-container">
<div class="ifc-container">
<pre id="json"></pre>
</div>
<div class="property-container">
<div class="input-container">
<input id="expressIDLabel" />
<!-- On Clicking this button we call getPropertyWithExpressId() -->
<button class="property-button" onclick="getPropertyWithExpressId()">Get Properties</button>
</div>
<!-- This is the area where our properties will be shown -->
<pre id="properties"></pre>
</div>
</div>
</div>

🎨 Now Styling

Containers:

.ifc-container {
height: 60%;
border-bottom: 5px solid #f3f4f6;
overflow: auto;
}
.property-container {
overflow: auto;
height: 40%;
}
.input-container {
padding: 20px;
border-bottom: 5px solid #f3f4f6;
}
#properties {
padding: 8px;
}

Input Field and button:

input {
font-size: 14px;
padding: 4px;
width: 60%;
border-radius: 8px;
}
.property-button {
margin-left: 20px;
font-size: 14px;
padding: 8px 12px;
background-color: #e6e6e6;
border: unset;
border-radius: 8px;
}
.property-button:hover {
box-shadow: 0 10px 20px 8px #e6e6e6;
background-color: white;
transition: 0.2s;
}

Table and Table Row:

table {
width: 100%;
border-collapse: collapse;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
td {
border: 1px solid black;
padding: 8px;
}

Next steps#

πŸŽ‰ Congratulations! You should now be able to traverse any IFC and extract the properties you are looking for.

You can use the web-ifc APIs to get Material Data as well and many more to query the lines according to your need.