mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
206 lines
8.9 KiB
Python
206 lines
8.9 KiB
Python
import ifcopenshell
|
|
import bpy
|
|
|
|
|
|
class IfcParser():
|
|
def __init__(self):
|
|
self.spatial_structure_elements = []
|
|
self.spatial_structure_elements_tree = []
|
|
self.rel_contained_in_spatial_structure = {}
|
|
self.context = {}
|
|
self.products = []
|
|
|
|
def parse(self):
|
|
self.spatial_structure_elements = self.get_spatial_structure_elements()
|
|
|
|
collection_name_filter = []
|
|
product_index = 0
|
|
for object in bpy.context.selected_objects:
|
|
product_data = {
|
|
'ifc': None,
|
|
'raw': object,
|
|
'relating_structure': None
|
|
}
|
|
for collection in object.users_collection:
|
|
if self.is_a_spatial_structure_element(self.get_ifc_class(collection.name)):
|
|
reference = self.get_spatial_structure_element_reference(collection.name)
|
|
self.rel_contained_in_spatial_structure.setdefault(reference, []).append(product_index)
|
|
product_data['relating_structure'] = reference
|
|
collection_name_filter.append(collection.name)
|
|
self.products.append(product_data)
|
|
product_index += 1
|
|
|
|
self.context = self.get_context()
|
|
self.spatial_structure_elements_tree = self.get_spatial_structure_elements_tree(
|
|
self.context['raw'].children, collection_name_filter)
|
|
|
|
def get_context(self):
|
|
for collection in bpy.data.collections:
|
|
if self.is_a_context(self.get_ifc_class(collection.name)):
|
|
return {
|
|
'ifc': None,
|
|
'class': self.get_ifc_class(collection.name),
|
|
'raw': collection,
|
|
'attributes': { 'Name': self.get_ifc_name(collection.name) }
|
|
}
|
|
|
|
def get_spatial_structure_elements(self):
|
|
elements = []
|
|
for collection in bpy.data.collections:
|
|
if self.is_a_spatial_structure_element(self.get_ifc_class(collection.name)):
|
|
elements.append({
|
|
'ifc': None,
|
|
'class': self.get_ifc_class(collection.name),
|
|
'raw': collection,
|
|
'attributes': { 'Name': self.get_ifc_name(collection.name)}
|
|
})
|
|
return elements
|
|
|
|
def get_spatial_structure_elements_tree(self, collections, name_filter):
|
|
collection_tree = []
|
|
|
|
for collection in collections:
|
|
if not self.is_a_spatial_structure_element(self.get_ifc_class(collection.name)):
|
|
continue
|
|
children = self.get_spatial_structure_elements_tree(
|
|
collection.children, name_filter)
|
|
if collection.name in name_filter \
|
|
or children:
|
|
collection_tree.append({
|
|
'reference': self.get_spatial_structure_element_reference(collection.name),
|
|
'children': children
|
|
})
|
|
|
|
return collection_tree
|
|
|
|
def get_spatial_structure_element_reference(self, name):
|
|
return [ e['attributes']['Name'] for e in self.spatial_structure_elements ].index(self.get_ifc_name(name))
|
|
|
|
def get_ifc_class(self, name):
|
|
return name.split('/')[0]
|
|
|
|
def get_ifc_name(self, name):
|
|
return name.split('/')[1]
|
|
|
|
def is_a_spatial_structure_element(self, class_name):
|
|
return class_name in ['IfcBuilding', 'IfcBuildingStorey', 'IfcSite'] # TODO: unhardcode
|
|
|
|
def is_a_context(self, class_name):
|
|
return class_name in ['IfcProject', 'IfcProjectLibrary'] # TODO: unhardcode
|
|
|
|
class IfcExporter():
|
|
def __init__(self, ifc_parser, ifc_schema):
|
|
self.template_file = '/home/dion/Projects/blender-bim-ifc/template.ifc'
|
|
self.output_file = '/home/dion/Projects/blender-bim-ifc/output.ifc'
|
|
self.data_dir = '/home/dion/Projects/blender-bim-ifc/data/'
|
|
self.ifc_parser = ifc_parser
|
|
self.ifc_schema = ifc_schema
|
|
|
|
def export(self):
|
|
self.file = ifcopenshell.open(self.template_file)
|
|
self.set_common_definitions()
|
|
self.parse_objects_into_ifc_data()
|
|
self.create_rep_context()
|
|
self.create_context()
|
|
self.create_spatial_structure_elements(self.ifc_parser.spatial_structure_elements_tree)
|
|
self.create_products()
|
|
self.relate_elements_to_spatial_structures()
|
|
self.file.write(self.output_file)
|
|
|
|
def set_common_definitions(self):
|
|
self.origin = self.file.by_type("IfcAxis2Placement3D")[0]
|
|
# Owner history doesn't actually work like this, but for now, it does :)
|
|
self.owner_history = self.file.by_type("ifcownerhistory")[0]
|
|
|
|
def parse_objects_into_ifc_data(self):
|
|
self.ifc_parser.parse()
|
|
|
|
def create_rep_context(self):
|
|
self.ifc_rep_context = self.file.createIfcGeometricRepresentationContext(
|
|
None, "Model",
|
|
3, 1.0E-05,
|
|
self.origin,
|
|
self.file.createIfcDirection((0., 1., 0.)))
|
|
|
|
self.ifc_rep_subcontext = self.file.createIfcGeometricRepresentationSubContext(
|
|
"Body", "Model",
|
|
None, None, None, None,
|
|
self.ifc_rep_context, None, "MODEL_VIEW", None)
|
|
|
|
def create_context(self):
|
|
context = self.ifc_parser.context
|
|
attributes = context['attributes']
|
|
attributes.update({
|
|
'GlobalId': ifcopenshell.guid.new(),
|
|
'RepresentationContexts': [self.ifc_rep_context],
|
|
'UnitsInContext': self.file.by_type("IfcUnitAssignment")[0]
|
|
})
|
|
self.ifc_parser.context['ifc'] = self.file.create_entity(self.ifc_parser.context['class'], **attributes)
|
|
|
|
def create_spatial_structure_elements(self, element_tree, relating_object=None):
|
|
if relating_object == None:
|
|
relating_object = self.ifc_parser.context['ifc']
|
|
placement_rel_to = None
|
|
else:
|
|
placement_rel_to = relating_object.ObjectPlacement
|
|
related_objects = []
|
|
for node in element_tree:
|
|
element = self.ifc_parser.spatial_structure_elements[node['reference']]
|
|
element['attributes'].update({
|
|
'GlobalId': ifcopenshell.guid.new(), # TODO: unhardcode
|
|
'OwnerHistory': self.owner_history, # TODO: unhardcode
|
|
'ObjectPlacement': self.file.createIfcLocalPlacement(placement_rel_to, self.origin)
|
|
})
|
|
element['ifc'] = self.file.create_entity(element['class'], **element['attributes'])
|
|
related_objects.append(element['ifc'])
|
|
self.create_spatial_structure_elements(node['children'], element['ifc'])
|
|
if related_objects:
|
|
self.file.createIfcRelAggregates(
|
|
ifcopenshell.guid.new(),
|
|
self.owner_history, None, None, relating_object, related_objects)
|
|
|
|
def create_products(self):
|
|
for product in self.ifc_parser.products:
|
|
object = product['raw']
|
|
placement_rel_to = self.ifc_parser.spatial_structure_elements[product['relating_structure']]['ifc'].ObjectPlacement
|
|
placement = self.file.createIfcLocalPlacement(placement_rel_to,
|
|
self.file.createIfcAxis2Placement3D(
|
|
self.file.createIfcCartesianPoint(
|
|
(object.location.x, object.location.y, object.location.z))))
|
|
representation = self.create_representation(object)
|
|
product['ifc'] = self.file.createIfcBuildingElementProxy(
|
|
ifcopenshell.guid.new(),
|
|
self.owner_history, object.name, None, None, placement, representation, None, None)
|
|
|
|
def create_representation(self, object):
|
|
ifc_vertices = []
|
|
ifc_faces = []
|
|
|
|
for vertice in object.data.vertices:
|
|
ifc_vertices.append(
|
|
self.file.createIfcCartesianPoint((vertice.co.x, vertice.co.y, vertice.co.z)))
|
|
for polygon in object.data.polygons:
|
|
ifc_faces.append(self.file.createIfcFace([
|
|
self.file.createIfcFaceOuterBound(
|
|
self.file.createIfcPolyLoop([ifc_vertices[vertice] for vertice in polygon.vertices]),
|
|
True)]))
|
|
|
|
return self.file.createIfcProductDefinitionShape(None, None,
|
|
[self.file.createIfcShapeRepresentation(
|
|
self.ifc_rep_subcontext, 'Body', 'Brep',
|
|
[self.file.createIfcFacetedBrep(self.file.createIfcClosedShell(ifc_faces))])])
|
|
|
|
def relate_elements_to_spatial_structures(self):
|
|
for relating_structure, related_elements in self.ifc_parser.rel_contained_in_spatial_structure.items():
|
|
self.file.createIfcRelContainedInSpatialStructure(
|
|
ifcopenshell.guid.new(), self.owner_history, None, None,
|
|
[ self.ifc_parser.products[e]['ifc'] for e in related_elements],
|
|
self.ifc_parser.spatial_structure_elements[relating_structure]['ifc'])
|
|
|
|
|
|
|
|
ifc_parser = IfcParser()
|
|
ifc_schema = IfcSchema()
|
|
ifc_exporter = IfcExporter(ifc_parser, ifc_schema)
|
|
ifc_exporter.export()
|