diff --git a/src/blenderbim/blenderbim/bim/__init__.py b/src/blenderbim/blenderbim/bim/__init__.py index 0ec9cfb9c7..d075705735 100644 --- a/src/blenderbim/blenderbim/bim/__init__.py +++ b/src/blenderbim/blenderbim/bim/__init__.py @@ -102,7 +102,7 @@ classes = [ ui.BIM_UL_generic, ui.BIM_UL_topics, ui.BIM_ADDON_preferences, - #scene panel groups --> + # scene panel groups --> ui.BIM_PT_project_setup, ui.BIM_PT_utilities, ui.BIM_PT_collaboration, @@ -112,12 +112,12 @@ classes = [ ui.BIM_PT_services, ui.BIM_PT_misc, ui.BIM_PT_quality_control, - #object panel groups --> + # object panel groups --> ui.BIM_PT_object_metadata, ui.BIM_PT_geometry_object, ui.BIM_PT_services_object, ui.BIM_PT_utilities_object, - ui.BIM_PT_misc_object + ui.BIM_PT_misc_object, ] for mod in modules.values(): diff --git a/src/blenderbim/blenderbim/bim/helper.py b/src/blenderbim/blenderbim/bim/helper.py index 9a8320aba5..3d9ac797bd 100644 --- a/src/blenderbim/blenderbim/bim/helper.py +++ b/src/blenderbim/blenderbim/bim/helper.py @@ -128,6 +128,6 @@ class IFCHeaderSpecs: self.name = part elif i == 3: self.time_stamp = part - elif line.startswith("FILE_SCHEMA"): + elif line.startswith("FILE_SCHEMA"): self.schema_name = line.split("'")[1] break diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index 603155f9eb..cac144c774 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -433,7 +433,6 @@ class OverrideOutlinerDelete(bpy.types.Operator, OverrideDeleteTrait): while queue: collection = queue.pop() for obj in collection.objects: - print('obj is', obj) objects.add(obj) queue.extend(collection.children) children = children.union(collection.children) diff --git a/src/blenderbim/blenderbim/bim/module/patch/__init__.py b/src/blenderbim/blenderbim/bim/module/patch/__init__.py index b5c7ef84c6..ac605b828d 100644 --- a/src/blenderbim/blenderbim/bim/module/patch/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/patch/__init__.py @@ -20,9 +20,10 @@ import bpy from . import ui, prop, operator classes = ( + operator.ExecuteIfcPatch, + operator.RunMigratePatch, operator.SelectIfcPatchInput, operator.SelectIfcPatchOutput, - operator.ExecuteIfcPatch, operator.UpdateIfcPatchArguments, prop.BIMPatchProperties, ui.BIM_PT_patch, diff --git a/src/blenderbim/blenderbim/bim/module/patch/operator.py b/src/blenderbim/blenderbim/bim/module/patch/operator.py index e8c4d1b89c..6f3e6647c3 100644 --- a/src/blenderbim/blenderbim/bim/module/patch/operator.py +++ b/src/blenderbim/blenderbim/bim/module/patch/operator.py @@ -19,6 +19,9 @@ import os import bpy import json +import blenderbim.tool as tool +import blenderbim.core.patch as core +import blenderbim.bim.handler try: import ifcpatch @@ -114,3 +117,17 @@ class UpdateIfcPatchArguments(bpy.types.Operator): new_attr.name = arg_name new_attr.set_value(arg_info.get("default", new_attr.get_value_default())) return {"FINISHED"} + + +class RunMigratePatch(bpy.types.Operator): + bl_idname = "bim.run_migrate_patch" + bl_label = "Execute IFCPatch" + infile: bpy.props.StringProperty() + outfile: bpy.props.StringProperty() + schema: bpy.props.StringProperty() + + def execute(self, context): + core.run_migrate_patch(tool.Patch, infile=self.infile, outfile=self.outfile, schema=self.schema) + bpy.ops.file.refresh() + blenderbim.bim.handler.refresh_ui_data() + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/ui.py b/src/blenderbim/blenderbim/bim/ui.py index 3600e3567f..955bc2b117 100644 --- a/src/blenderbim/blenderbim/bim/ui.py +++ b/src/blenderbim/blenderbim/bim/ui.py @@ -47,6 +47,16 @@ class IFCFileSelector: split = box.split() split.label(text=attr_name.title().replace("_", " ")) split.label(text=str(attr_value)) + if ( + attr_name.lower() == "schema_name" + and str(attr_value).lower() == "ifc2x3" + and filepath[-4:].lower() == ".ifc" + ): + row = box.row() + op = row.operator("bim.run_migrate_patch") + op.infile = filepath + op.outfile = filepath[0:-4] + "-IFC4.ifc" + op.schema = "IFC4" class BIM_PT_section_plane(Panel): @@ -178,7 +188,7 @@ class BIM_PT_utilities(Panel): @classmethod def poll(cls, context): return tool.Ifc.get() - + def draw(self, context): pass @@ -204,7 +214,7 @@ class BIM_PT_geometry(Panel): @classmethod def poll(cls, context): return tool.Ifc.get() - + def draw(self, context): pass @@ -219,7 +229,7 @@ class BIM_PT_4D5D(Panel): @classmethod def poll(cls, context): return tool.Ifc.get() - + def draw(self, context): pass @@ -234,7 +244,7 @@ class BIM_PT_structural(Panel): @classmethod def poll(cls, context): return tool.Ifc.get() - + def draw(self, context): pass @@ -249,7 +259,7 @@ class BIM_PT_services(Panel): @classmethod def poll(cls, context): return tool.Ifc.get() - + def draw(self, context): pass @@ -290,11 +300,11 @@ class BIM_PT_object_metadata(Panel): @classmethod def poll(cls, context): return tool.Ifc.get() - + def draw(self, context): pass - - + + class BIM_PT_geometry_object(Panel): bl_label = "IFC Geometry" bl_space_type = "PROPERTIES" @@ -305,7 +315,7 @@ class BIM_PT_geometry_object(Panel): @classmethod def poll(cls, context): return tool.Ifc.get() - + def draw(self, context): pass @@ -320,7 +330,7 @@ class BIM_PT_services_object(Panel): @classmethod def poll(cls, context): return tool.Ifc.get() - + def draw(self, context): pass @@ -335,7 +345,7 @@ class BIM_PT_utilities_object(Panel): @classmethod def poll(cls, context): return tool.Ifc.get() - + def draw(self, context): pass @@ -350,6 +360,6 @@ class BIM_PT_misc_object(Panel): @classmethod def poll(cls, context): return tool.Ifc.get() - + def draw(self, context): pass diff --git a/src/blenderbim/blenderbim/core/patch.py b/src/blenderbim/blenderbim/core/patch.py new file mode 100644 index 0000000000..2449d6250e --- /dev/null +++ b/src/blenderbim/blenderbim/core/patch.py @@ -0,0 +1,21 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2022 Dion Moult +# +# 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 . + + +def run_migrate_patch(patch, infile=None, outfile=None, schema=None): + patch.run_migrate_patch(infile, outfile, schema) diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index 8c603d78fc..1d620d2abf 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -196,6 +196,11 @@ class Misc: def split_objects_with_cutter(cls, objs, cutter): pass +@interface +class Patch: + def run_migrate_patch(cls, infile, outfile, schema): pass + + @interface class Owner: def add_address_attribute(cls, name): pass diff --git a/src/blenderbim/blenderbim/tool/__init__.py b/src/blenderbim/blenderbim/tool/__init__.py index ffb79aecbb..bdd34ab26b 100644 --- a/src/blenderbim/blenderbim/tool/__init__.py +++ b/src/blenderbim/blenderbim/tool/__init__.py @@ -29,6 +29,7 @@ from blenderbim.tool.library import Library from blenderbim.tool.material import Material from blenderbim.tool.misc import Misc from blenderbim.tool.owner import Owner +from blenderbim.tool.patch import Patch from blenderbim.tool.pset import Pset from blenderbim.tool.qto import Qto from blenderbim.tool.root import Root diff --git a/src/blenderbim/blenderbim/tool/patch.py b/src/blenderbim/blenderbim/tool/patch.py new file mode 100644 index 0000000000..16cca5ff44 --- /dev/null +++ b/src/blenderbim/blenderbim/tool/patch.py @@ -0,0 +1,34 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2022 Dion Moult +# +# 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 . + +import os +import bpy +import blenderbim.core.tool +import blenderbim.tool as tool + +try: + import ifcpatch +except: + print("IfcPatch not available") + + +class Patch(blenderbim.core.tool.Patch): + @classmethod + def run_migrate_patch(cls, infile, outfile, schema): + log = os.path.join(bpy.context.scene.BIMProperties.data_dir, "process.log") + ifcpatch.execute({"input": infile, "output": outfile, "recipe": "Migrate", "arguments": [schema], "log": log}) diff --git a/src/blenderbim/test/bim/feature/patch.feature b/src/blenderbim/test/bim/feature/patch.feature index 905eb2896e..473c45cbb7 100644 --- a/src/blenderbim/test/bim/feature/patch.feature +++ b/src/blenderbim/test/bim/feature/patch.feature @@ -9,3 +9,8 @@ Scenario: Execute IFC Patch And I set "scene.BIMPatchProperties.ifc_patch_args" to "[123454321,0,0,0]" When I press "bim.execute_ifc_patch" Then the file "{cwd}/test/files/basic-patched.ifc" should contain "123454321" + +Scenario: Run migrate patch + Given an empty Blender session + When I press "bim.run_migrate_patch(infile='{cwd}/test/files/ifc2x3.ifc', outfile='{cwd}/test/files/ifc2x3-migrated.ifc', schema='IFC4')" + Then the file "{cwd}/test/files/ifc2x3-migrated.ifc" should contain "IFC4" diff --git a/src/blenderbim/test/core/bootstrap.py b/src/blenderbim/test/core/bootstrap.py index 3ee75fef62..b27dd5e05e 100644 --- a/src/blenderbim/test/core/bootstrap.py +++ b/src/blenderbim/test/core/bootstrap.py @@ -112,6 +112,13 @@ def owner(): prophet.verify() +@pytest.fixture +def patch(): + prophet = Prophecy(blenderbim.core.tool.Patch) + yield prophet + prophet.verify() + + @pytest.fixture def pset(): prophet = Prophecy(blenderbim.core.tool.Pset) diff --git a/src/blenderbim/test/core/test_brick.py b/src/blenderbim/test/core/test_brick.py index a02562609f..23aa28e9a7 100644 --- a/src/blenderbim/test/core/test_brick.py +++ b/src/blenderbim/test/core/test_brick.py @@ -122,7 +122,9 @@ class TestAddBrick: brick.add_brick_from_element("element", "namespace", "brick_class").should_be_called().will_return("brick_uri") brick.run_assign_brick_reference(element="element", library="library", brick_uri="brick_uri").should_be_called() brick.run_refresh_brick_viewer().should_be_called() - subject.add_brick(ifc, brick, element="element", namespace="namespace", brick_class="brick_class", library="library") + subject.add_brick( + ifc, brick, element="element", namespace="namespace", brick_class="brick_class", library="library" + ) def test_adding_a_plain_brick(self, ifc, brick): brick.add_brick("namespace", "brick_class").should_be_called() diff --git a/src/blenderbim/test/core/test_drawing.py b/src/blenderbim/test/core/test_drawing.py index 19c06a0df4..fa4234ba57 100644 --- a/src/blenderbim/test/core/test_drawing.py +++ b/src/blenderbim/test/core/test_drawing.py @@ -60,7 +60,9 @@ class TestEditTextProduct: def test_run(self, ifc, drawing): ifc.get_entity("obj").should_be_called().will_return("element") drawing.get_text_product("element").should_be_called().will_return("existing_product") - ifc.run("drawing.unassign_product", relating_product="existing_product", related_object="element").should_be_called() + ifc.run( + "drawing.unassign_product", relating_product="existing_product", related_object="element" + ).should_be_called() ifc.run("drawing.assign_product", relating_product="product", related_object="element").should_be_called() drawing.update_text_value("obj").should_be_called() drawing.disable_editing_text_product("obj").should_be_called() diff --git a/src/blenderbim/test/core/test_patch.py b/src/blenderbim/test/core/test_patch.py new file mode 100644 index 0000000000..436e8cc496 --- /dev/null +++ b/src/blenderbim/test/core/test_patch.py @@ -0,0 +1,26 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2022 Dion Moult +# +# 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 . + +import blenderbim.core.owner as subject +from test.core.bootstrap import patch + + +class TestRunMigratePatch: + def test_run(self, patch): + patch.run_migrate_patch("infile", "outfile", "schema").should_be_called() + assert subject.run_migrate_patch(patch, infile="infile", outfile="outfile", schema="schema") diff --git a/src/blenderbim/test/files/ifc2x3.ifc b/src/blenderbim/test/files/ifc2x3.ifc new file mode 100644 index 0000000000..9088218670 --- /dev/null +++ b/src/blenderbim/test/files/ifc2x3.ifc @@ -0,0 +1,12 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition [CoordinationView]'),'2;1'); +FILE_NAME('','2021-09-03T08:40:25',(),(),'IfcOpenShell 0.6.0b0','IfcOpenShell 0.6.0b0',''); +FILE_SCHEMA(('IFC2X3')); +ENDSEC; +DATA; +#1=IFCPERSON($,$,$,$,$,$,$,$); +#2=IFCORGANIZATION('abc','Foobar','http://www.example.com',$,$); +#3=IFCPERSONANDORGANIZATION(#1,#2,$); +ENDSEC; +END-ISO-10303-21; diff --git a/src/blenderbim/test/tool/test_brick.py b/src/blenderbim/test/tool/test_brick.py index 33a66009af..65bee9dbc9 100644 --- a/src/blenderbim/test/tool/test_brick.py +++ b/src/blenderbim/test/tool/test_brick.py @@ -37,12 +37,12 @@ class TestImplementsTool(NewFile): class TestAddBrick(NewFile): def test_run(self): BrickStore.graph = brickschema.Graph() - result = subject.add_brick( - "http://example.org/digitaltwin#", "https://brickschema.org/schema/Brick#Equipment" - ) + result = subject.add_brick("http://example.org/digitaltwin#", "https://brickschema.org/schema/Brick#Equipment") assert "http://example.org/digitaltwin#" in result assert list( - BrickStore.graph.triples((URIRef(result), RDF.type, URIRef("https://brickschema.org/schema/Brick#Equipment"))) + BrickStore.graph.triples( + (URIRef(result), RDF.type, URIRef("https://brickschema.org/schema/Brick#Equipment")) + ) ) assert list( BrickStore.graph.triples( diff --git a/src/blenderbim/test/tool/test_patch.py b/src/blenderbim/test/tool/test_patch.py new file mode 100644 index 0000000000..4c1d2b63fa --- /dev/null +++ b/src/blenderbim/test/tool/test_patch.py @@ -0,0 +1,40 @@ +# BlenderBIM Add-on - OpenBIM Blender Add-on +# Copyright (C) 2022 Dion Moult +# +# 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 . + +import os +import bpy +import ifcopenshell +import blenderbim.core.tool +import blenderbim.tool as tool +from test.bim.bootstrap import NewFile +from blenderbim.tool.patch import Patch as subject + + +class TestImplementsTool(NewFile): + def test_run(self): + assert isinstance(subject(), blenderbim.core.tool.Patch) + + +class TestRunMigratePatch(NewFile): + def test_run(self): + cwd = os.path.dirname(os.path.realpath(__file__)) + infile = os.path.join(cwd, "..", "files", "ifc2x3.ifc") + outfile = os.path.join(cwd, "..", "files", "ifc2x3-migrated.ifc") + subject.run_migrate_patch(infile, outfile, "IFC4") + ifc = ifcopenshell.open(outfile) + assert ifc.schema == "IFC4"