In this tutorial, I’m going to show you how to create a simple wall using IfcOpenShell WebAssembly.

We will be using some Python, Javascript, HTML and a dash of CSS. I won’t be explaining the complete basics of these technologies in this video because I want to focus on IfcOpenShell WebAssembly. However, if you would like me to create content showing how Python, Javascript and other programming languages can be used with OpenBIM, please let me know.

If you would like to follow along and play with the code, you can find the example here on Github.

First, let’s look at the final result and then we will go back and explain the different parts. Using Visual Studio Code and the Live Server extension I launch the example. Here’s the final result:

“But where is my AI-generated super automatic digital twin BIM model?!” you ask. Well, baby step… we have to start somewhere.

Let’s take a look at what’s happening behind the scenes to makes this happen.

If you’ve never seen HTML source before this may seem intimidating, but let’s look at the most relevant parts in bite-size chunks. At the top of the document we find the <head> tag which contains a <link> tag that points to style.css. This is simply loading our CSS file. As mentioned, we will not go in-depth into the CSS or styling of our page in this tutorial.

1
2
3
4
5
6
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="style.css">
  </head>

The next major tag is the <body> tag, which contains the rest of the page really. We will skip down to the <script> tags. These here are fetching a library called Pyodide which allows us to run Python code inside the browser:

19
20
<script type="text/javascript">document.querySelector("#status2").innerHTML = "Fetching pyodide";</script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/pyodide/v0.22.0a1/full/pyodide.js"></script>

Pretty neat! These next lines fetch the Three.js library which we use to show stuff in 3D in the browser:

22
23
24
25
26
27
<script type="importmap">
    {"imports": {"three": "https://unpkg.com/three@0.141.0/build/three.module.js",
                "OrbitControls": "https://unpkg.com/three@0.141.0/examples/jsm/controls/OrbitControls.js"}}
    </script>
    <script type="module">
    import * as THREE from 'three';

If we skip ahead a little to the more interesting bits, we find the main function. It first loads and initializes Pyodide and then loads IfcOpenShell as a python package.

34
35
36
37
38
39
40
41
42
async function main() {
    document.querySelector("#status2").innerHTML = "Initializing pyodide";
    pyodide = await loadPyodide();
    document.querySelector("#status2").innerHTML = "Loading package manager";
    await pyodide.loadPackage("micropip");
    await pyodide.loadPackage("numpy");
    const micropip = pyodide.pyimport("micropip");
    document.querySelector("#status2").innerHTML = "Loading IfcOpenShell (this may take a while)";
    await micropip.install("../IfcOpenShell-0.7.0-py3-none-any.whl");

Then we define a function that is bound to the onclick event of the only button on our page. This is where things get really interesting. On line 51 we run a python file called create_basic_wall.py. Let’s jump into that file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import ifcopenshell
from ifcopenshell.api import run
# Create a blank model
model = ifcopenshell.file()
# All projects must have one IFC Project element
project = run("root.create_entity", model, ifc_class="IfcProject", name="My Project")
# Geometry is optional in IFC, but because we want to use geometry in this example, let's define units
# Assigning without arguments defaults to metric units
run("unit.assign_unit", model)
# Let's create a modeling geometry context, so we can store 3D geometry (note: IFC supports 2D too!)
context = run("context.add_context", model, context_type="Model")
# In particular, in this example we want to store the 3D "body" geometry of objects, i.e. the body shape
body = run(
    "context.add_context", model,
    context_type="Model", context_identifier="Body", target_view="MODEL_VIEW", parent=context
)
# Create a site, building, and storey. Many hierarchies are possible.
site = run("root.create_entity", model, ifc_class="IfcSite", name="My Site")
building = run("root.create_entity", model, ifc_class="IfcBuilding", name="Building A")
storey = run("root.create_entity", model, ifc_class="IfcBuildingStorey", name="Ground Floor")
# Since the site is our top level location, assign it to the project
# Then place our building on the site, and our storey in the building
run("aggregate.assign_object", model, relating_object=project, product=site)
run("aggregate.assign_object", model, relating_object=site, product=building)
run("aggregate.assign_object", model, relating_object=building, product=storey)
# Let's create a new wall
wall = run("root.create_entity", model, ifc_class="IfcWall")
# Add a new wall-like body geometry, 5 meters long, 3 meters high, and 200mm thick
representation = run("geometry.add_wall_representation", model, context=body, length=5, height=3, thickness=0.2)
# Assign our new body geometry back to our wall
run("geometry.assign_representation", model, product=wall, representation=representation)
# Place our wall in the ground floor
run("spatial.assign_container", model, relating_structure=storey, product=wall)
# Return ifc model
model

This is a pure python file. Again, it’s running in the browser thanks to Pyodide. Here we can use IfcOpenShell using it’s Python interface to create a simple wall. Each line is commented, but essentially we create all the basic elements an IFC model needs, including a Project, Site, Building, Storey, etc. We add a wall to it and at the very end return the model variable, which in this case is an IFC file.

Going back to the HTML file, more precisely in the javascript code, we grab the model that was returned and generate mesh geometry we can load into Three.js. That’s basically what the rest of the code does.

So, what do you think? Could we build our own open-source browser-based BIM modeller using this technology? In a future tutorial, we will dive even deeper into an example of interactively drawing IFC walls in the browser.