2626
2727import os
2828import uuid
29+ from tempfile import NamedTemporaryFile
2930import subprocess
3031import ifcopenshell
3132import ifcopenshell .guid as guid
3233import ifcjson .common as common
3334
35+
36+ explicitInverseAttributes = {
37+ 'IsDecomposedBy' ,
38+ 'HasAssociations' ,
39+ 'IsDefinedBy' ,
40+ 'HasOpenings' ,
41+ 'ContainsElements'
42+ }
43+
3444class IFC2JSON5a :
3545 def __init__ (self , ifcFilePath ):
3646 self .ifcFilePath = ifcFilePath
@@ -45,53 +55,178 @@ def __init__(self, ifcFilePath):
4555 def spf2Json (self ):
4656 objData = self .getObjData (self .ifcFilePath )
4757 jsonObjects = []
48- entityIter = iter (self .ifcModel )
49- for entity in entityIter :
58+ # entityIter = iter(self.ifcModel)
59+ # for entity in entityIter:
60+ # # print(dir(entity))
61+ # # print("test")
62+ # # print(getitem(entity))
63+ # self.entityToDict(entity, objData)
64+ for entity in self .ifcModel .by_type ('IfcProject' ):
5065 self .entityToDict (entity , objData )
5166 for key in self .id_objects :
5267 jsonObjects .append (self .id_objects [key ])
5368 for key in self .representations :
5469 jsonObjects .append (self .representations [key ])
55- return jsonObjects
70+ return {'file_schema' : 'IFC.JSON5a' ,'data' : jsonObjects }
71+
72+ def entityToDict (self , entity , objData , parent = None ):
73+ entityAttributes = entity .__dict__
74+ # inverseAttributes = explicitInverseAttributes.intersection(entity.wrapped_data.get_inverse_attribute_names())
75+ entityType = entity .is_a ()
5676
57- def entityToDict (self , entity , objData ):
5877 ref = {
59- 'type' : entity . is_a ()
78+ 'type' : entityType
6079 }
61- attr_dict = entity .__dict__
6280
63- # check for globalid
64- if 'GlobalId' in attr_dict :
65- uuid = guid .split (guid .expand (attr_dict ["GlobalId" ]))[1 :- 1 ]
81+
82+ # determine if object needs to be nested or referenced
83+ reference = False
84+ if 'GlobalId' in entityAttributes :
85+ reference = True
86+ if entity .is_a == 'IfcRelAggregates' :
87+ # print('relaggregates!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
88+ reference = False
89+
90+ d = {
91+ 'type' : entityType
92+ }
93+
94+
95+ # for inverseAttribute in inverseAttributes:
96+ # invAtt = {}
97+ # attributeObject = getattr(entity, inverseAttribute)
98+ # attr = inverseAttribute
99+ # attrKey = common.toLowerCamelcase(attr)
100+ # print(attributeObject)
101+
102+ # print("yeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeees")
103+ # if isinstance(attributeObject, ifcopenshell.entity_instance):
104+ # print("dsicnkjcnkdjvnskjcnkvjnfjkn")
105+ # # if attributeObject.is_a == 'IfcRelAggregates':
106+ # # d[inverseAttribute] = attributeObject.RelatedObjects
107+ # # jsonValue = self.getEntityValue(attributeObject, objData)
108+ # # if jsonValue:
109+ # # invAtt[attrKey] = jsonValue
110+ # # if attributeObject == None:
111+ # # continue
112+ # # elif isinstance(attributeObject, ifcopenshell.entity_instance):
113+ # # invAtt[attrKey] = self.entityToDict(attributeObject, objData)
114+ # # elif isinstance(attributeObject, tuple):
115+ # # subEnts = []
116+ # # for subEntity in attributeObject:
117+ # # if isinstance(subEntity, ifcopenshell.entity_instance):
118+ # # subEntJson = self.entityToDict(subEntity, objData)
119+ # # if subEntJson:
120+ # # subEnts.append(subEntJson)
121+ # # else:
122+ # # subEnts.append(subEntity)
123+ # # if len(subEnts) > 0:
124+ # # invAtt[attrKey] = subEnts
125+ # # else:
126+ # # invAtt[attrKey] = attributeObject
127+ # if invAtt:
128+ # # print(inverseAttribute)
129+ # d[inverseAttribute] = invAtt
130+
131+
132+ # if hasattr(entity, 'IsDefinedBy'):
133+ # decomposedBy = entity.IsDefinedBy
134+ # invAtt = []
135+ # for rel in decomposedBy:
136+ # print(rel)
137+ # relatedObjects = rel.RelatingPropertyDefinition.HasProperties
138+ # print(relatedObjects)
139+ # for relatedObject in relatedObjects:
140+ # relatedEntity = self.entityToDict(relatedObject, objData, parent=entity)
141+ # if parent != relatedEntity:
142+ # invAtt.append(relatedEntity)
143+ # # print(relatedObject)
144+ # # invAtt = invAtt + list(self.entityToDict(subEntity, objData))
145+ # print(invAtt)
146+ # if invAtt:
147+ # d['IsDefinedBy'] = invAtt
148+
149+
150+ if hasattr (entity , 'IsDefinedBy' ):
151+ relations = entity .IsDefinedBy
152+ # p = {}
153+ for rel in relations :
154+ if rel .is_a () == 'IfcRelDefinesByProperties' :
155+ definition = rel .RelatingPropertyDefinition
156+ if definition .is_a () == 'IfcPropertySet' :
157+ relatedObjects = definition .HasProperties
158+ for relatedObject in relatedObjects :
159+ value = relatedObject .NominalValue .wrappedValue
160+ if value and value != '' :
161+ d [common .toLowerCamelcase (relatedObject .Name )] = value
162+ elif definition .is_a () == 'IfcElementQuantity' :
163+ relatedObjects = definition .Quantities
164+ for relatedObject in relatedObjects :
165+ value = relatedObject .AreaValue
166+ if value and value != '' :
167+ d [common .toLowerCamelcase (relatedObject .Name )] = value
168+ else :
169+ print ('Skipped: ' + str (definition ))
170+ else :
171+ print ('Skipped: ' + str (rel ))
172+ # if p:
173+ # d['properties'] = p
174+
175+
176+ if hasattr (entity , 'IsDecomposedBy' ):
177+ decomposedBy = entity .IsDecomposedBy
178+ invAtt = []
179+ for rel in decomposedBy :
180+ relatedObjects = rel .RelatedObjects
181+ for relatedObject in relatedObjects :
182+ relatedEntity = self .entityToDict (relatedObject , objData , parent = entity )
183+ if parent != relatedEntity :
184+ invAtt .append (relatedEntity )
185+ if invAtt :
186+ d ['IsDecomposedBy' ] = invAtt
187+
188+
189+ if hasattr (entity , 'ContainsElements' ):
190+ decomposedBy = entity .ContainsElements
191+ invAtt = []
192+ for rel in decomposedBy :
193+ relatedObjects = rel .RelatedElements
194+ for relatedObject in relatedObjects :
195+ relatedEntity = self .entityToDict (relatedObject , objData , parent = entity )
196+ if parent != relatedEntity :
197+ invAtt .append (relatedEntity )
198+ if invAtt :
199+ d ['ContainsElements' ] = invAtt
200+
201+
202+ if reference :
203+ uuid = guid .split (guid .expand (entityAttributes ["GlobalId" ]))[1 :- 1 ]
66204 ref ['ref' ] = uuid
67- if not attr_dict ['GlobalId' ] in self .id_objects :
68- d = {
69- 'type' : entity .is_a ()
70- }
205+ if not entityAttributes ['GlobalId' ] in self .id_objects :
71206
72207 for i in range (0 ,len (entity )):
73208 attr = entity .attribute_name (i )
74209 attrKey = common .toLowerCamelcase (attr )
75210 if attr == "GlobalId" :
76211 d [attrKey ] = uuid
77212 else :
78- if attr in attr_dict :
213+ if attr in entityAttributes :
79214
80215 # Skip all IFC entities that are not part of IFC.JSON5a
81- if type (attr_dict [attr ]) == ifcopenshell .entity_instance :
216+ if type (entityAttributes [attr ]) == ifcopenshell .entity_instance :
82217
83218 # Skip IfcOwnerHistory
84- if attr_dict [attr ].is_a () == 'IfcOwnerHistory' :
219+ if entityAttributes [attr ].is_a () == 'IfcOwnerHistory' :
85220 continue
86221
87222 # Skip IfcGeometricRepresentationContext
88- if attr_dict [attr ].is_a () == 'IfcGeometricRepresentationContext' :
223+ if entityAttributes [attr ].is_a () == 'IfcGeometricRepresentationContext' :
89224 continue
90225
91226 # Use representation from OBJ list if present
92227 if attr == 'Representation' :
93228 if objData :
94- if attr_dict ['GlobalId' ] in objData :
229+ if entityAttributes ['GlobalId' ] in objData :
95230 id = guid .split (guid .expand (guid .new ()))[1 :- 1 ]
96231 d ['representations' ] = [
97232 {
@@ -105,7 +240,7 @@ def entityToDict(self, entity, objData):
105240 "representationIdentifier" : "Body" ,
106241 "representationType" : "OBJ" ,
107242 "items" : [
108- objData [attr_dict ['GlobalId' ]]
243+ objData [entityAttributes ['GlobalId' ]]
109244 ]
110245 }
111246 continue
@@ -117,16 +252,16 @@ def entityToDict(self, entity, objData):
117252 if attr == 'ObjectPlacement' :
118253 continue
119254
120- jsonValue = self .getEntityValue (attr_dict [attr ], objData )
255+ jsonValue = self .getEntityValue (entityAttributes [attr ], objData )
121256 if jsonValue :
122257 d [attrKey ] = jsonValue
123- if attr_dict [attr ] == None :
258+ if entityAttributes [attr ] == None :
124259 continue
125- elif isinstance (attr_dict [attr ], ifcopenshell .entity_instance ):
126- d [attrKey ] = self .entityToDict (attr_dict [attr ], objData )
127- elif isinstance (attr_dict [attr ], tuple ):
260+ elif isinstance (entityAttributes [attr ], ifcopenshell .entity_instance ):
261+ d [attrKey ] = self .entityToDict (entityAttributes [attr ], objData )
262+ elif isinstance (entityAttributes [attr ], tuple ):
128263 subEnts = []
129- for subEntity in attr_dict [attr ]:
264+ for subEntity in entityAttributes [attr ]:
130265 if isinstance (subEntity , ifcopenshell .entity_instance ):
131266 subEntJson = self .entityToDict (subEntity , objData )
132267 if subEntJson :
@@ -136,29 +271,26 @@ def entityToDict(self, entity, objData):
136271 if len (subEnts ) > 0 :
137272 d [attrKey ] = subEnts
138273 else :
139- d [attrKey ] = attr_dict [attr ]
140- self .id_objects [attr_dict ['GlobalId' ]] = d
274+ d [attrKey ] = entityAttributes [attr ]
275+ self .id_objects [entityAttributes ['GlobalId' ]] = d
141276 return ref
142277 else :
143- d = {
144- 'type' : entity .is_a ()
145- }
146278
147279 for i in range (0 ,len (entity )):
148280 attr = entity .attribute_name (i )
149281 attrKey = common .toLowerCamelcase (attr )
150- if attr in attr_dict :
282+ if attr in entityAttributes :
151283 if not attr == 'OwnerHistory' :
152- jsonValue = self .getEntityValue (attr_dict [attr ], objData )
284+ jsonValue = self .getEntityValue (entityAttributes [attr ], objData )
153285 if jsonValue :
154286 d [attrKey ] = jsonValue
155- if attr_dict [attr ] == None :
287+ if entityAttributes [attr ] == None :
156288 continue
157- elif isinstance (attr_dict [attr ], ifcopenshell .entity_instance ):
158- d [attrKey ] = self .entityToDict (attr_dict [attr ], objData )
159- elif isinstance (attr_dict [attr ], tuple ):
289+ elif isinstance (entityAttributes [attr ], ifcopenshell .entity_instance ):
290+ d [attrKey ] = self .entityToDict (entityAttributes [attr ], objData )
291+ elif isinstance (entityAttributes [attr ], tuple ):
160292 subEnts = []
161- for subEntity in attr_dict [attr ]:
293+ for subEntity in entityAttributes [attr ]:
162294 if isinstance (subEntity , ifcopenshell .entity_instance ):
163295 subEntJson = self .entityToDict (subEntity , objData )
164296 if subEntJson :
@@ -168,7 +300,9 @@ def entityToDict(self, entity, objData):
168300 if len (subEnts ) > 0 :
169301 d [attrKey ] = subEnts
170302 else :
171- d [attrKey ] = attr_dict [attr ]
303+ d [attrKey ] = entityAttributes [attr ]
304+
305+
172306 return d
173307
174308 def getEntityValue (self , value , objData ):
@@ -188,15 +322,15 @@ def getEntityValue(self, value, objData):
188322
189323 # convert IFC SPF file into OBJ using IfcConvert and extract OBJ objects
190324 def getObjData (self , ifcFilePath ):
191- objFilePath = os . path . splitext ( ifcFilePath )[ 0 ] + '.obj'
325+ objFilePath = NamedTemporaryFile ( suffix = '.obj' , delete = True ). name
192326
193327 # Convert IFC to OBJ using IfcConvert (could also be done for glTF or Collada)
194- # subprocess.run([
195- # './ifcopenshell/IfcConvert',
196- # ifcFilePath,
197- # objFilePath,
198- # '--use-element-guids'
199- # ])
328+ subprocess .run ([
329+ './ifcopenshell/IfcConvert' ,
330+ ifcFilePath ,
331+ objFilePath ,
332+ '--use-element-guids'
333+ ])
200334 if os .path .isfile (objFilePath ):
201335 objData = {}
202336 header = True
@@ -208,14 +342,15 @@ def getObjData(self, ifcFilePath):
208342 # find group
209343 if line [0 ] == 'g' :
210344 header = False
211- objData [groupId ] = '\n ' .join (groupData )
345+ objData [groupId ] = '' .join (groupData )
212346 groupId = line .split ()[1 ]
213347 groupData = []
214348 else :
215349 if header :
216350 pass
217351 else :
218- groupData .append (line )
352+ if line [0 ] == 'v' or line [0 ] == 'f' :
353+ groupData .append (line )
219354 return objData
220355 else :
221356 print ('Creating intermediate OBJ failed' )
0 commit comments