Schema versions are no longer locked to IFC4 and 2X3. You can now load express schemas at run time.

This commit is contained in:
Dion Moult
2022-01-10 10:45:46 +11:00
parent 6c991ed356
commit 43c74010a5
20 changed files with 282 additions and 14 deletions
+3 -1
View File
@@ -1,5 +1,5 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
# Copyright (C) 2020, 2021, 2022 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
@@ -47,6 +47,7 @@ class IfcStore:
last_transaction = ""
history = []
future = []
schema_identifiers = ["IFC4", "IFC2X3"]
@staticmethod
def purge():
@@ -63,6 +64,7 @@ class IfcStore:
IfcStore.pset_template_file = None
IfcStore.library_path = ""
IfcStore.library_file = None
IfcStore.schema_identifiers = ["IFC4", "IFC2X3"]
@staticmethod
def get_file():
@@ -20,18 +20,20 @@ import bpy
from . import ui, prop, operator
classes = (
operator.PrintIfcFile,
operator.PurgeIfcLinks,
operator.PrintObjectPlacement,
operator.ValidateIfcFile,
operator.ProfileImportIFC,
operator.CreateAllShapes,
operator.CreateShapeFromStepId,
operator.InspectFromObject,
operator.InspectFromStepId,
operator.ParseExpress,
operator.PrintIfcFile,
operator.PrintObjectPlacement,
operator.ProfileImportIFC,
operator.PurgeIfcLinks,
operator.RewindInspector,
operator.SelectExpressFile,
operator.SelectHighPolygonMeshes,
operator.SelectHighestPolygonMeshes,
operator.InspectFromStepId,
operator.InspectFromObject,
operator.RewindInspector,
operator.ValidateIfcFile,
prop.BIMDebugProperties,
ui.BIM_PT_debug,
)
@@ -16,14 +16,18 @@
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import os
import bpy
import time
import logging
import ifcopenshell
import ifcopenshell.util.placement
import ifcopenshell.util.representation
import blenderbim.tool as tool
import blenderbim.core.debug as core
import blenderbim.bim.handler
import blenderbim.bim.import_ifc as import_ifc
import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore
@@ -296,3 +300,31 @@ class PrintObjectPlacement(bpy.types.Operator):
def execute(self, context):
print(ifcopenshell.util.placement.get_local_placement(IfcStore.get_file().by_id(self.step_id)))
return {"FINISHED"}
class ParseExpress(bpy.types.Operator):
bl_idname = "bim.parse_express"
bl_label = "Parse Express"
def execute(self, context):
core.parse_express(tool.Debug, context.scene.BIMDebugProperties.express_file)
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
class SelectExpressFile(bpy.types.Operator):
bl_idname = "bim.select_express_file"
bl_label = "Select Express File"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Select an IFC EXPRESS definition"
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
filter_glob: bpy.props.StringProperty(default="*.exp", options={"HIDDEN"})
def execute(self, context):
if os.path.exists(self.filepath) and "exp" in os.path.splitext(self.filepath)[1]:
context.scene.BIMDebugProperties.express_file = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
@@ -39,3 +39,4 @@ class BIMDebugProperties(PropertyGroup):
attributes: CollectionProperty(name="Attributes", type=Attribute)
inverse_attributes: CollectionProperty(name="Inverse Attributes", type=Attribute)
inverse_references: CollectionProperty(name="Inverse References", type=Attribute)
express_file: StringProperty(name="Express File")
@@ -38,6 +38,11 @@ class BIM_PT_debug(Panel):
row.operator("bim.validate_ifc_file", icon="CHECKMARK", text="")
row.operator("bim.select_ifc_file", icon="FILE_FOLDER", text="")
row = self.layout.row(align=True)
row.prop(props, "express_file", text="")
row.operator("bim.parse_express", icon="IMPORT", text="")
row.operator("bim.select_express_file", icon="FILE_FOLDER", text="")
row = layout.row()
row.operator("bim.print_ifc_file")
@@ -0,0 +1,39 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore
def refresh():
ProjectData.is_loaded = False
class ProjectData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {"export_schema": cls.get_export_schema()}
cls.is_loaded = True
@classmethod
def get_export_schema(cls):
return [(s, s, "") for s in IfcStore.schema_identifiers]
@@ -57,7 +57,7 @@ class CreateProject(bpy.types.Operator):
return {"FINISHED"}
IfcStore.file = ifcopenshell.api.run(
"project.create_file", **{"version": context.scene.BIMProperties.export_schema}
"project.create_file", **{"version": context.scene.BIMProjectProperties.export_schema}
)
self.file = IfcStore.get_file()
@@ -18,18 +18,26 @@
import bpy
import ifcopenshell.util.placement
from blenderbim.bim.module.project.data import ProjectData
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.prop import StrProperty
from bpy.types import PropertyGroup
from bpy.props import (
StringProperty,
BoolProperty,
CollectionProperty,
EnumProperty,
FloatProperty,
IntProperty,
CollectionProperty,
StringProperty,
)
def get_export_schema(self, context):
if not ProjectData.is_loaded:
ProjectData.load()
return ProjectData.data["export_schema"]
def update_filter_mode(self, context):
self.filter_categories.clear()
if self.filter_mode == "NONE":
@@ -123,6 +131,7 @@ class BIMProjectProperties(PropertyGroup):
model_offset_coordinates: StringProperty(name="Model Offset Coordinates", default="0,0,0")
links: CollectionProperty(name="Links", type=Link)
active_link_index: IntProperty(name="Active Link Index")
export_schema: EnumProperty(items=get_export_schema, name="IFC Schema")
def get_library_element_index(self, lib_element):
return next((i for i in range(len(self.library_elements)) if self.library_elements[i] == lib_element))
@@ -19,6 +19,7 @@
import os
from bpy.types import Panel, UIList
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.project.data import ProjectData
class BIM_PT_project(Panel):
@@ -29,6 +30,9 @@ class BIM_PT_project(Panel):
bl_context = "scene"
def draw(self, context):
if not ProjectData.is_loaded:
ProjectData.load()
self.layout.use_property_decorate = False
self.layout.use_property_split = True
props = context.scene.BIMProperties
@@ -148,8 +152,9 @@ class BIM_PT_project(Panel):
def draw_create_project_ui(self, context):
props = context.scene.BIMProperties
pprops = context.scene.BIMProjectProperties
row = self.layout.row()
row.prop(props, "export_schema")
row.prop(pprops, "export_schema")
row = self.layout.row()
row.prop(context.scene.unit_settings, "system")
row = self.layout.row()
-1
View File
@@ -248,7 +248,6 @@ class BIMProperties(PropertyGroup):
default=os.path.join(cwd, "data") + os.path.sep, name="Data Directory", update=update_data_dir
)
ifc_file: StringProperty(name="IFC File", update=update_ifc_file)
export_schema: EnumProperty(items=[("IFC4", "IFC4", ""), ("IFC2X3", "IFC2X3", "")], name="IFC Schema")
last_transaction: StringProperty(name="Last Transaction")
should_section_selected_objects: BoolProperty(name="Section Selected Objects", default=False)
section_plane_colour: FloatVectorProperty(
+21
View File
@@ -0,0 +1,21 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
def parse_express(debug, filename):
debug.add_schema_identifier(debug.load_express(filename))
+6
View File
@@ -82,6 +82,12 @@ class Context:
def set_context(cls, context): pass
@interface
class Debug:
def add_schema_identifier(cls, schema): pass
def load_express(cls, filename): pass
@interface
class Drawing:
def disable_editing_text(cls, obj): pass
@@ -21,6 +21,7 @@ from blenderbim.tool.blender import Blender
from blenderbim.tool.brick import Brick
from blenderbim.tool.collector import Collector
from blenderbim.tool.context import Context
from blenderbim.tool.debug import Debug
from blenderbim.tool.drawing import Drawing
from blenderbim.tool.geometry import Geometry
from blenderbim.tool.ifc import Ifc
+34
View File
@@ -0,0 +1,34 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import ifcopenshell.express
import blenderbim.core.tool
from blenderbim.bim.ifc import IfcStore
class Debug(blenderbim.core.tool.Debug):
@classmethod
def add_schema_identifier(cls, schema):
IfcStore.schema_identifiers.append(schema.schema_name)
@classmethod
def load_express(cls, filename):
schema = ifcopenshell.express.parse(filename)
ifcopenshell.register_schema(schema)
return schema
+1
View File
@@ -5,6 +5,7 @@ markers =
bimtester
brick
context
debug
drawing
geometry
library
@@ -0,0 +1,13 @@
@debug
Feature: Debug
Scenario: Select express file
Given an empty Blender session
When I press "bim.select_express_file(filepath='{cwd}/test/files/test.exp')"
Then nothing happens
Scenario: Parse express
Given an empty Blender session
And I press "bim.select_express_file(filepath='{cwd}/test/files/test.exp')"
When I press "bim.parse_express"
Then nothing happens
+7
View File
@@ -63,6 +63,13 @@ def context():
prophet.verify()
@pytest.fixture
def debug():
prophet = Prophecy(blenderbim.core.tool.Debug)
yield prophet
prophet.verify()
@pytest.fixture
def drawing():
prophet = Prophecy(blenderbim.core.tool.Drawing)
+27
View File
@@ -0,0 +1,27 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import blenderbim.core.debug as subject
from test.core.bootstrap import debug
class TestParseExpress:
def test_run(self, debug):
debug.load_express("filename").should_be_called().will_return("schema")
debug.add_schema_identifier("schema").should_be_called()
subject.parse_express(debug, "filename")
+19
View File
@@ -0,0 +1,19 @@
SCHEMA IFCROGUE;
TYPE IfcDonkeyPowerMeasure = REAL;
END_TYPE;
TYPE IfcLabel = STRING(255);
END_TYPE;
ENTITY IfcBurbRoot
SUBTYPE OF (IfcRoot);
AcidDamage : OPTIONAL IfcDonkeyPowerMeasure;
END_ENTITY;
ENTITY IfcRoot
ABSTRACT SUPERTYPE OF (IfcBurbRoot);
Name : OPTIONAL IfcLabel;
END_ENTITY;
END_SCHEMA;
+45
View File
@@ -0,0 +1,45 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import os
import bpy
import ifcopenshell
import blenderbim.core.tool
import blenderbim.tool as tool
from test.bim.bootstrap import NewFile
from blenderbim.tool.debug import Debug as subject
from blenderbim.bim.ifc import IfcStore
class TestImplementsTool(NewFile):
def test_run(self):
assert isinstance(subject(), blenderbim.core.tool.Debug)
class TestAddSchemaIdentifier(NewFile):
def test_run(self):
subject.add_schema_identifier(TestLoadExpress().test_run())
assert IfcStore.schema_identifiers[-1] == "IFCROGUE"
class TestLoadExpress(NewFile):
def test_run(self):
cwd = os.path.dirname(os.path.realpath(__file__))
schema = subject.load_express(os.path.join(cwd, "..", "files", "test.exp"))
assert schema.schema_name == "IFCROGUE"
return schema