I am trying to achieve categorisation of an IFC model using IfcOpenShell.
In the first step I extract the the attributes GlobalId
and ObjectType
from a list of IFC model elements. Then I would like to sort the information using the ObjectType
attribute, to receive the following information from the model:
Basiswand:Bestand 08.0:161894
{'GlobalId': '3vpWoB_K1EZ8RCaYmNGs6M', 'Element': 'Basiswand:Bestand 08.0:161894'}
{'GlobalId': '3vpWoB_K1EZ8RCaYmNGsB2', 'Element': 'Basiswand:Bestand 08.0:161894'}
Fenster 1-flg - Variabel
{'GlobalId': '3vpWoB_K1EZ8RCaYmNGssv', 'Element': 'Fenster 1-flg - Variabel'}
{'GlobalId': '3vpWoB_K1EZ8RCaYmNGsqI', 'Element': 'Fenster 1-flg - Variabel'}
The elements with same ObjectType
and with different GlobalId
should be combined in one group, to get a categorisation.
rows =[]
buildingelement = model.by_type('IfcBuildingElement')
for buildingelement in model.by_type('IfcBuildingElement'):
rows.append(str(buildingelement.GlobalId) + ': ' + str(buildingelement.ObjectType))
print(rows)
from operator import itemgetter
from itertools import groupby
# Sort by the desired field first
rows.sort(key=itemgetter('IfcBuildingElement'))
# Iterate in groups
for date, items in groupby(rows, key=itemgetter('IfcBuildingElement')):
print(date)
for i in items:
print(' ', i)
With above code, I get the error message Exception has occurred: TypeError string indices must be integers
.
In the first loop, you collect the elements of rows
as strings in the form '3vpWoB...: Basiswand...'
. For example:
['3vpWoB_K1EZ8RCaYmNGs6M: Basiswand:Bestand 08.0:161894',
'3vpWoB_K1EZ8RCaYmNGsB2: Basiswand:Bestand 08.0:161894',
'3vpWoB_K1EZ8RCaYmNGssv: Fenster 1-flg - Variabel',
'3vpWoB_K1EZ8RCaYmNGsqI: Fenster 1-flg - Variabel'
]
Then, when you sort and group with itemgetter
as key function, you would have to specify a position or range in the string. E.g. when you want to compare based on the 24th character use itemgetter(24)
or likewise to compare based on the trailing substring use itemgetter(slice(24,-1))
.
>>> '3vpWoB_K1EZ8RCaYmNGs6M: Basiswand:Bestand 08.0:161894'[24]
'B'
>>> '3vpWoB_K1EZ8RCaYmNGs6M: Basiswand:Bestand 08.0:161894'[24:-1]
'Basiswand:Bestand 08.0:161894'
If you try to use a string as index to get a substring, like in itemgetter('IfcBuildingElement')
you get the error you see.
>>> '3vpWoB_K1EZ8RCaYmNGs6M: Basiswand:Bestand 08.0:161894'['IfcBuildingElement']
TypeError: string indices must be integers
So in order to successfully use itemgetter('Element')
as key for sorting and grouping, you want to collect the rows as dictionaries of the form
{'GlobalId': '3vpWoB...', 'Element': 'Basiswand...'}
instead of strings. For example:
[{'GlobalId':'3vpWoB_K1EZ8RCaYmNGs6M', 'Element':'Basiswand:Bestand 08.0:161894'},
{'GlobalId':'3vpWoB_K1EZ8RCaYmNGsB2', 'Element':'Basiswand:Bestand 08.0:161894'},
{'GlobalId':'3vpWoB_K1EZ8RCaYmNGssv', 'Element':'Fenster 1-flg - Variabel'},
{'GlobalId':'3vpWoB_K1EZ8RCaYmNGsqI', 'Element':'Fenster 1-flg - Variabel'}
]
This could be achieved with the following code in the loop to collect the rows.
rows.append({'GlobalId': buildingelement.GlobalId, 'Element': buildingelement.ObjectType})