Skip to content

Commit 6e8eca3

Browse files
committed
experimental ca2ifc (json -> ifc) for creating example files
1 parent 63e65b2 commit 6e8eca3

1 file changed

Lines changed: 291 additions & 0 deletions

File tree

src/ifc2ca/ca2ifc.py

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
import json
2+
import ifcopenshell
3+
import os
4+
5+
class CA2IFC:
6+
def __init__(self, inputFilename, outputFilename):
7+
self.inputFilename = inputFilename
8+
self.outputFilename = outputFilename
9+
self.data = None
10+
self.f = None
11+
self.reps = {}
12+
self.origin = None
13+
self.xAxis = None
14+
self.yAxis = None
15+
self.zAxis = None
16+
17+
def convert(self):
18+
# load json file
19+
with open(self.inputFilename) as dataFile:
20+
self.data = json.load(dataFile)
21+
22+
# initiate ifc file
23+
self.f = ifcopenshell.file()
24+
25+
# create header
26+
self.create_header()
27+
28+
# create global axes
29+
globalAxes = self.create_global_axes()
30+
localPlacement = self.f.createIfcLocalPlacement(None, globalAxes)
31+
32+
# TODO: create units
33+
unitAssignment = self.f.createIfcUnitAssignment()
34+
35+
# create owner history
36+
ownerHistory = self.create_owner_history()
37+
38+
# create representations and subrepresentations
39+
self.reps = self.create_reference_subrep(globalAxes)
40+
41+
# create project and model
42+
project = self.f.createIfcProject(self.guid(), ownerHistory, 'A Project', None, None, None, None, (self.reps['model'],), unitAssignment)
43+
model = self.f.createIfcStructuralAnalysisModel(self.guid(), ownerHistory, self.data['name'], None, None, 'NOTDEFINED', globalAxes, None, None, localPlacement)
44+
self.f.createIfcRelDeclares(self.guid(), ownerHistory, None, None, project, (model,))
45+
46+
# create materials
47+
ifcMaterials = [None for _ in range(len(self.data['db']['materials']))]
48+
for i,material in enumerate(self.data['db']['materials']):
49+
ifcMaterials[i] = self.create_material(material)
50+
51+
# create profiles
52+
ifcProfiles = [None for _ in range(len(self.data['db']['profiles']))]
53+
for i,profile in enumerate(self.data['db']['profiles']):
54+
ifcProfiles[i] = self.create_profile(profile)
55+
56+
# create material-profile sets
57+
mpSets = list(set([el['material'] + '-' + el['profile'] for el in self.data['elements'] if el['geometryType'] == 'line']))
58+
ifcMaterialProfileSets = [None for _ in range(len(mpSets))]
59+
for i,mpSet in enumerate(mpSets):
60+
materialIndex = [mat['ifcName'] for mat in self.data['db']['materials']].index(mpSet.split('-')[0])
61+
profileIndex = [prof['ifcName'] for prof in self.data['db']['profiles']].index(mpSet.split('-')[1])
62+
material = ifcMaterials[materialIndex]
63+
profile = ifcProfiles[materialIndex]
64+
matProf = self.f.createIfcMaterialProfile(self.data['db']['materials'][materialIndex]['name'] + ' | ' + self.data['db']['profiles'][profileIndex]['profileName'], None, material, profile)
65+
ifcMaterialProfileSets[i] = self.f.createIfcMaterialProfileSet(None, None, (matProf,))
66+
67+
# create structural elements
68+
ifcElements = [None for _ in range(len(self.data['elements']))]
69+
for i,el in enumerate(self.data['elements']):
70+
# geometry - product definition shape
71+
prodDefShape = self.create_geometry(el)
72+
73+
if el['geometryType'] == 'line':
74+
# z axis TODO: group by elements
75+
localZAxis = self.f.createIfcDirection(tuple(el['orientation'][2]))
76+
# element
77+
ifcElements[i] = self.f.createIfcStructuralCurveMember(self.guid(), ownerHistory, el['name'], None, None, localPlacement, prodDefShape, el['predefinedType'], localZAxis)
78+
79+
if el['geometryType'] == 'surface':
80+
# element
81+
ifcElements[i] = self.f.createIfcStructuralSurfaceMember(self.guid(), ownerHistory, el['name'], None, None, localPlacement, prodDefShape, el['predefinedType'], el['thickness'])
82+
83+
# create structural point connections
84+
ifcConnections = [None for _ in range(len(self.data['connections']))]
85+
for i,conn in enumerate(self.data['connections']):
86+
# geometry - product definition shape
87+
prodDefShape = self.create_geometry(conn)
88+
# local axes
89+
localAxes = self.create_orientation(conn['orientation'])
90+
# boundary conditions
91+
if conn['appliedCondition']:
92+
bc = conn['appliedCondition']
93+
appliedCondition = self.f.createIfcBoundaryNodeCondition(None, self.f.createIfcBoolean(bc['dx']), self.f.createIfcBoolean(bc['dy']), self.f.createIfcBoolean(bc['dz']), self.f.createIfcBoolean(bc['drx']), self.f.createIfcBoolean(bc['dry']), self.f.createIfcBoolean(bc['drz']))
94+
else:
95+
appliedCondition = None
96+
97+
# connection
98+
if conn['geometryType'] == 'point':
99+
ifcConnections[i] = self.f.createIfcStructuralPointConnection(self.guid(), ownerHistory, conn['name'], None, None, localPlacement, prodDefShape, appliedCondition, localAxes)
100+
101+
# assign material-profile-sets
102+
for i,mpSet in enumerate(mpSets):
103+
groupOfElements = []
104+
for j,el in enumerate(self.data['elements']):
105+
if el['geometryType'] == 'line' and el['material'] + '-' + el['profile'] == mpSet:
106+
groupOfElements.append(ifcElements[j])
107+
108+
if groupOfElements:
109+
self.f.createIfcRelAssociatesMaterial(self.guid(), ownerHistory, None, None, tuple(groupOfElements), ifcMaterialProfileSets[i])
110+
111+
# assign materials
112+
for i,mat in enumerate(self.data['db']['materials']):
113+
groupOfElements = []
114+
for j,el in enumerate(self.data['elements']):
115+
if el['geometryType'] == 'surface' and el['material'] == mat['ifcName']:
116+
groupOfElements.append(ifcElements[j])
117+
if groupOfElements:
118+
self.f.createIfcRelAssociatesMaterial(self.guid(), ownerHistory, None, None, tuple(groupOfElements), ifcMaterials[i])
119+
120+
# create connections with elements
121+
for i,el in enumerate(self.data['elements']):
122+
for conn in el['connections']:
123+
localAxes = self.create_orientation(conn['orientation'])
124+
if conn['appliedCondition']:
125+
bc = conn['appliedCondition']
126+
appliedCondition = self.f.createIfcBoundaryNodeCondition(None, self.f.createIfcBoolean(bc['dx']), self.f.createIfcBoolean(bc['dy']), self.f.createIfcBoolean(bc['dz']), self.f.createIfcBoolean(bc['drx']), self.f.createIfcBoolean(bc['dry']), self.f.createIfcBoolean(bc['drz']))
127+
else:
128+
appliedCondition = None
129+
j = [c['ifcName'] for c in self.data['connections']].index(conn['relatedConnection'])
130+
if not conn['eccentricity']:
131+
self.f.createIfcRelConnectsStructuralMember(self.guid(), ownerHistory, None, None, ifcElements[i], ifcConnections[j], appliedCondition, None, None, localAxes)
132+
else:
133+
pass
134+
135+
# assign elements and connections to group
136+
self.f.createIfcRelAssignsToGroup(self.guid(), ownerHistory, None, None, tuple(ifcElements + ifcConnections), None, model)
137+
138+
# finalize ifc file
139+
self.f.write(self.outputFilename)
140+
141+
def guid(self):
142+
return ifcopenshell.guid.new()
143+
144+
def create_header(self):
145+
self.f.wrapped_data.header.file_name.name = os.path.basename(self.outputFilename)
146+
147+
def create_global_axes(self):
148+
self.xAxis = self.f.createIfcDirection((1., 0., 0.))
149+
self.yAxis = self.f.createIfcDirection((0., 1., 0.))
150+
self.zAxis = self.f.createIfcDirection((0., 0., 1.))
151+
self.origin = self.f.createIfcCartesianPoint((0., 0., 0.))
152+
axes = self.f.createIfcAxis2Placement3D(self.origin, self.zAxis, self.xAxis)
153+
154+
return axes
155+
156+
def create_orientation(self, orientation):
157+
xAxis = self.f.createIfcDirection(tuple(orientation[0]))
158+
zAxis = self.f.createIfcDirection(tuple(orientation[2]))
159+
axes = self.f.createIfcAxis2Placement3D(self.origin, zAxis, xAxis)
160+
161+
return axes
162+
163+
def create_owner_history(self):
164+
actor = self.f.createIfcActorRole('ENGINEER', None, None)
165+
person = self.f.createIfcPerson('Christovasilis', None, 'Ioannis', None, None, None, (actor,))
166+
organization = self.f.createIfcOrganization(None, 'IfcOpenShell', 'IfcOpenShell, an open source (LGPL) software library that helps users and software developers to work with the IFC file format.')
167+
p_o = self.f.createIfcPersonAndOrganization(person, organization)
168+
application = self.f.createIfcApplication(organization, 'v0.0.x', 'IFC2CA', 'IFC2CA')
169+
ownerHistory = self.f.createIfcOwnerHistory(p_o, application, 'READWRITE', None, None, p_o, application)
170+
171+
return ownerHistory
172+
173+
def create_reference_subrep(self, globalAxes):
174+
modelRep = self.f.createIfcGeometricRepresentationContext(None, 'Model', 3, 1.E-05, globalAxes, None)
175+
bodySubRep = self.f.createIfcGeometricRepresentationSubContext('Body', 'Model', None, None, None , None, modelRep, None, 'MODEL_VIEW', None)
176+
refSubRep = self.f.createIfcGeometricRepresentationSubContext('Reference', 'Model', None, None, None , None, modelRep, None, 'GRAPH_VIEW', None)
177+
178+
return {
179+
'model': modelRep,
180+
'body': bodySubRep,
181+
'reference': refSubRep
182+
}
183+
184+
def create_material(self, material):
185+
ifcMaterial = self.f.createIfcMaterial(material['name'], None, material['category'])
186+
187+
mechProps = []
188+
if 'youngModulus' in material['mechProps']:
189+
youngModulus = self.f.createIfcPropertySingleValue('YoungModulus', None, self.f.createIfcModulusOfElasticityMeasure(material['mechProps']['youngModulus']))
190+
mechProps.append(youngModulus)
191+
if 'shearModulus' in material['mechProps']:
192+
shearModulus = self.f.createIfcPropertySingleValue('ShearModulus', None, self.f.createIfcModulusOfElasticityMeasure(material['mechProps']['shearModulus']))
193+
mechProps.append(shearModulus)
194+
if 'poissonRatio' in material['mechProps']:
195+
poissonRatio = self.f.createIfcPropertySingleValue('PoissonRatio', None, self.f.createIfcPositiveRatioMeasure(material['mechProps']['poissonRatio']))
196+
mechProps.append(poissonRatio)
197+
if mechProps:
198+
self.f.createIfcMaterialProperties('Pset_MaterialMechanical', material['name'], tuple(mechProps), ifcMaterial)
199+
200+
commonProps = []
201+
if 'massDensity' in material['commonProps']:
202+
massDensity = self.f.createIfcPropertySingleValue('MassDensity', None, self.f.createIfcMassDensityMeasure(material['commonProps']['massDensity']))
203+
commonProps.append(massDensity)
204+
if commonProps:
205+
self.f.createIfcMaterialProperties('Pset_MaterialCommon', material['name'], tuple(commonProps), ifcMaterial)
206+
207+
return ifcMaterial
208+
209+
def create_profile(self, profile):
210+
if profile['profileShape'] == 'rectangular':
211+
ifcProfile = self.f.createIfcRectangleProfileDef(profile['profileType'], profile['profileName'], None, profile['xDim'], profile['yDim'])
212+
213+
if profile['profileShape'] == 'iSymmetrical':
214+
ifcProfile = self.f.createIfcIShapeProfileDef(
215+
profile['profileType'], profile['profileName'], None,
216+
profile['commonProps']['overallWidth'],
217+
profile['commonProps']['overallDepth'],
218+
profile['commonProps']['webThickness'],
219+
profile['commonProps']['flangeThickness'],
220+
profile['commonProps']['filletRadius']
221+
)
222+
223+
mechProps = []
224+
if 'massPerLength' in profile['mechProps']:
225+
massPerLength = self.f.createIfcPropertySingleValue('MassPerLength', None, self.f.createIfcMassPerLengthMeasure(profile['mechProps']['massPerLength']))
226+
mechProps.append(massPerLength)
227+
if 'crossSectionArea' in profile['mechProps']:
228+
crossSectionArea = self.f.createIfcPropertySingleValue('CrossSectionArea', None, self.f.createIfcAreaMeasure(profile['mechProps']['crossSectionArea']))
229+
mechProps.append(crossSectionArea)
230+
if 'momentOfInertiaY' in profile['mechProps']:
231+
momentOfInertiaY = self.f.createIfcPropertySingleValue('MomentOfInertiaY', None, self.f.createIfcMomentOfInertiaMeasure(profile['mechProps']['momentOfInertiaY']))
232+
mechProps.append(momentOfInertiaY)
233+
if 'momentOfInertiaZ' in profile['mechProps']:
234+
momentOfInertiaZ = self.f.createIfcPropertySingleValue('MomentOfInertiaZ', None, self.f.createIfcMomentOfInertiaMeasure(profile['mechProps']['momentOfInertiaZ']))
235+
mechProps.append(momentOfInertiaZ)
236+
if 'torsionalConstantX' in profile['mechProps']:
237+
torsionalConstantX = self.f.createIfcPropertySingleValue('TorsionalConstantX', None, self.f.createIfcMomentOfInertiaMeasure(profile['mechProps']['torsionalConstantX']))
238+
mechProps.append(torsionalConstantX)
239+
if mechProps:
240+
self.f.createIfcProfileProperties('Pset_ProfileMechanical', profile['profileName'], tuple(mechProps), ifcProfile)
241+
242+
return ifcProfile
243+
244+
def create_geometry(self, object):
245+
if object['geometryType'] == 'point':
246+
point = self.f.createIfcCartesianPoint(tuple(object['geometry']))
247+
vertex = self.f.createIfcVertexPoint(point)
248+
vertexTopologyRep = self.f.createIfcTopologyRepresentation(self.reps['reference'], 'Reference', 'Vertex', (vertex,))
249+
vertexProdDefShape = self.f.createIfcProductDefinitionShape(None, None, (vertexTopologyRep,))
250+
251+
return vertexProdDefShape
252+
253+
if object['geometryType'] == 'line':
254+
startPoint = self.f.createIfcCartesianPoint(tuple(object['geometry'][0]))
255+
startVertex = self.f.createIfcVertexPoint(startPoint)
256+
endPoint = self.f.createIfcCartesianPoint(tuple(object['geometry'][1]))
257+
endVertex = self.f.createIfcVertexPoint(endPoint)
258+
edge = self.f.createIfcEdge(startVertex, endVertex)
259+
edgeTopologyRep = self.f.createIfcTopologyRepresentation(self.reps['reference'], 'Reference', 'Edge', (edge,))
260+
edgeProdDefShape = self.f.createIfcProductDefinitionShape(None, None, (edgeTopologyRep,))
261+
262+
return edgeProdDefShape
263+
264+
if object['geometryType'] == 'surface':
265+
verts = [None for _ in range(len(object['geometry']))]
266+
for i,p in enumerate(object['geometry']):
267+
point = self.f.createIfcCartesianPoint(tuple(p))
268+
verts[i] = self.f.createIfcVertexPoint(point)
269+
270+
orientedEdges = [None for _ in range(len(object['geometry']))]
271+
for i,v in enumerate(verts):
272+
v2Index = (i + 1) if i < len(verts) - 1 else 0
273+
edge = self.f.createIfcEdge(v, verts[v2Index])
274+
orientedEdges[i] = self.f.createIfcOrientedEdge(None, None, edge, True)
275+
276+
edgeLoop = self.f.createIfcEdgeLoop(tuple(orientedEdges))
277+
localAxes = self.create_orientation(object['orientation'])
278+
plane = self.f.createIfcPlane(localAxes)
279+
faceBound = self.f.createIfcFaceBound(edgeLoop, True)
280+
face = self.f.createIfcFaceSurface((faceBound,), plane, True)
281+
faceTopologyRep = self.f.createIfcTopologyRepresentation(self.reps['reference'], 'Reference', 'Face', (face,))
282+
faceProdDefShape = self.f.createIfcProductDefinitionShape(None, None, (faceTopologyRep,))
283+
284+
return faceProdDefShape
285+
286+
if __name__ == '__main__':
287+
inputFilename = '' # json file to read
288+
outputFilename = '' # ifc file to write
289+
290+
ca2ifc = CA2IFC(inputFilename, outputFilename)
291+
ca2ifc.convert()

0 commit comments

Comments
 (0)