diff --git a/src/ifcblenderexport/import.py b/src/ifcblenderexport/import.py deleted file mode 100644 index e9e4282491..0000000000 --- a/src/ifcblenderexport/import.py +++ /dev/null @@ -1,84 +0,0 @@ -#import sys -#sys.path.append('C:/Program Files/Python37/Lib/site-packages') -import ifcopenshell -import ifcopenshell.geom -import bpy -import time -import mathutils - -class ImportIFC(): - def __init__(self): - self.file = None - self.settings = ifcopenshell.geom.settings() - self.meshes = {} - - def execute(self): - self.load_file() - n = 0 - elements = self.file.by_type('IfcElement') + self.file.by_type('IfcSpace') - for element in elements: - self.create_object(element) - n += 1 - if n > 1000: - break - - def load_file(self): - self.file = ifcopenshell.open('C:/cygwin64/home/moud308/Projects/IFCAudit/big.ifc') - - def create_object(self, element): - try: - if element.is_a('IfcOpeningElement'): - return - - shape = ifcopenshell.geom.create_shape(self.settings, element) - mesh_name = 'mesh-{}'.format(shape.geometry.id) - - mesh = self.meshes.get(mesh_name) - if mesh is None: - mesh = self.create_mesh(element, shape) - self.meshes[mesh_name] = mesh - else: - print('we reused a mesh!') - - materials = shape.geometry.materials - for material in materials: - if material.has_diffuse: - alpha = 1. - blender_material = bpy.data.materials.new('mymaterial') - blender_material.diffuse_color = material.diffuse + (alpha,) - mesh.materials.append(blender_material) - - object = bpy.data.objects.new('{}/{}'.format(element.is_a(), element.Name), mesh) - m = shape.transformation.matrix.data - matrix = mathutils.Matrix(( - [m[0], m[1], m[2], 0], - [m[3], m[4], m[5], 0], - [m[6], m[7], m[8], 0], - [m[9], m[10], m[11], 1])) - matrix.transpose() - object.matrix_world = matrix - bpy.context.scene.collection.objects.link(object) - except: - print('Could not create object for {}: {}/{}'.format( - element.GlobalId, element.is_a(), element.Name)) - - def create_mesh(self, element, shape): - try: - mesh = bpy.data.meshes.new(shape.geometry.id) - f = shape.geometry.faces - v = shape.geometry.verts - vertices = [[v[i], v[i + 1], v[i + 2]] - for i in range(0, len(v), 3)] - faces = [[f[i], f[i + 1], f[i + 2]] - for i in range(0, len(f), 3)] - mesh.from_pydata(vertices, [], faces) - return mesh - except: - print('Could not create mesh for {}: {}/{}'.format( - element.GlobalId, element.is_a(), element.Name)) - -print('# Starting import') -start = time.time() -import_ifc = ImportIFC() -import_ifc.execute() -print('# Finished in {}s'.format(time.time() - start)) diff --git a/src/ifcblenderexport/io_export_ifc/__init__.py b/src/ifcblenderexport/io_export_ifc/__init__.py index bd046a1205..9a3b7a2a9f 100644 --- a/src/ifcblenderexport/io_export_ifc/__init__.py +++ b/src/ifcblenderexport/io_export_ifc/__init__.py @@ -21,25 +21,32 @@ classes = ( operator.SelectDataDir, operator.SelectSchemaDir, operator.ExportIFC, + operator.ImportIFC, ui.BIMProperties, ui.BIMPanel, ui.MVDPanel, ) -def menu_func(self, context): +def menu_func_export(self, context): self.layout.operator(operator.ExportIFC.bl_idname, text="Industry Foundation Classes (.ifc)") +def menu_func_import(self, context): + self.layout.operator(operator.ImportIFC.bl_idname, + text="Industry Foundation Classes (.ifc)") + def register(): for cls in classes: bpy.utils.register_class(cls) - bpy.types.TOPBAR_MT_file_export.append(menu_func) + bpy.types.TOPBAR_MT_file_export.append(menu_func_export) + bpy.types.TOPBAR_MT_file_import.append(menu_func_import) bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=ui.BIMProperties) def unregister(): for cls in reversed(classes): bpy.utils.unregister_class(cls) - bpy.types.TOPBAR_MT_file_export.remove(menu_func) + bpy.types.TOPBAR_MT_file_export.remove(menu_func_export) + bpy.types.TOPBAR_MT_file_import.remove(menu_func_import) del(bpy.types.Scene.BIMProperties) if __name__ == "__main__": diff --git a/src/ifcblenderexport/io_export_ifc/export.py b/src/ifcblenderexport/io_export_ifc/export_ifc.py similarity index 99% rename from src/ifcblenderexport/io_export_ifc/export.py rename to src/ifcblenderexport/io_export_ifc/export_ifc.py index 41c5f982d9..5d995d28bb 100644 --- a/src/ifcblenderexport/io_export_ifc/export.py +++ b/src/ifcblenderexport/io_export_ifc/export_ifc.py @@ -747,7 +747,6 @@ class SIUnitHelper: class IfcExporter(): def __init__(self, ifc_export_settings, ifc_schema, ifc_parser, qto_calculator): self.template_file = '{}template.ifc'.format(ifc_export_settings.schema_dir) - self.output_file = ifc_export_settings.output_file self.ifc_export_settings = ifc_export_settings self.ifc_schema = ifc_schema self.ifc_parser = ifc_parser @@ -790,7 +789,7 @@ class IfcExporter(): self.relate_to_classifications(self.ifc_parser.rel_associates_classification_type) self.relate_to_objectives(self.ifc_parser.rel_associates_constraint_objective_object) self.relate_to_objectives(self.ifc_parser.rel_associates_constraint_objective_type) - self.file.write(self.output_file) + self.file.write(self.ifc_export_settings.output_file) def set_common_definitions(self): # Owner history doesn't actually work like this, but for now, it does :) diff --git a/src/ifcblenderexport/io_export_ifc/import_ifc.py b/src/ifcblenderexport/io_export_ifc/import_ifc.py new file mode 100644 index 0000000000..d9efff0739 --- /dev/null +++ b/src/ifcblenderexport/io_export_ifc/import_ifc.py @@ -0,0 +1,113 @@ +from . import ifcopenshell +from .ifcopenshell import geom +import bpy +import mathutils + +class IfcImporter(): + def __init__(self, ifc_import_settings): + self.ifc_import_settings = ifc_import_settings + self.file = None + self.settings = ifcopenshell.geom.settings() + self.project = None + self.spatial_structure_elements = {} + self.elements = {} + self.meshes = {} + + def execute(self): + self.load_file() + self.create_project() + self.create_spatial_hierarchy() + elements = self.file.by_type('IfcElement') + self.file.by_type('IfcSpace') + for element in elements: + self.create_object(element) + + def load_file(self): + print('loading file {}'.format(self.ifc_import_settings.input_file)) + self.file = ifcopenshell.open(self.ifc_import_settings.input_file) + + def create_project(self): + self.project = { 'ifc': self.file.by_type('IfcProject')[0] } + self.project['blender'] = bpy.data.collections.new('IfcProject/{}'.format(self.project['ifc'].Name)) + bpy.context.scene.collection.children.link(self.project['blender']) + + def create_spatial_hierarchy(self): + elements = self.file.by_type('IfcSpatialStructureElement') + while len(self.spatial_structure_elements) < len(elements): + for element in elements: + parent = element.Decomposes[0].RelatingObject + parent_name = self.get_name(parent) + name = self.get_name(element) + if name in self.spatial_structure_elements: + continue + if parent.is_a('IfcProject'): + self.spatial_structure_elements[name] = { + 'blender': bpy.data.collections.new(name)} + self.project['blender'].children.link(self.spatial_structure_elements[name]['blender']) + elif parent_name in self.spatial_structure_elements: + self.spatial_structure_elements[name] = { + 'blender': bpy.data.collections.new(name)} + self.spatial_structure_elements[parent_name]['blender'].children.link( + self.spatial_structure_elements[name]['blender']) + + def get_name(self, element): + return '{}/{}'.format(element.is_a(), element.Name) + + def create_object(self, element): + if element.is_a('IfcOpeningElement'): + return + + shape = ifcopenshell.geom.create_shape(self.settings, element) + mesh_name = 'mesh-{}'.format(shape.geometry.id) + + mesh = self.meshes.get(mesh_name) + if mesh is None: + mesh = self.create_mesh(element, shape) + self.meshes[mesh_name] = mesh + else: + print('we reused a mesh!') + + materials = shape.geometry.materials + for material in materials: + if material.has_diffuse: + alpha = 1. + blender_material = bpy.data.materials.new('mymaterial') + blender_material.diffuse_color = material.diffuse + (alpha,) + mesh.materials.append(blender_material) + + object = bpy.data.objects.new(self.get_name(element), mesh) + m = shape.transformation.matrix.data + matrix = mathutils.Matrix(( + [m[0], m[1], m[2], 0], + [m[3], m[4], m[5], 0], + [m[6], m[7], m[8], 0], + [m[9], m[10], m[11], 1])) + matrix.transpose() + object.matrix_world = matrix + + if element.ContainedInStructure \ + and element.ContainedInStructure[0].RelatingStructure: + structure_name = self.get_name(element.ContainedInStructure[0].RelatingStructure) + if structure_name in self.spatial_structure_elements: + self.spatial_structure_elements[structure_name]['blender'].objects.link(object) + else: + bpy.context.scene.collection.objects.link(object) + + def create_mesh(self, element, shape): + try: + mesh = bpy.data.meshes.new(shape.geometry.id) + f = shape.geometry.faces + v = shape.geometry.verts + vertices = [[v[i], v[i + 1], v[i + 2]] + for i in range(0, len(v), 3)] + faces = [[f[i], f[i + 1], f[i + 2]] + for i in range(0, len(f), 3)] + mesh.from_pydata(vertices, [], faces) + return mesh + except: + print('Could not create mesh for {}: {}/{}'.format( + element.GlobalId, self.get_name(element))) + +class IfcImportSettings: + def __init__(self): + self.logger = None + self.input_file = None diff --git a/src/ifcblenderexport/io_export_ifc/operator.py b/src/ifcblenderexport/io_export_ifc/operator.py index d7840ca268..0a50d38ad5 100644 --- a/src/ifcblenderexport/io_export_ifc/operator.py +++ b/src/ifcblenderexport/io_export_ifc/operator.py @@ -1,7 +1,9 @@ import bpy import time import logging -from . import export +from . import export_ifc +from . import import_ifc +from bpy_extras.io_utils import ImportHelper class ExportIFC(bpy.types.Operator): bl_idname = "export.ifc" @@ -18,9 +20,9 @@ class ExportIFC(bpy.types.Operator): def execute(self, context): start = time.time() - ifc_export_settings = export.IfcExportSettings() + ifc_export_settings = export_ifc.IfcExportSettings() logging.basicConfig( - filename=bpy.context.scene.BIMProperties.data_dir + 'export.log', + filename=bpy.context.scene.BIMProperties.data_dir + 'process.log', filemode='a', level=logging.DEBUG) ifc_export_settings.logger = logging.getLogger('ExportIFC') ifc_export_settings.logger.info('Starting export') @@ -28,14 +30,35 @@ class ExportIFC(bpy.types.Operator): ifc_export_settings.schema_dir = bpy.context.scene.BIMProperties.schema_dir ifc_export_settings.output_file = bpy.path.ensure_ext(self.filepath, '.ifc') ifc_export_settings.has_representations = bpy.context.scene.BIMProperties.export_has_representations - ifc_parser = export.IfcParser(ifc_export_settings) - ifc_schema = export.IfcSchema(ifc_export_settings) - qto_calculator = export.QtoCalculator() - ifc_exporter = export.IfcExporter(ifc_export_settings, ifc_schema, ifc_parser, qto_calculator) + ifc_parser = export_ifc.IfcParser(ifc_export_settings) + ifc_schema = export_ifc.IfcSchema(ifc_export_settings) + qto_calculator = export_ifc.QtoCalculator() + ifc_exporter = export_ifc.IfcExporter(ifc_export_settings, ifc_schema, ifc_parser, qto_calculator) ifc_exporter.export() ifc_export_settings.logger.info('Export finished in {:.2f} seconds'.format(time.time() - start)) return {'FINISHED'} +class ImportIFC(bpy.types.Operator, ImportHelper): + bl_idname = "import.ifc" + bl_label = "Import .ifc file" + + filename_ext = ".ifc" + filter_glob: bpy.props.StringProperty(default="*.ifc", options={'HIDDEN'}) + + def execute(self, context): + start = time.time() + ifc_import_settings = import_ifc.IfcImportSettings() + logging.basicConfig( + filename=bpy.context.scene.BIMProperties.data_dir + 'process.log', + filemode='a', level=logging.DEBUG) + ifc_import_settings.logger = logging.getLogger('ImportIFC') + ifc_import_settings.logger.info('Starting import') + ifc_import_settings.input_file = self.filepath + ifc_importer = import_ifc.IfcImporter(ifc_import_settings) + ifc_importer.execute() + ifc_import_settings.logger.info('Import finished in {:.2f} seconds'.format(time.time() - start)) + return {'FINISHED'} + class AssignClass(bpy.types.Operator): bl_idname = 'bim.assign_class' bl_label = 'Assign IFC Class'