mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 10:57:49 +00:00
349 lines
19 KiB
Python
349 lines
19 KiB
Python
import json
|
|
import ifcopenshell
|
|
import os
|
|
|
|
class CA2IFC:
|
|
def __init__(self, inputFilename, outputFilename):
|
|
self.inputFilename = inputFilename
|
|
self.outputFilename = outputFilename
|
|
self.data = None
|
|
self.f = None
|
|
self.reps = {}
|
|
self.origin = None
|
|
self.xAxis = None
|
|
self.yAxis = None
|
|
self.zAxis = None
|
|
|
|
def convert(self):
|
|
# load json file
|
|
with open(self.inputFilename) as dataFile:
|
|
self.data = json.load(dataFile)
|
|
|
|
# initiate ifc file
|
|
self.f = ifcopenshell.file()
|
|
|
|
# create header
|
|
self.create_header()
|
|
|
|
# create global axes
|
|
globalAxes = self.create_global_axes()
|
|
localPlacement = self.f.createIfcLocalPlacement(None, globalAxes)
|
|
|
|
# TODO: create units
|
|
lengthUnit = self.f.createIfcSIUnit(None, 'LENGTHUNIT', None, 'METRE')
|
|
unitAssignment = self.f.createIfcUnitAssignment((lengthUnit,))
|
|
|
|
# create owner history
|
|
ownerHistory = self.create_owner_history()
|
|
|
|
# create representations and subrepresentations
|
|
self.reps = self.create_reference_subrep(globalAxes)
|
|
|
|
# create project and model
|
|
project = self.f.createIfcProject(self.guid(), ownerHistory, 'A Project', None, None, None, None, (self.reps['model'],), unitAssignment)
|
|
model = self.f.createIfcStructuralAnalysisModel(self.guid(), ownerHistory, self.data['name'], None, None, 'NOTDEFINED', globalAxes, None, None, localPlacement)
|
|
self.f.createIfcRelDeclares(self.guid(), ownerHistory, None, None, project, (model,))
|
|
|
|
# create materials
|
|
ifcMaterials = [None for _ in range(len(self.data['db']['materials']))]
|
|
for i,material in enumerate(self.data['db']['materials']):
|
|
ifcMaterials[i] = self.create_material(material)
|
|
|
|
# create profiles
|
|
ifcProfiles = [None for _ in range(len(self.data['db']['profiles']))]
|
|
for i,profile in enumerate(self.data['db']['profiles']):
|
|
ifcProfiles[i] = self.create_profile(profile)
|
|
|
|
# create material-profile sets
|
|
mpSets = list(set([el['material'] + '-' + el['profile'] for el in self.data['elements'] if el['geometryType'] == 'line']))
|
|
ifcMaterialProfileSets = [None for _ in range(len(mpSets))]
|
|
for i,mpSet in enumerate(mpSets):
|
|
materialIndex = [mat['ifcName'] for mat in self.data['db']['materials']].index(mpSet.split('-')[0])
|
|
profileIndex = [prof['ifcName'] for prof in self.data['db']['profiles']].index(mpSet.split('-')[1])
|
|
material = ifcMaterials[materialIndex]
|
|
profile = ifcProfiles[profileIndex]
|
|
matProf = self.f.createIfcMaterialProfile(self.data['db']['materials'][materialIndex]['name'] + ' | ' + self.data['db']['profiles'][profileIndex]['profileName'], None, material, profile)
|
|
ifcMaterialProfileSets[i] = self.f.createIfcMaterialProfileSet(None, None, (matProf,))
|
|
|
|
# create structural elements
|
|
ifcElements = [None for _ in range(len(self.data['elements']))]
|
|
for i,el in enumerate(self.data['elements']):
|
|
# geometry - product definition shape
|
|
prodDefShape = self.create_geometry(el)
|
|
|
|
if el['geometryType'] == 'line':
|
|
# z axis TODO: group by elements
|
|
localZAxis = self.f.createIfcDirection(tuple(el['orientation'][2]))
|
|
# element
|
|
ifcElements[i] = self.f.createIfcStructuralCurveMember(self.guid(), ownerHistory, el['name'], None, None, localPlacement, prodDefShape, el['predefinedType'], localZAxis)
|
|
|
|
if el['geometryType'] == 'surface':
|
|
ifcElements[i] = self.f.createIfcStructuralSurfaceMember(self.guid(), ownerHistory, el['name'], None, None, localPlacement, prodDefShape, el['predefinedType'], el['thickness'])
|
|
|
|
# create structural point connections
|
|
ifcConnections = [None for _ in range(len(self.data['connections']))]
|
|
for i,conn in enumerate(self.data['connections']):
|
|
# geometry - product definition shape
|
|
prodDefShape = self.create_geometry(conn)
|
|
|
|
# boundary conditions
|
|
if conn['appliedCondition']:
|
|
bc = self.create_applied_conditions(conn['appliedCondition'], conn['geometryType'])
|
|
if conn['geometryType'] == 'point':
|
|
appliedCondition = self.f.createIfcBoundaryNodeCondition(None, bc['dx'], bc['dy'], bc['dz'], bc['drx'], bc['dry'], bc['drz'])
|
|
if conn['geometryType'] == 'line':
|
|
appliedCondition = self.f.createIfcBoundaryEdgeCondition(None, bc['dx'], bc['dy'], bc['dz'], bc['drx'], bc['dry'], bc['drz'])
|
|
if conn['geometryType'] == 'surface':
|
|
appliedCondition = self.f.createIfcBoundaryFaceCondition(None, bc['dx'], bc['dy'], bc['dz'])
|
|
else:
|
|
appliedCondition = None
|
|
|
|
if conn['geometryType'] == 'point':
|
|
# local axes
|
|
localAxes = self.create_orientation(conn['orientation'])
|
|
# connection
|
|
ifcConnections[i] = self.f.createIfcStructuralPointConnection(self.guid(), ownerHistory, conn['name'], None, None, localPlacement, prodDefShape, appliedCondition, localAxes)
|
|
|
|
if conn['geometryType'] == 'line':
|
|
# z axis TODO: group by elements
|
|
localZAxis = self.f.createIfcDirection(tuple(conn['orientation'][2]))
|
|
# connection
|
|
ifcConnections[i] = self.f.createIfcStructuralCurveConnection(self.guid(), ownerHistory, conn['name'], None, None, localPlacement, prodDefShape, appliedCondition, localZAxis)
|
|
|
|
if conn['geometryType'] == 'surface':
|
|
ifcConnections[i] = self.f.createIfcStructuralSurfaceConnection(self.guid(), ownerHistory, conn['name'], None, None, localPlacement, prodDefShape, appliedCondition)
|
|
|
|
# assign material-profile-sets
|
|
for i,mpSet in enumerate(mpSets):
|
|
groupOfElements = []
|
|
for j,el in enumerate(self.data['elements']):
|
|
if el['geometryType'] == 'line' and el['material'] + '-' + el['profile'] == mpSet:
|
|
groupOfElements.append(ifcElements[j])
|
|
|
|
if groupOfElements:
|
|
self.f.createIfcRelAssociatesMaterial(self.guid(), ownerHistory, None, None, tuple(groupOfElements), ifcMaterialProfileSets[i])
|
|
|
|
# assign materials
|
|
for i,mat in enumerate(self.data['db']['materials']):
|
|
groupOfElements = []
|
|
for j,el in enumerate(self.data['elements']):
|
|
if el['geometryType'] == 'surface' and el['material'] == mat['ifcName']:
|
|
groupOfElements.append(ifcElements[j])
|
|
if groupOfElements:
|
|
self.f.createIfcRelAssociatesMaterial(self.guid(), ownerHistory, None, None, tuple(groupOfElements), ifcMaterials[i])
|
|
|
|
# create connections with elements
|
|
for i,el in enumerate(self.data['elements']):
|
|
for conn in el['connections']:
|
|
j = [c['ifcName'] for c in self.data['connections']].index(conn['relatedConnection'])
|
|
geometryType = self.data['connections'][j]['geometryType']
|
|
|
|
if conn['appliedCondition']:
|
|
bc = self.create_applied_conditions(conn['appliedCondition'], geometryType)
|
|
if geometryType == 'point':
|
|
appliedCondition = self.f.createIfcBoundaryNodeCondition(None, bc['dx'], bc['dy'], bc['dz'], bc['drx'], bc['dry'], bc['drz'])
|
|
if geometryType == 'line':
|
|
appliedCondition = self.f.createIfcBoundaryEdgeCondition(None, bc['dx'], bc['dy'], bc['dz'], bc['drx'], bc['dry'], bc['drz'])
|
|
if geometryType == 'surface':
|
|
appliedCondition = self.f.createIfcBoundaryFaceCondition(None, bc['dx'], bc['dy'], bc['dz'])
|
|
else:
|
|
appliedCondition = None
|
|
|
|
# local axes
|
|
localAxes = self.create_orientation(conn['orientation'])
|
|
|
|
if geometryType == 'point':
|
|
if not conn['eccentricity']:
|
|
self.f.createIfcRelConnectsStructuralMember(self.guid(), ownerHistory, None, None, ifcElements[i], ifcConnections[j], appliedCondition, None, None, localAxes)
|
|
else:
|
|
pointOnElement = self.f.createIfcCartesianPoint(tuple(conn['eccentricity']['pointOnElement']))
|
|
vector = conn['eccentricity']['vector']
|
|
connPointEcc = self.f.createIfcConnectionPointEccentricity(pointOnElement, None, vector[0], vector[1], vector[2])
|
|
self.f.createIfcRelConnectsWithEccentricity(self.guid(), ownerHistory, None, None, ifcElements[i], ifcConnections[j], appliedCondition, None, None, localAxes, connPointEcc)
|
|
|
|
if geometryType in ['line', 'surface']:
|
|
self.f.createIfcRelConnectsStructuralMember(self.guid(), ownerHistory, None, None, ifcElements[i], ifcConnections[j], appliedCondition, None, None, localAxes)
|
|
|
|
# assign elements and connections to group
|
|
self.f.createIfcRelAssignsToGroup(self.guid(), ownerHistory, None, None, tuple(ifcElements + ifcConnections), None, model)
|
|
|
|
# finalize ifc file
|
|
self.f.write(self.outputFilename)
|
|
|
|
def guid(self):
|
|
return ifcopenshell.guid.new()
|
|
|
|
def create_header(self):
|
|
self.f.wrapped_data.header.file_name.name = os.path.basename(self.outputFilename)
|
|
|
|
def create_global_axes(self):
|
|
self.xAxis = self.f.createIfcDirection((1., 0., 0.))
|
|
self.yAxis = self.f.createIfcDirection((0., 1., 0.))
|
|
self.zAxis = self.f.createIfcDirection((0., 0., 1.))
|
|
self.origin = self.f.createIfcCartesianPoint((0., 0., 0.))
|
|
axes = self.f.createIfcAxis2Placement3D(self.origin, self.zAxis, self.xAxis)
|
|
|
|
return axes
|
|
|
|
def create_orientation(self, orientation):
|
|
xAxis = self.f.createIfcDirection(tuple(orientation[0]))
|
|
zAxis = self.f.createIfcDirection(tuple(orientation[2]))
|
|
axes = self.f.createIfcAxis2Placement3D(self.origin, zAxis, xAxis)
|
|
|
|
return axes
|
|
|
|
def create_owner_history(self):
|
|
actor = self.f.createIfcActorRole('ENGINEER', None, None)
|
|
person = self.f.createIfcPerson('Christovasilis', None, 'Ioannis', None, None, None, (actor,))
|
|
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.')
|
|
p_o = self.f.createIfcPersonAndOrganization(person, organization)
|
|
application = self.f.createIfcApplication(organization, 'v0.0.x', 'IFC2CA', 'IFC2CA')
|
|
ownerHistory = self.f.createIfcOwnerHistory(p_o, application, 'READWRITE', None, None, p_o, application)
|
|
|
|
return ownerHistory
|
|
|
|
def create_reference_subrep(self, globalAxes):
|
|
modelRep = self.f.createIfcGeometricRepresentationContext(None, 'Model', 3, 1.E-05, globalAxes, None)
|
|
bodySubRep = self.f.createIfcGeometricRepresentationSubContext('Body', 'Model', None, None, None , None, modelRep, None, 'MODEL_VIEW', None)
|
|
refSubRep = self.f.createIfcGeometricRepresentationSubContext('Reference', 'Model', None, None, None , None, modelRep, None, 'GRAPH_VIEW', None)
|
|
|
|
return {
|
|
'model': modelRep,
|
|
'body': bodySubRep,
|
|
'reference': refSubRep
|
|
}
|
|
|
|
def create_material(self, material):
|
|
ifcMaterial = self.f.createIfcMaterial(material['name'], None, material['category'])
|
|
|
|
mechProps = []
|
|
if 'youngModulus' in material['mechProps']:
|
|
youngModulus = self.f.createIfcPropertySingleValue('YoungModulus', None, self.f.createIfcModulusOfElasticityMeasure(material['mechProps']['youngModulus']))
|
|
mechProps.append(youngModulus)
|
|
if 'shearModulus' in material['mechProps']:
|
|
shearModulus = self.f.createIfcPropertySingleValue('ShearModulus', None, self.f.createIfcModulusOfElasticityMeasure(material['mechProps']['shearModulus']))
|
|
mechProps.append(shearModulus)
|
|
if 'poissonRatio' in material['mechProps']:
|
|
poissonRatio = self.f.createIfcPropertySingleValue('PoissonRatio', None, self.f.createIfcPositiveRatioMeasure(material['mechProps']['poissonRatio']))
|
|
mechProps.append(poissonRatio)
|
|
if mechProps:
|
|
self.f.createIfcMaterialProperties('Pset_MaterialMechanical', material['name'], tuple(mechProps), ifcMaterial)
|
|
|
|
commonProps = []
|
|
if 'massDensity' in material['commonProps']:
|
|
massDensity = self.f.createIfcPropertySingleValue('MassDensity', None, self.f.createIfcMassDensityMeasure(material['commonProps']['massDensity']))
|
|
commonProps.append(massDensity)
|
|
if commonProps:
|
|
self.f.createIfcMaterialProperties('Pset_MaterialCommon', material['name'], tuple(commonProps), ifcMaterial)
|
|
|
|
return ifcMaterial
|
|
|
|
def create_profile(self, profile):
|
|
if profile['profileShape'] == 'rectangular':
|
|
ifcProfile = self.f.createIfcRectangleProfileDef(profile['profileType'], profile['profileName'], None, profile['xDim'], profile['yDim'])
|
|
|
|
if profile['profileShape'] == 'iSymmetrical':
|
|
ifcProfile = self.f.createIfcIShapeProfileDef(
|
|
profile['profileType'], profile['profileName'], None,
|
|
profile['commonProps']['overallWidth'],
|
|
profile['commonProps']['overallDepth'],
|
|
profile['commonProps']['webThickness'],
|
|
profile['commonProps']['flangeThickness'],
|
|
profile['commonProps']['filletRadius']
|
|
)
|
|
|
|
mechProps = []
|
|
if 'massPerLength' in profile['mechProps']:
|
|
massPerLength = self.f.createIfcPropertySingleValue('MassPerLength', None, self.f.createIfcMassPerLengthMeasure(profile['mechProps']['massPerLength']))
|
|
mechProps.append(massPerLength)
|
|
if 'crossSectionArea' in profile['mechProps']:
|
|
crossSectionArea = self.f.createIfcPropertySingleValue('CrossSectionArea', None, self.f.createIfcAreaMeasure(profile['mechProps']['crossSectionArea']))
|
|
mechProps.append(crossSectionArea)
|
|
if 'momentOfInertiaY' in profile['mechProps']:
|
|
momentOfInertiaY = self.f.createIfcPropertySingleValue('MomentOfInertiaY', None, self.f.createIfcMomentOfInertiaMeasure(profile['mechProps']['momentOfInertiaY']))
|
|
mechProps.append(momentOfInertiaY)
|
|
if 'momentOfInertiaZ' in profile['mechProps']:
|
|
momentOfInertiaZ = self.f.createIfcPropertySingleValue('MomentOfInertiaZ', None, self.f.createIfcMomentOfInertiaMeasure(profile['mechProps']['momentOfInertiaZ']))
|
|
mechProps.append(momentOfInertiaZ)
|
|
if 'torsionalConstantX' in profile['mechProps']:
|
|
torsionalConstantX = self.f.createIfcPropertySingleValue('TorsionalConstantX', None, self.f.createIfcMomentOfInertiaMeasure(profile['mechProps']['torsionalConstantX']))
|
|
mechProps.append(torsionalConstantX)
|
|
if mechProps:
|
|
self.f.createIfcProfileProperties('Pset_ProfileMechanical', profile['profileName'], tuple(mechProps), ifcProfile)
|
|
|
|
return ifcProfile
|
|
|
|
def create_geometry(self, object):
|
|
if object['geometryType'] == 'point':
|
|
point = self.f.createIfcCartesianPoint(tuple(object['geometry']))
|
|
vertex = self.f.createIfcVertexPoint(point)
|
|
vertexTopologyRep = self.f.createIfcTopologyRepresentation(self.reps['reference'], 'Reference', 'Vertex', (vertex,))
|
|
vertexProdDefShape = self.f.createIfcProductDefinitionShape(None, None, (vertexTopologyRep,))
|
|
|
|
return vertexProdDefShape
|
|
|
|
if object['geometryType'] == 'line':
|
|
startPoint = self.f.createIfcCartesianPoint(tuple(object['geometry'][0]))
|
|
startVertex = self.f.createIfcVertexPoint(startPoint)
|
|
endPoint = self.f.createIfcCartesianPoint(tuple(object['geometry'][1]))
|
|
endVertex = self.f.createIfcVertexPoint(endPoint)
|
|
edge = self.f.createIfcEdge(startVertex, endVertex)
|
|
edgeTopologyRep = self.f.createIfcTopologyRepresentation(self.reps['reference'], 'Reference', 'Edge', (edge,))
|
|
edgeProdDefShape = self.f.createIfcProductDefinitionShape(None, None, (edgeTopologyRep,))
|
|
|
|
return edgeProdDefShape
|
|
|
|
if object['geometryType'] == 'surface':
|
|
verts = [None for _ in range(len(object['geometry']))]
|
|
for i,p in enumerate(object['geometry']):
|
|
point = self.f.createIfcCartesianPoint(tuple(p))
|
|
verts[i] = self.f.createIfcVertexPoint(point)
|
|
|
|
orientedEdges = [None for _ in range(len(object['geometry']))]
|
|
for i,v in enumerate(verts):
|
|
v2Index = (i + 1) if i < len(verts) - 1 else 0
|
|
edge = self.f.createIfcEdge(v, verts[v2Index])
|
|
orientedEdges[i] = self.f.createIfcOrientedEdge(None, None, edge, True)
|
|
|
|
edgeLoop = self.f.createIfcEdgeLoop(tuple(orientedEdges))
|
|
localAxes = self.create_orientation(object['orientation'])
|
|
plane = self.f.createIfcPlane(localAxes)
|
|
faceBound = self.f.createIfcFaceBound(edgeLoop, True)
|
|
face = self.f.createIfcFaceSurface((faceBound,), plane, True)
|
|
faceTopologyRep = self.f.createIfcTopologyRepresentation(self.reps['reference'], 'Reference', 'Face', (face,))
|
|
faceProdDefShape = self.f.createIfcProductDefinitionShape(None, None, (faceTopologyRep,))
|
|
|
|
return faceProdDefShape
|
|
|
|
def create_applied_conditions(self, bc, geometryType):
|
|
for dof in ['dx', 'dy', 'dz']:
|
|
if isinstance(bc[dof], bool):
|
|
bc[dof] = self.f.createIfcBoolean(bc[dof])
|
|
else:
|
|
if geometryType == 'point':
|
|
bc[dof] = self.f.createIfcLinearStiffnessMeasure(bc[dof])
|
|
if geometryType == 'line':
|
|
bc[dof] = self.f.createIfcModulusOfLinearSubgradeReactionMeasure(bc[dof])
|
|
if geometryType == 'surface':
|
|
bc[dof] = self.f.createIfcModulusOfSubgradeReactionMeasure(bc[dof])
|
|
|
|
for dof in ['drx', 'dry', 'drz']:
|
|
if isinstance(bc[dof], bool):
|
|
bc[dof] = self.f.createIfcBoolean(bc[dof])
|
|
else:
|
|
if geometryType == 'point':
|
|
bc[dof] = self.f.createIfcRotationalStiffnessMeasure(bc[dof])
|
|
if geometryType == 'line':
|
|
bc[dof] = self.f.createIfcModulusOfRotationalSubgradeReactionMeasure(bc[dof])
|
|
|
|
return bc
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
inputFilename = 'structure_01.json'
|
|
outputFilename = 'structure_01.ifc'
|
|
|
|
ca2ifc = CA2IFC(inputFilename, outputFilename)
|
|
ca2ifc.convert()
|