Skip to content

Instantly share code, notes, and snippets.

@stefkeB
Last active April 17, 2024 03:31
Show Gist options
  • Save stefkeB/86b6393a8d248579ac3a0fad8676d96e to your computer and use it in GitHub Desktop.
Save stefkeB/86b6393a8d248579ac3a0fad8676d96e to your computer and use it in GitHub Desktop.
Print IFC Hierarchy using IfcOpenShell and Python

About this example

This is a straightforward example of parsing an IFC file using IfcOpenShell. http://ifcopenshell.org

We load an IFC file from the command line argument, find the project and then step through its Spatial Hierarchy, following the Decomposes and IsContainedInSpatialStructure relations. Along the way, we print out the Properties and Quantities.

Run as follows:

python3 IFCOSPrintHierarchy.py <filename.ifc>

This will display something like this for the IfcOpenHouse.ifc sample file in the IfcOpenShell toolkit.

#12 = IfcProject "IfcOpenHouse" (02NgJh73z9H9p1e8asU8xp)
.  #18 = IfcSite "None" (3ouLTcA3r8P9cplyI5HVtV)
.  .  Pset_SiteCommon
.  .  .  TotalArea = 523.31397507897
.  .  #25 = IfcBuilding "None" (2CLK0Xn_T2iBVjws$YeMlK)
.  .  .  #32 = IfcBuildingStorey "None" (15VFoi2F54guzs2VUHeW$Z)
.  .  .  .  #34 = IfcWallStandardCase "South wall" (2eZ4QSizXEuRNpHMBut_dk)
.  .  .  .  #77 = IfcFooting "Footing" (2YmZTDa0T3h97PCthS2e$n)
.  .  .  .  #187 = IfcRoof "Roof" (2BBRbyGfz0oAPIZfmijoFU)
.  .  .  .  .  #188 = IfcSlab "South roof" (2N9x4fcqf7jPAPjLJiEAeu)
.  .  .  .  .  #189 = IfcSlab "North roof" (0XohIE5VnFEeXM8xcyKinZ)
.  .  .  .  #219 = IfcWallStandardCase "North wall" (3MI1ZgnBDDDBiVLjK3Pjw6)
.  .  .  .  #292 = IfcWallStandardCase "East wall" (2BwdmwOJTA3AXuw7xnEWxI)
.  .  .  .  #299 = IfcWallStandardCase "West wall" (2NGpkeicv1wxe44d6RlRW4)
.  .  .  .  #2609 = IfcStairFlight "None" (3Kt_zAPyX1DPS4ICfjKmJe)
.  .  .  .  #2687 = IfcDoor "None" (2yg42GmAP2FPvawq2Wx0_t)
.  .  .  .  .  Door type
.  .  .  .  #2756 = IfcWindow "None" (1I6DWQZ398jPufhllK9p9v)
.  .  .  .  .  #2787 = IfcMember "None" (3AB2FCwEbFJRjTNrrzBzRx)
.  .  .  .  .  #2793 = IfcMember "None" (1NOhpy0kH7GhQhwTkNsTkW)
.  .  .  .  .  #2804 = IfcMember "None" (0wIkMD7fX4Gx1TviaIBg7B)
.  .  .  .  .  #2810 = IfcMember "None" (3bbwac$Qz9XfP4$vwRZn_n)
.  .  .  .  .  #2830 = IfcPlate "None" (3vj_YCbVX0xf$s9BJ1jfni)
.  .  .  .  #2837 = IfcWindow "None" (1CDtdlyp142Ra7nrHrHp3n)
.  .  .  .  .  #2863 = IfcMember "None" (0bYSqmJFH9B9iQineRza0t)
.  .  .  .  .  #2869 = IfcMember "None" (0iEQdvyZbCD9QwMyZcoWbe)
.  .  .  .  .  #2875 = IfcMember "None" (0QnU_5Wv10efdpZOlt_PdH)
.  .  .  .  .  #2881 = IfcMember "None" (2Rr$NdMOj5ehIfklzFoux3)
.  .  .  .  .  #2901 = IfcPlate "None" (2vbNIVlI50GO0a4IjZdaws)
.  .  .  .  #2908 = IfcWindow "None" (3R3qWEaU905At4mDtVMMcL)
.  .  .  .  .  #2934 = IfcMember "None" (1r8BKeb7D99xtMg_MHX9gH)
.  .  .  .  .  #2940 = IfcMember "None" (1aOuLtEW9C1gu921pG7NmQ)
.  .  .  .  .  #2946 = IfcMember "None" (2wcyJCbj99oA87M9J1$pwo)
.  .  .  .  .  #2952 = IfcMember "None" (1Jfizzbvb9vOzFvdiixKEY)
.  .  .  .  .  #2972 = IfcPlate "None" (2JKY$Y_Af9g9P3eOabCTlE)
.  .  .  .  #2979 = IfcWindow "None" (1rIP5j0CrBBgIVVNROt1U8)
.  .  .  .  .  #3005 = IfcMember "None" (3IkQrRLgTEmgIYqQ6CYj5j)
.  .  .  .  .  #3011 = IfcMember "None" (131EGjUgnE1eBcsIJj2NWq)
.  .  .  .  .  #3017 = IfcMember "None" (0a$SU8COT7dQTEqIBq1iIm)
.  .  .  .  .  #3023 = IfcMember "None" (0jHdJ0WUH0OPZ7Tu5W_b70)
.  .  .  .  .  #3043 = IfcPlate "None" (1SDocEeHH9uBO_5OZEJJ9h)
.  .  .  .  #3050 = IfcWindow "None" (1dmSFt7FTBjwBVhxk9UIwv)
.  .  .  .  .  #3076 = IfcMember "None" (1J1PQJXqz6oPlCr02UnY5V)
.  .  .  .  .  #3082 = IfcMember "None" (39v3BUiu1EnAY67Ev89uee)
.  .  .  .  .  #3088 = IfcMember "None" (0LIKNCiHr4pgJvgjnj77Ue)
.  .  .  .  .  #3094 = IfcMember "None" (2wTCMQ71P1ovhnMbcvrSa8)
.  .  .  .  .  #3114 = IfcPlate "None" (1QRDIGdcjDhxuxkcU7tT1Z)

Acknowledgements

This is expanded from the nice tutorial by Dion @Moult https://thinkmoult.com/using-ifcopenshell-parse-ifc-files-python.html

import sys
import ifcopenshell
# Indent
def indent(level):
spacer = '. '
for i in range(level):
print(spacer,end='')
# PropertySet
def print_element_properties(property_set, level):
indent(level)
print(property_set.Name)
for prop in property_set.HasProperties:
if prop.is_a('IfcPropertySingleValue'):
indent(level + 1)
print(prop.Name + " = " + str(prop.NominalValue.wrappedValue))
# QuantitySet
def print_element_quantities(quantity_set, level):
indent(level)
print(quantity_set.Name)
# the individual quantities
for quantity in quantity_set.Quantities:
if quantity.is_a('IfcQuantityLength'):
indent(level + 1)
print(quantity.Name + ' = ' + str(quantity.LengthValue))
elif quantity.is_a('IfcQuantityArea'):
indent(level + 1)
print(quantity.Name + ' = ' + str(quantity.AreaValue))
elif quantity.is_a('IfcQuantityVolume'):
indent(level + 1)
print(quantity.Name + ' = ' + str(quantity.VolumeValue))
elif quantity.is_a('IfcQuantityCount'):
indent(level + 1)
print(quantity.Name + ' = ' + str(quantity.CountValue))
else:
indent(level + 1)
print(quantity.Name)
# Type
def print_element_type(type, level):
indent(level)
print(type.Name)
# Entity
def print_element(element, level):
indent(level)
# element
print('#' + str(element.id()) + ' = ' + element.is_a() + ' "' + str(element.Name) + '" (' + element.GlobalId + ')' )
for definition in element.IsDefinedBy:
if definition.is_a('IfcRelDefinesByProperties'):
related_data = definition.RelatingPropertyDefinition
# the individual properties/quantities
if related_data.is_a('IfcPropertySet'):
print_element_properties(related_data, level + 1)
elif related_data.is_a('IfcElementQuantity'):
print_element_quantities(related_data, level + 1)
if definition.is_a('IfcRelDefinesByType'):
print_element_type(definition.RelatingType, level + 1)
# follow Spatial relation
if (element.is_a('IfcSpatialStructureElement')):
for rel in element.ContainsElements:
relatedElements = rel.RelatedElements
for child in relatedElements:
print_element(child, level + 1)
# follow Aggregation Relation
if (element.is_a('IfcObjectDefinition')):
for rel in element.IsDecomposedBy:
relatedObjects = rel.RelatedObjects
for child in relatedObjects:
print_element(child, level + 1)
def main():
# import IFC File
args = sys.argv
ifc_file = ifcopenshell.open(args[1])
items = ifc_file.by_type('IfcProject')
for item in items:
print_element(item, 0)
if __name__ == "__main__":
main()
#12 = IfcProject "IfcOpenHouse" (02NgJh73z9H9p1e8asU8xp)
. #18 = IfcSite "None" (3ouLTcA3r8P9cplyI5HVtV)
. . Pset_SiteCommon
. . . TotalArea = 523.31397507897
. . #25 = IfcBuilding "None" (2CLK0Xn_T2iBVjws$YeMlK)
. . . #32 = IfcBuildingStorey "None" (15VFoi2F54guzs2VUHeW$Z)
. . . . #34 = IfcWallStandardCase "South wall" (2eZ4QSizXEuRNpHMBut_dk)
. . . . #77 = IfcFooting "Footing" (2YmZTDa0T3h97PCthS2e$n)
. . . . #187 = IfcRoof "Roof" (2BBRbyGfz0oAPIZfmijoFU)
. . . . . #188 = IfcSlab "South roof" (2N9x4fcqf7jPAPjLJiEAeu)
. . . . . #189 = IfcSlab "North roof" (0XohIE5VnFEeXM8xcyKinZ)
. . . . #219 = IfcWallStandardCase "North wall" (3MI1ZgnBDDDBiVLjK3Pjw6)
. . . . #292 = IfcWallStandardCase "East wall" (2BwdmwOJTA3AXuw7xnEWxI)
. . . . #299 = IfcWallStandardCase "West wall" (2NGpkeicv1wxe44d6RlRW4)
. . . . #2609 = IfcStairFlight "None" (3Kt_zAPyX1DPS4ICfjKmJe)
. . . . #2687 = IfcDoor "None" (2yg42GmAP2FPvawq2Wx0_t)
. . . . . Door type
. . . . #2756 = IfcWindow "None" (1I6DWQZ398jPufhllK9p9v)
. . . . . #2787 = IfcMember "None" (3AB2FCwEbFJRjTNrrzBzRx)
. . . . . #2793 = IfcMember "None" (1NOhpy0kH7GhQhwTkNsTkW)
. . . . . #2804 = IfcMember "None" (0wIkMD7fX4Gx1TviaIBg7B)
. . . . . #2810 = IfcMember "None" (3bbwac$Qz9XfP4$vwRZn_n)
. . . . . #2830 = IfcPlate "None" (3vj_YCbVX0xf$s9BJ1jfni)
. . . . #2837 = IfcWindow "None" (1CDtdlyp142Ra7nrHrHp3n)
. . . . . #2863 = IfcMember "None" (0bYSqmJFH9B9iQineRza0t)
. . . . . #2869 = IfcMember "None" (0iEQdvyZbCD9QwMyZcoWbe)
. . . . . #2875 = IfcMember "None" (0QnU_5Wv10efdpZOlt_PdH)
. . . . . #2881 = IfcMember "None" (2Rr$NdMOj5ehIfklzFoux3)
. . . . . #2901 = IfcPlate "None" (2vbNIVlI50GO0a4IjZdaws)
. . . . #2908 = IfcWindow "None" (3R3qWEaU905At4mDtVMMcL)
. . . . . #2934 = IfcMember "None" (1r8BKeb7D99xtMg_MHX9gH)
. . . . . #2940 = IfcMember "None" (1aOuLtEW9C1gu921pG7NmQ)
. . . . . #2946 = IfcMember "None" (2wcyJCbj99oA87M9J1$pwo)
. . . . . #2952 = IfcMember "None" (1Jfizzbvb9vOzFvdiixKEY)
. . . . . #2972 = IfcPlate "None" (2JKY$Y_Af9g9P3eOabCTlE)
. . . . #2979 = IfcWindow "None" (1rIP5j0CrBBgIVVNROt1U8)
. . . . . #3005 = IfcMember "None" (3IkQrRLgTEmgIYqQ6CYj5j)
. . . . . #3011 = IfcMember "None" (131EGjUgnE1eBcsIJj2NWq)
. . . . . #3017 = IfcMember "None" (0a$SU8COT7dQTEqIBq1iIm)
. . . . . #3023 = IfcMember "None" (0jHdJ0WUH0OPZ7Tu5W_b70)
. . . . . #3043 = IfcPlate "None" (1SDocEeHH9uBO_5OZEJJ9h)
. . . . #3050 = IfcWindow "None" (1dmSFt7FTBjwBVhxk9UIwv)
. . . . . #3076 = IfcMember "None" (1J1PQJXqz6oPlCr02UnY5V)
. . . . . #3082 = IfcMember "None" (39v3BUiu1EnAY67Ev89uee)
. . . . . #3088 = IfcMember "None" (0LIKNCiHr4pgJvgjnj77Ue)
. . . . . #3094 = IfcMember "None" (2wTCMQ71P1ovhnMbcvrSa8)
. . . . . #3114 = IfcPlate "None" (1QRDIGdcjDhxuxkcU7tT1Z)
@talyacode
Copy link

someone ever tried it in js ?

@autra
Copy link

autra commented Feb 21, 2024

I replaced L17 by :

            val = str(prop.NominalValue) if prop.NominalValue is not None else '<No Value>'
            print(prop.Name + " = " + val)

because apparently NominalValue can be None.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment