diff --git a/src/blenderbim/blenderbim/bim/helper.py b/src/blenderbim/blenderbim/bim/helper.py index 0a0bbdcec0..9a8320aba5 100644 --- a/src/blenderbim/blenderbim/bim/helper.py +++ b/src/blenderbim/blenderbim/bim/helper.py @@ -97,3 +97,37 @@ def export_attributes(props, callback=None): continue # Our job is done attributes[prop.name] = prop.get_value() return attributes + + +class IFCHeaderSpecs: + def __init__(self, filepath: str): + # According to https://www.steptools.com/stds/step/IS_final_p21e3.html#clause-8 + self.description = "" + self.implementation_level = "" + self.name = "" + self.time_stamp = "" + self.author = "" + self.organization = "" + self.preprocessor_version = "" + self.originating_system = "" + self.authorization = "" + self.schema_name = "" + with open(filepath) as ifc_file: + max_lines_to_parse = 50 + for _ in range(max_lines_to_parse): + line = next(ifc_file) + if line.startswith("FILE_DESCRIPTION"): + for i, part in enumerate(line.split("'")): + if i == 1: + self.description = part + elif i == 3: + self.implementation_level = part + elif line.startswith("FILE_NAME"): + for i, part in enumerate(line.split("'")): + if i == 1: + self.name = part + elif i == 3: + self.time_stamp = part + elif line.startswith("FILE_SCHEMA"): + self.schema_name = line.split("'")[1] + break diff --git a/src/blenderbim/blenderbim/bim/module/project/operator.py b/src/blenderbim/blenderbim/bim/module/project/operator.py index fb683d88af..973b0d140d 100644 --- a/src/blenderbim/blenderbim/bim/module/project/operator.py +++ b/src/blenderbim/blenderbim/bim/module/project/operator.py @@ -30,6 +30,7 @@ import blenderbim.tool as tool import blenderbim.core.context import blenderbim.core.owner from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.ui import IFCFileSelector from blenderbim.bim import import_ifc from blenderbim.bim import export_ifc from ifcopenshell.api.context.data import Data as ContextData @@ -126,7 +127,7 @@ class CreateProject(bpy.types.Operator): IfcStore.file = data["file"] -class SelectLibraryFile(bpy.types.Operator): +class SelectLibraryFile(bpy.types.Operator, IFCFileSelector): bl_idname = "bim.select_library_file" bl_label = "Select Library File" bl_options = {"REGISTER", "UNDO"} @@ -539,7 +540,7 @@ class DisableEditingHeader(bpy.types.Operator): return {"FINISHED"} -class LoadProject(bpy.types.Operator): +class LoadProject(bpy.types.Operator, IFCFileSelector): bl_idname = "bim.load_project" bl_label = "Load Project" bl_options = {"REGISTER", "UNDO"} @@ -549,7 +550,7 @@ class LoadProject(bpy.types.Operator): is_advanced: bpy.props.BoolProperty(name="Enable Advanced Mode", default=False) def execute(self, context): - if not os.path.exists(self.filepath) or "ifc" not in os.path.splitext(self.filepath)[1].lower(): + if not self.is_existing_ifc_file(): return {"FINISHED"} context.scene.BIMProperties.ifc_file = self.filepath context.scene.BIMProjectProperties.is_loading = True @@ -561,6 +562,10 @@ class LoadProject(bpy.types.Operator): context.window_manager.fileselect_add(self) return {"RUNNING_MODAL"} + def draw(self, context): + self.layout.prop(self, "is_advanced") + IFCFileSelector.draw(self, context) + class UnloadProject(bpy.types.Operator): bl_idname = "bim.unload_project" diff --git a/src/blenderbim/blenderbim/bim/operator.py b/src/blenderbim/blenderbim/bim/operator.py index c7d009990e..119acc4b25 100644 --- a/src/blenderbim/blenderbim/bim/operator.py +++ b/src/blenderbim/blenderbim/bim/operator.py @@ -22,9 +22,9 @@ import json import webbrowser import ifcopenshell import blenderbim.bim.handler -from pathlib import Path from . import schema from blenderbim.bim.ifc import IfcStore +from blenderbim.bim.ui import IFCFileSelector from mathutils import Vector, Matrix, Euler from math import radians @@ -39,7 +39,7 @@ class OpenUri(bpy.types.Operator): return {"FINISHED"} -class SelectIfcFile(bpy.types.Operator): +class SelectIfcFile(bpy.types.Operator, IFCFileSelector): bl_idname = "bim.select_ifc_file" bl_label = "Select IFC File" bl_options = {"REGISTER", "UNDO"} @@ -47,11 +47,6 @@ class SelectIfcFile(bpy.types.Operator): filepath: bpy.props.StringProperty(subtype="FILE_PATH") filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"}) - def is_existing_ifc_file(self, filepath=None): - if filepath is None: - filepath = self.filepath - return os.path.exists(filepath) and "ifc" in os.path.splitext(filepath)[1].lower() - def execute(self, context): if self.is_existing_ifc_file(): context.scene.BIMProperties.ifc_file = self.filepath @@ -61,25 +56,6 @@ class SelectIfcFile(bpy.types.Operator): context.window_manager.fileselect_add(self) return {"RUNNING_MODAL"} - def draw(self, context): - # Access filepath & Directory https://blender.stackexchange.com/a/207665 - params = context.space_data.params - # Decode byte string https://stackoverflow.com/a/47737082/ - directory = Path(params.directory.decode("utf-8")) - filepath = os.path.join(directory, params.filename) - if self.is_existing_ifc_file(filepath): - self.draw_ifc_specs(filepath) - - def draw_ifc_specs(self, filepath): - with open(filepath) as ifc_file: - max_lines_to_parse = 50 - for _ in range(max_lines_to_parse): - line = next(ifc_file) - if line.startswith("FILE_SCHEMA(('") and line.endswith("'));\n"): - schema = line.split("'")[1] - self.layout.label(text=f"File Schema : {schema}") - break - class SelectDataDir(bpy.types.Operator): bl_idname = "bim.select_data_dir" diff --git a/src/blenderbim/blenderbim/bim/ui.py b/src/blenderbim/blenderbim/bim/ui.py index ce7fd3bdd8..a3f2992006 100644 --- a/src/blenderbim/blenderbim/bim/ui.py +++ b/src/blenderbim/blenderbim/bim/ui.py @@ -18,9 +18,34 @@ import os import bpy +from pathlib import Path from . import ifc from bpy.types import Panel from bpy.props import StringProperty, IntProperty, BoolProperty +from blenderbim.bim.helper import IFCHeaderSpecs + + +class IFCFileSelector: + def is_existing_ifc_file(self, filepath=None): + if filepath is None: + filepath = self.filepath + return os.path.exists(filepath) and "ifc" in os.path.splitext(filepath)[1].lower() + + def draw(self, context): + # Access filepath & Directory https://blender.stackexchange.com/a/207665 + params = context.space_data.params + # Decode byte string https://stackoverflow.com/a/47737082/ + directory = Path(params.directory.decode("utf-8")) + filepath = os.path.join(directory, params.filename) + if self.is_existing_ifc_file(filepath): + box = self.layout.box() + box.label(text="IFC Header Specifications", icon="INFO") + ifc_specs = IFCHeaderSpecs(filepath) + for attr_name, attr_value in ifc_specs.__dict__.items(): + if attr_value != "": + split = box.split() + split.label(text=attr_name.title().replace("_", " ")) + split.label(text=str(attr_value)) class BIM_PT_section_plane(Panel): @@ -163,7 +188,7 @@ class BIM_PT_collaboration_and_data_exchange(Panel): def draw(self, context): pass - + class BIM_PT_geometry_and_spatial_structure(Panel): bl_label = "IFC Geometry and Spatial Structure" @@ -174,7 +199,7 @@ class BIM_PT_geometry_and_spatial_structure(Panel): def draw(self, context): pass - + class BIM_PT_4D5D(Panel): bl_label = "IFC 4D/5D" @@ -196,7 +221,7 @@ class BIM_PT_structural(Panel): def draw(self, context): pass - + class BIM_PT_misc(Panel): bl_label = "IFC Misc." @@ -207,7 +232,7 @@ class BIM_PT_misc(Panel): def draw(self, context): pass - + class BIM_PT_quality_control(Panel): bl_label = "IFC Quality Control" @@ -230,7 +255,7 @@ class BIM_PT_geometry_and_spatial_structure_object(Panel): def draw(self, context): pass - + class BIM_PT_object_attributes_properties_and_relationships(Panel): bl_label = "IFC Object Attributes, Properties and Relationships"