diff --git a/src/ifcblenderexport/io_export_ifc/__init__.py b/src/ifcblenderexport/io_export_ifc/__init__.py index 52496c190f..98e9889181 100644 --- a/src/ifcblenderexport/io_export_ifc/__init__.py +++ b/src/ifcblenderexport/io_export_ifc/__init__.py @@ -7,62 +7,26 @@ bl_info = { "location": "File > Export", "tracker_url": "https://sourceforge.net/p/ifcopenshell/" "_list/tickets?source=navbar", - "category": "Import-Export"} - -if "bpy" in locals(): - from importlib import reload - reload(export) - del reload + "category": "Import-Export" + } import bpy -import time -from . import export from . import ui -import os - -cwd = os.path.dirname(os.path.realpath(__file__)) + os.path.sep - -class ExportIFC(bpy.types.Operator): - bl_idname = "export.ifc" - bl_label = "Export .ifc file" - filename_ext = ".ifc" - filepath: bpy.props.StringProperty(subtype='FILE_PATH') - - def invoke(self, context, event): - if not self.filepath: - self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".ifc") - WindowManager = context.window_manager - WindowManager.fileselect_add(self) - return {'RUNNING_MODAL'} - - def execute(self, context): - print('# Starting export') - start = time.time() - ifc_export_settings = export.IfcExportSettings() - ifc_export_settings.data_dir = bpy.context.scene.BIMProperties.data_dir - ifc_export_settings.schema_dir = bpy.context.scene.BIMProperties.schema_dir - ifc_export_settings.output_file = bpy.path.ensure_ext(self.filepath, '.ifc') - 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_exporter.export() - print('# Export finished in {:.2f} seconds'.format(time.time() - start)) - return {'FINISHED'} - -def menu_func(self, context): - self.layout.operator(ExportIFC.bl_idname, - text="Industry Foundation Classes (.ifc)") +from . import operator classes = ( - ui.BIMOpAssignClass, - ui.BIMOpSelectDataDir, - ui.BIMOpSelectSchemaDir, + operator.AssignClass, + operator.SelectDataDir, + operator.SelectSchemaDir, + operator.ExportIFC, ui.BIMProperties, ui.BIMPanel, - ExportIFC, ) +def menu_func(self, context): + self.layout.operator(operator.ExportIFC.bl_idname, + text="Industry Foundation Classes (.ifc)") + def register(): for cls in classes: bpy.utils.register_class(cls) diff --git a/src/ifcblenderexport/io_export_ifc/export.py b/src/ifcblenderexport/io_export_ifc/export.py index 7e0e420d9b..30203d60b7 100644 --- a/src/ifcblenderexport/io_export_ifc/export.py +++ b/src/ifcblenderexport/io_export_ifc/export.py @@ -649,7 +649,7 @@ class IfcParser(): index += 1 except Exception as e: - print('The type product "{}" could not be parsed: {}'.format(object.name, e.args)) + self.ifc_export_settings.logger.error('The type product "{}" could not be parsed: {}'.format(object.name, e.args)) return results def get_object_representation_names(self, object): @@ -701,7 +701,7 @@ class IfcParser(): try: return name.split('/')[1] except IndexError: - print('ERROR: Name "{}" does not follow the format of "IfcClass/Name"'.format(name)) + self.ifc_export_settings.logger.error('Name "{}" does not follow the format of "IfcClass/Name"'.format(name)) def is_a_spatial_structure_element(self, class_name): # We assume that any collection we can't identify is a spatial structure @@ -965,7 +965,7 @@ class IfcExporter(): try: product['ifc'] = self.file.create_entity(product['class'], **product['attributes']) except RuntimeError as e: - print('The type product "{}/{}" could not be created: {}'.format(product['class'], product['attributes']['Name'], e.args)) + self.ifc_export_settings.logger.error('The type product "{}/{}" could not be created: {}'.format(product['class'], product['attributes']['Name'], e.args)) def add_predefined_attributes_to_type_product(self, product, attributes): self.create_predefined_attributes(attributes) @@ -1104,7 +1104,7 @@ class IfcExporter(): try: product['ifc'] = self.file.create_entity(product['class'], **product['attributes']) except RuntimeError as e: - print('The product "{}/{}" could not be created: {}'.format(product['class'], product['attributes']['Name'], e.args)) + self.ifc_export_settings.logger.error('The product "{}/{}" could not be created: {}'.format(product['class'], product['attributes']['Name'], e.args)) def get_product_shape(self, product): try: @@ -1135,7 +1135,7 @@ class IfcExporter(): vg.name.split('/')[1], None, self.ifc_parser.units['volume']['ifc'], quantity)) if not quantity: - print('Warning: the calculated quantity {} for {} is zero.'.format( + self.ifc_export_settings.logger.warning('The calculated quantity {} for {} is zero.'.format( vg.name, object.name)) return quantities @@ -1414,6 +1414,7 @@ class IfcExporter(): class IfcExportSettings: def __init__(self): + self.logger = None self.schema_dir = None self.data_dir = None self.output_file = None diff --git a/src/ifcblenderexport/io_export_ifc/operator.py b/src/ifcblenderexport/io_export_ifc/operator.py new file mode 100644 index 0000000000..d2244a76b3 --- /dev/null +++ b/src/ifcblenderexport/io_export_ifc/operator.py @@ -0,0 +1,90 @@ +import bpy +import time +import logging +from . import export + +class ExportIFC(bpy.types.Operator): + bl_idname = "export.ifc" + bl_label = "Export .ifc file" + filename_ext = ".ifc" + filepath: bpy.props.StringProperty(subtype='FILE_PATH') + + def invoke(self, context, event): + if not self.filepath: + self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".ifc") + WindowManager = context.window_manager + WindowManager.fileselect_add(self) + return {'RUNNING_MODAL'} + + def execute(self, context): + start = time.time() + ifc_export_settings = export.IfcExportSettings() + logging.basicConfig( + filename=bpy.context.scene.BIMProperties.data_dir + 'export.log', + filemode='a', level=logging.DEBUG) + ifc_export_settings.logger = logging.getLogger('ExportIFC') + ifc_export_settings.logger.info('Starting export') + ifc_export_settings.data_dir = bpy.context.scene.BIMProperties.data_dir + ifc_export_settings.schema_dir = bpy.context.scene.BIMProperties.schema_dir + ifc_export_settings.output_file = bpy.path.ensure_ext(self.filepath, '.ifc') + 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_exporter.export() + ifc_export_settings.logger.info('Export 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' + + def execute(self, context): + for object in bpy.context.selected_objects: + existing_class = None + if '/' in object.name \ + and object.name[0:3] == 'Ifc': + existing_class = object.name.split('/')[0] + if existing_class: + object.name = '{}/{}'.format( + bpy.context.scene.BIMProperties.ifc_class, + object.name.split('/')[1]) + else: + object.name = '{}/{}'.format( + bpy.context.scene.BIMProperties.ifc_class, + object.name) + if existing_class != bpy.context.scene.BIMProperties.ifc_class \ + and 'IfcPredefinedType' in object.keys(): + del(object['IfcPredefinedType']) + object['IfcPredefinedType'] = bpy.context.scene.BIMProperties.ifc_predefined_type + if bpy.context.scene.BIMProperties.ifc_predefined_type == 'USERDEFINED': + object['IfcObjectType'] = bpy.context.scene.BIMProperties.ifc_userdefined_type + elif 'IfcObjectType' in object.keys(): + del(object['IfcObjectType']) + return {'FINISHED'} + +class SelectDataDir(bpy.types.Operator): + bl_idname = "bim.select_data_dir" + bl_label = "Select Data Directory" + filepath: bpy.props.StringProperty(subtype="FILE_PATH") + + def execute(self, context): + bpy.context.scene.BIMProperties.data_dir = self.filepath + return {'FINISHED'} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {'RUNNING_MODAL'} + +class SelectSchemaDir(bpy.types.Operator): + bl_idname = "bim.select_schema_dir" + bl_label = "Select Schema Directory" + filepath: bpy.props.StringProperty(subtype="FILE_PATH") + + def execute(self, context): + bpy.context.scene.BIMProperties.schema_dir = self.filepath + return {'FINISHED'} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {'RUNNING_MODAL'} diff --git a/src/ifcblenderexport/io_export_ifc/ui.py b/src/ifcblenderexport/io_export_ifc/ui.py index 36be3ddccb..fc047707fe 100644 --- a/src/ifcblenderexport/io_export_ifc/ui.py +++ b/src/ifcblenderexport/io_export_ifc/ui.py @@ -4,60 +4,6 @@ import os cwd = os.path.dirname(os.path.realpath(__file__)) + os.path.sep -class BIMOpAssignClass(bpy.types.Operator): - bl_idname = 'bim.assign_class' - bl_label = 'Assign IFC Class' - - def execute(self, context): - for object in bpy.context.selected_objects: - existing_class = None - if '/' in object.name \ - and object.name[0:3] == 'Ifc': - existing_class = object.name.split('/')[0] - if existing_class: - object.name = '{}/{}'.format( - bpy.context.scene.BIMProperties.ifc_class, - object.name.split('/')[1]) - else: - object.name = '{}/{}'.format( - bpy.context.scene.BIMProperties.ifc_class, - object.name) - if existing_class != bpy.context.scene.BIMProperties.ifc_class \ - and 'IfcPredefinedType' in object.keys(): - del(object['IfcPredefinedType']) - object['IfcPredefinedType'] = bpy.context.scene.BIMProperties.ifc_predefined_type - if bpy.context.scene.BIMProperties.ifc_predefined_type == 'USERDEFINED': - object['IfcObjectType'] = bpy.context.scene.BIMProperties.ifc_userdefined_type - elif 'IfcObjectType' in object.keys(): - del(object['IfcObjectType']) - return {'FINISHED'} - -class BIMOpSelectDataDir(bpy.types.Operator): - bl_idname = "bim.select_data_dir" - bl_label = "Select Data Directory" - filepath: bpy.props.StringProperty(subtype="FILE_PATH") - - def execute(self, context): - bpy.context.scene.BIMProperties.data_dir = self.filepath - return {'FINISHED'} - - def invoke(self, context, event): - context.window_manager.fileselect_add(self) - return {'RUNNING_MODAL'} - -class BIMOpSelectSchemaDir(bpy.types.Operator): - bl_idname = "bim.select_schema_dir" - bl_label = "Select Schema Directory" - filepath: bpy.props.StringProperty(subtype="FILE_PATH") - - def execute(self, context): - bpy.context.scene.BIMProperties.schema_dir = self.filepath - return {'FINISHED'} - - def invoke(self, context, event): - context.window_manager.fileselect_add(self) - return {'RUNNING_MODAL'} - class IfcSchema(): def __init__(self): with open('{}ifc_elements_IFC4.json'.format(cwd + 'schema/')) as f: