Skip to content

Commit 7ca3a30

Browse files
Fixed problem with multiple IfcOwnerHistory copies
1 parent 094f6ab commit 7ca3a30

File tree

6 files changed

+781915
-3165
lines changed

6 files changed

+781915
-3165
lines changed

ifcjson/ifc2json4.py

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,20 @@ def spf2Json(self):
5353
self.entityToDict(entity)
5454
for key in self.id_objects:
5555
jsonObjects.append(self.id_objects[key])
56-
return {'file_schema': 'IFC.JSON4','data': jsonObjects}
56+
return {
57+
'file_schema': 'IFC.JSON4',
58+
'originatingSystem': 'IFC2JSON_python',
59+
'data': jsonObjects
60+
}
5761

5862
@functools.lru_cache(maxsize=maxCache)
5963
def entityToDict(self, entity):
6064

61-
# Entitie names must be in camelCase
62-
entityType = entity.is_a()
63-
entityType = entityType[0].lower() + entityType[1:]
65+
# Entity names must be in camelCase
66+
entityType = common.toLowerCamelcase(entity.is_a())
67+
6468
entityAttributes = entity.__dict__
65-
69+
6670
ref = {
6771
"type": entityType
6872
}
@@ -71,18 +75,20 @@ def entityToDict(self, entity):
7175
if entityType == 'ifcOwnerHistory':
7276
if not entity.id() in self.ownerHistories:
7377
self.ownerHistories[entity.id()] = guid.new()
74-
entityAttributes["globalId"] = self.ownerHistories[entity.id()]
78+
entityAttributes["GlobalId"] = self.ownerHistories[entity.id()]
7579

7680
# Add missing GlobalId to IfcGeometricRepresentationContext
7781
if entityType == 'ifcGeometricRepresentationContext':
7882
if not entity.id() in self.representationContexts:
7983
self.representationContexts[entity.id()] = guid.new()
80-
entityAttributes["globalId"] = self.representationContexts[entity.id()]
84+
entityAttributes["GlobalId"] = self.representationContexts[entity.id()]
8185

82-
# check for globalid
86+
# All objects with a GlobalId must be referenced, all others nested
8387
if "GlobalId" in entityAttributes:
8488
uuid = guid.split(guid.expand(entityAttributes["GlobalId"]))[1:-1]
8589
ref["ref"] = uuid
90+
91+
# Every object must be added to the root array only once
8692
if not entityAttributes["GlobalId"] in self.id_objects:
8793
d = {
8894
"type": entityType
@@ -96,36 +102,39 @@ def entityToDict(self, entity):
96102
if entityType == 'ifcGeometricRepresentationContext':
97103
d["globalId"] = guid.split(guid.expand(self.representationContexts[entity.id()]))[1:-1]
98104

99-
for i in range(0,len(entity)):
100-
attr = entity.attribute_name(i)
105+
for attr in entityAttributes:
101106
attrKey = common.toLowerCamelcase(attr)
102107
if attr == "GlobalId":
103108
d[attrKey] = uuid
104109
else:
105-
if attr in entityAttributes:
106-
jsonValue = self.getEntityValue(entityAttributes[attr])
107-
if jsonValue:
108-
if ((entityType == 'ifcOwnerHistory') and (attr == "GlobalId")):
109-
pass
110-
else:
111-
d[attrKey] = jsonValue
112-
if entityAttributes[attr] == None:
113-
continue
114-
elif isinstance(entityAttributes[attr], ifcopenshell.entity_instance):
115-
d[attrKey] = self.entityToDict(entityAttributes[attr])
116-
elif isinstance(entityAttributes[attr], tuple):
117-
subEnts = []
118-
for subEntity in entityAttributes[attr]:
119-
if isinstance(subEntity, ifcopenshell.entity_instance):
120-
subEntJson = self.entityToDict(subEntity)
121-
if subEntJson:
122-
subEnts.append(subEntJson)
123-
else:
124-
subEnts.append(subEntity)
125-
if len(subEnts) > 0:
126-
d[attrKey] = subEnts
110+
111+
# Line numbers are not part of IFC JSON
112+
if attr == 'id':
113+
continue
114+
115+
jsonValue = self.getEntityValue(entityAttributes[attr])
116+
if jsonValue:
117+
if ((entityType == 'ifcOwnerHistory') and (attr == "GlobalId")):
118+
pass
127119
else:
128-
d[attrKey] = entityAttributes[attr]
120+
d[attrKey] = jsonValue
121+
if entityAttributes[attr] == None:
122+
continue
123+
elif isinstance(entityAttributes[attr], ifcopenshell.entity_instance):
124+
d[attrKey] = self.entityToDict(entityAttributes[attr])
125+
elif isinstance(entityAttributes[attr], tuple):
126+
subEnts = []
127+
for subEntity in entityAttributes[attr]:
128+
if isinstance(subEntity, ifcopenshell.entity_instance):
129+
subEntJson = self.entityToDict(subEntity)
130+
if subEntJson:
131+
subEnts.append(subEntJson)
132+
else:
133+
subEnts.append(subEntity)
134+
if len(subEnts) > 0:
135+
d[attrKey] = subEnts
136+
else:
137+
d[attrKey] = entityAttributes[attr]
129138
self.id_objects[entityAttributes["GlobalId"]] = d
130139
return ref
131140
else:

ifcjson/ifc2json5a.py

Lines changed: 44 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
'ContainsElements'
4343
}
4444

45+
4546
class IFC2JSON5a:
4647
def __init__(self, ifcFilePath):
4748
self.ifcFilePath = ifcFilePath
@@ -55,7 +56,7 @@ def __init__(self, ifcFilePath):
5556

5657
def spf2Json(self):
5758
objData = self.getObjData(self.ifcFilePath)
58-
jsonObjects= []
59+
jsonObjects = []
5960
# entityIter = iter(self.ifcModel)
6061
# for entity in entityIter:
6162
# # print(dir(entity))
@@ -68,23 +69,25 @@ def spf2Json(self):
6869
jsonObjects.append(self.id_objects[key])
6970
for key in self.representations:
7071
jsonObjects.append(self.representations[key])
71-
return {'file_schema': 'IFC.JSON5a','data': jsonObjects}
72+
return {
73+
'file_schema': 'IFC.JSON5a',
74+
'originatingSystem': 'IFC2JSON_python',
75+
'data': jsonObjects
76+
}
7277

7378
def entityToDict(self, entity, objData, parent=None):
74-
entityAttributes = entity.__dict__
75-
# inverseAttributes = explicitInverseAttributes.intersection(entity.wrapped_data.get_inverse_attribute_names())
76-
entityType = entity.is_a()
77-
entityType = entityType[3:]
7879

79-
# Entitie names must be in camelCase
80-
entityType = entityType[0].lower() + entityType[1:]
80+
# Entity names must be in camelCase and stripped of Ifc prefix
81+
entityType = common.toLowerCamelcase(entity.is_a()[3:])
8182

83+
entityAttributes = entity.__dict__
84+
# inverseAttributes = explicitInverseAttributes.intersection(entity.wrapped_data.get_inverse_attribute_names())
85+
8286
ref = {
8387
'type': entityType
8488
}
8589

86-
87-
# determine if object needs to be nested or referenced
90+
# All objects with a GlobalId must be referenced, all others nested
8891
reference = False
8992
if 'GlobalId' in entityAttributes:
9093
reference = True
@@ -95,15 +98,13 @@ def entityToDict(self, entity, objData, parent=None):
9598
'type': entityType
9699
}
97100

98-
99101
# for inverseAttribute in inverseAttributes:
100102
# invAtt = {}
101103
# attributeObject = getattr(entity, inverseAttribute)
102104
# attr = inverseAttribute
103105
# attrKey = common.toLowerCamelcase(attr)
104106
# print(attributeObject)
105-
106-
# print("yeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeees")
107+
107108
# if isinstance(attributeObject, ifcopenshell.entity_instance):
108109
# print("dsicnkjcnkdjvnskjcnkvjnfjkn")
109110
# # if attributeObject.is_a == 'IfcRelAggregates':
@@ -132,7 +133,6 @@ def entityToDict(self, entity, objData, parent=None):
132133
# # print(inverseAttribute)
133134
# d[inverseAttribute] = invAtt
134135

135-
136136
# if hasattr(entity, 'IsDefinedBy'):
137137
# decomposedBy = entity.IsDefinedBy
138138
# invAtt = []
@@ -150,7 +150,6 @@ def entityToDict(self, entity, objData, parent=None):
150150
# if invAtt:
151151
# d['IsDefinedBy'] = invAtt
152152

153-
154153
if hasattr(entity, 'IsDefinedBy'):
155154
relations = entity.IsDefinedBy
156155
# p = {}
@@ -159,56 +158,57 @@ def entityToDict(self, entity, objData, parent=None):
159158
definition = rel.RelatingPropertyDefinition
160159
if definition.is_a() == 'IfcPropertySet':
161160
relatedObjects = definition.HasProperties
162-
for relatedObject in relatedObjects:
161+
for relatedObject in relatedObjects:
163162
value = relatedObject.NominalValue.wrappedValue
164163
if value and value != '':
165-
d[common.toLowerCamelcase(relatedObject.Name)] = value
164+
d[common.toLowerCamelcase(
165+
relatedObject.Name)] = value
166166
elif definition.is_a() == 'IfcElementQuantity':
167167
relatedObjects = definition.Quantities
168-
for relatedObject in relatedObjects:
168+
for relatedObject in relatedObjects:
169169
value = relatedObject.AreaValue
170170
if value and value != '':
171-
d[common.toLowerCamelcase(relatedObject.Name)] = value
171+
d[common.toLowerCamelcase(
172+
relatedObject.Name)] = value
172173
else:
173174
print('Skipped: ' + str(definition))
174175
else:
175176
print('Skipped: ' + str(rel))
176177
# if p:
177178
# d['properties'] = p
178-
179179

180180
if hasattr(entity, 'IsDecomposedBy'):
181181
decomposedBy = entity.IsDecomposedBy
182182
invAtt = []
183183
for rel in decomposedBy:
184184
relatedObjects = rel.RelatedObjects
185-
for relatedObject in relatedObjects:
186-
relatedEntity = self.entityToDict(relatedObject, objData, parent=entity)
185+
for relatedObject in relatedObjects:
186+
relatedEntity = self.entityToDict(
187+
relatedObject, objData, parent=entity)
187188
if parent != relatedEntity:
188189
invAtt.append(relatedEntity)
189190
if invAtt:
190191
d['IsDecomposedBy'] = invAtt
191192

192-
193193
if hasattr(entity, 'ContainsElements'):
194194
decomposedBy = entity.ContainsElements
195195
invAtt = []
196196
for rel in decomposedBy:
197197
relatedObjects = rel.RelatedElements
198-
for relatedObject in relatedObjects:
199-
relatedEntity = self.entityToDict(relatedObject, objData, parent=entity)
198+
for relatedObject in relatedObjects:
199+
relatedEntity = self.entityToDict(
200+
relatedObject, objData, parent=entity)
200201
if parent != relatedEntity:
201202
invAtt.append(relatedEntity)
202203
if invAtt:
203204
d['ContainsElements'] = invAtt
204205

205-
206206
if reference:
207207
uuid = guid.split(guid.expand(entityAttributes["GlobalId"]))[1:-1]
208208
ref['ref'] = uuid
209209
if not entityAttributes['GlobalId'] in self.id_objects:
210210

211-
for i in range(0,len(entity)):
211+
for i in range(0, len(entity)):
212212
attr = entity.attribute_name(i)
213213
attrKey = common.toLowerCamelcase(attr)
214214
if attr == "GlobalId":
@@ -231,7 +231,8 @@ def entityToDict(self, entity, objData, parent=None):
231231
if attr == 'Representation':
232232
if objData:
233233
if entityAttributes['GlobalId'] in objData:
234-
id = guid.split(guid.expand(guid.new()))[1:-1]
234+
id = guid.split(
235+
guid.expand(guid.new()))[1:-1]
235236
d['representations'] = [
236237
{
237238
"type": "shapeRepresentation",
@@ -251,23 +252,25 @@ def entityToDict(self, entity, objData, parent=None):
251252
else:
252253
continue
253254

254-
255255
# Skip ObjectPlacement: all OBJ geometries are in world coordinates
256256
if attr == 'ObjectPlacement':
257257
continue
258258

259-
jsonValue = self.getEntityValue(entityAttributes[attr], objData)
259+
jsonValue = self.getEntityValue(
260+
entityAttributes[attr], objData)
260261
if jsonValue:
261262
d[attrKey] = jsonValue
262263
if entityAttributes[attr] == None:
263264
continue
264265
elif isinstance(entityAttributes[attr], ifcopenshell.entity_instance):
265-
d[attrKey] = self.entityToDict(entityAttributes[attr], objData)
266+
d[attrKey] = self.entityToDict(
267+
entityAttributes[attr], objData)
266268
elif isinstance(entityAttributes[attr], tuple):
267269
subEnts = []
268270
for subEntity in entityAttributes[attr]:
269271
if isinstance(subEntity, ifcopenshell.entity_instance):
270-
subEntJson = self.entityToDict(subEntity, objData)
272+
subEntJson = self.entityToDict(
273+
subEntity, objData)
271274
if subEntJson:
272275
subEnts.append(subEntJson)
273276
else:
@@ -280,23 +283,26 @@ def entityToDict(self, entity, objData, parent=None):
280283
return ref
281284
else:
282285

283-
for i in range(0,len(entity)):
286+
for i in range(0, len(entity)):
284287
attr = entity.attribute_name(i)
285288
attrKey = common.toLowerCamelcase(attr)
286289
if attr in entityAttributes:
287290
if not attr == 'OwnerHistory':
288-
jsonValue = self.getEntityValue(entityAttributes[attr], objData)
291+
jsonValue = self.getEntityValue(
292+
entityAttributes[attr], objData)
289293
if jsonValue:
290294
d[attrKey] = jsonValue
291295
if entityAttributes[attr] == None:
292296
continue
293297
elif isinstance(entityAttributes[attr], ifcopenshell.entity_instance):
294-
d[attrKey] = self.entityToDict(entityAttributes[attr], objData)
298+
d[attrKey] = self.entityToDict(
299+
entityAttributes[attr], objData)
295300
elif isinstance(entityAttributes[attr], tuple):
296301
subEnts = []
297302
for subEntity in entityAttributes[attr]:
298303
if isinstance(subEntity, ifcopenshell.entity_instance):
299-
subEntJson = self.entityToDict(subEntity, objData)
304+
subEntJson = self.entityToDict(
305+
subEntity, objData)
300306
if subEntJson:
301307
subEnts.append(subEntJson)
302308
else:
@@ -306,7 +312,6 @@ def entityToDict(self, entity, objData, parent=None):
306312
else:
307313
d[attrKey] = entityAttributes[attr]
308314

309-
310315
return d
311316

312317
def getEntityValue(self, value, objData):
@@ -327,7 +332,6 @@ def getEntityValue(self, value, objData):
327332
# convert IFC SPF file into OBJ using IfcConvert and extract OBJ objects
328333
def getObjData(self, ifcFilePath):
329334
objFilePath = NamedTemporaryFile(suffix='.obj', delete=True).name
330-
print(objFilePath)
331335

332336
# Convert IFC to OBJ using IfcConvert (could also be done for glTF or Collada)
333337
subprocess.run([
@@ -346,7 +350,7 @@ def getObjData(self, ifcFilePath):
346350
f = open(objFilePath, 'r')
347351
lc = 0
348352
for line in f:
349-
lc +=1
353+
lc += 1
350354

351355
# find group
352356
if line[0] == 'g':
@@ -377,4 +381,4 @@ def getObjData(self, ifcFilePath):
377381
return objData
378382
else:
379383
print('Creating intermediate OBJ failed')
380-
return None
384+
return None

0 commit comments

Comments
 (0)