diff --git a/src/blenderbim/blenderbim/bim/module/brick/__init__.py b/src/blenderbim/blenderbim/bim/module/brick/__init__.py index 2b7647dc3c..5e0afa989a 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/brick/__init__.py @@ -29,6 +29,7 @@ classes = ( operator.LoadBrickProject, operator.NewBrickFile, operator.RefreshBrickViewer, + operator.RemoveBrick, operator.RewindBrickClass, operator.ViewBrickClass, operator.ViewBrickItem, diff --git a/src/blenderbim/blenderbim/bim/module/brick/data.py b/src/blenderbim/blenderbim/bim/module/brick/data.py index 2fc5d38377..072f9b2f70 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/data.py +++ b/src/blenderbim/blenderbim/bim/module/brick/data.py @@ -148,7 +148,10 @@ class BrickschemaReferencesData: @classmethod def libraries(cls): results = [] - for library in tool.Ifc.get().by_type("IfcLibraryInformation"): + ifc = tool.Ifc.get() + if not ifc: + return results + for library in ifc.by_type("IfcLibraryInformation"): if tool.Ifc.get_schema() == "IFC2X3": results.append((str(library.id()), library.Name or "Unnamed", "")) elif ".ttl" in library.Location: diff --git a/src/blenderbim/blenderbim/bim/module/brick/operator.py b/src/blenderbim/blenderbim/bim/module/brick/operator.py index 34466f37ad..33d877ebd1 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/operator.py +++ b/src/blenderbim/blenderbim/bim/module/brick/operator.py @@ -174,3 +174,18 @@ class RefreshBrickViewer(bpy.types.Operator, Operator): def _execute(self, context): core.refresh_brick_viewer(tool.Brick) + + +class RemoveBrick(bpy.types.Operator, Operator): + bl_idname = "bim.remove_brick" + bl_label = "Remove Brick" + bl_options = {"REGISTER", "UNDO"} + + def _execute(self, context): + props = context.scene.BIMBrickProperties + core.remove_brick( + tool.Ifc, + tool.Brick, + library=tool.Ifc.get().by_id(int(props.libraries)) if props.libraries else None, + brick_uri=props.bricks[props.active_brick_index].uri, + ) diff --git a/src/blenderbim/blenderbim/bim/module/brick/ui.py b/src/blenderbim/blenderbim/bim/module/brick/ui.py index ec9e56b4d1..da3647ab6d 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/ui.py +++ b/src/blenderbim/blenderbim/bim/module/brick/ui.py @@ -51,7 +51,11 @@ class BIM_PT_brickschema(Panel): row.prop(self.props, "namespace", text="") row.prop(self.props, "brick_equipment_class", text="") row.operator("bim.add_brick", text="", icon="ADD") + + row = self.layout.row(align=True) + row.alignment = "RIGHT" row.operator("bim.add_brick_feed", text="", icon="PLUGIN") + row.operator("bim.remove_brick", text="", icon="X") self.layout.template_list("BIM_UL_bricks", "", self.props, "bricks", self.props, "active_brick_index") diff --git a/src/blenderbim/blenderbim/bim/module/patch/operator.py b/src/blenderbim/blenderbim/bim/module/patch/operator.py index 08fde84fc2..a5c3b19ac6 100644 --- a/src/blenderbim/blenderbim/bim/module/patch/operator.py +++ b/src/blenderbim/blenderbim/bim/module/patch/operator.py @@ -121,7 +121,7 @@ class UpdateIfcPatchArguments(bpy.types.Operator): class RunMigratePatch(bpy.types.Operator): bl_idname = "bim.run_migrate_patch" - bl_label = "Execute IFCPatch" + bl_label = "Run Migrate Patch" infile: bpy.props.StringProperty() outfile: bpy.props.StringProperty() schema: bpy.props.StringProperty() diff --git a/src/blenderbim/blenderbim/bim/module/pset/ui.py b/src/blenderbim/blenderbim/bim/module/pset/ui.py index 55df0ec104..9cfca725c7 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/ui.py +++ b/src/blenderbim/blenderbim/bim/module/pset/ui.py @@ -192,7 +192,6 @@ class BIM_PT_material_psets(Panel): bl_space_type = "PROPERTIES" bl_region_type = "WINDOW" bl_context = "material" - bl_parent_id = "BIM_PT_object_metadata" @classmethod def poll(cls, context): diff --git a/src/blenderbim/blenderbim/bim/module/system/ui.py b/src/blenderbim/blenderbim/bim/module/system/ui.py index 594d479e99..b4ce788937 100644 --- a/src/blenderbim/blenderbim/bim/module/system/ui.py +++ b/src/blenderbim/blenderbim/bim/module/system/ui.py @@ -121,7 +121,7 @@ class BIM_PT_object_systems(Panel): op = row.operator("bim.unassign_system", text="", icon="X") op.system = system["id"] - if not systems_object: + if not ObjectSystemData.data["systems"]: self.layout.label(text="No System associated with Active Object") diff --git a/src/blenderbim/blenderbim/bim/ui.py b/src/blenderbim/blenderbim/bim/ui.py index cc7f900ba8..23c49c4775 100644 --- a/src/blenderbim/blenderbim/bim/ui.py +++ b/src/blenderbim/blenderbim/bim/ui.py @@ -53,7 +53,7 @@ class IFCFileSelector: and filepath[-4:].lower() == ".ifc" ): row = box.row() - op = row.operator("bim.run_migrate_patch") + op = row.operator("bim.run_migrate_patch", text="Upgrade to IFC4") op.infile = filepath op.outfile = filepath[0:-4] + "-IFC4.ifc" op.schema = "IFC4" diff --git a/src/blenderbim/blenderbim/core/brick.py b/src/blenderbim/blenderbim/core/brick.py index e5ab6a9bc6..d4df98654e 100644 --- a/src/blenderbim/blenderbim/core/brick.py +++ b/src/blenderbim/blenderbim/core/brick.py @@ -100,3 +100,12 @@ def new_brick_file(brick): def refresh_brick_viewer(brick): brick.run_view_brick_class(brick_class=brick.get_active_brick_class()) brick.pop_brick_breadcrumb() + + +def remove_brick(ifc, brick, library=None, brick_uri=None): + if library: + reference = brick.get_library_brick_reference(library, brick_uri) + if reference: + ifc.run("library.remove_reference", reference=reference) + brick.remove_brick(brick_uri) + brick.run_refresh_brick_viewer() diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index cdb4c9a651..f3e252f499 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -67,6 +67,7 @@ class Brick: def load_brick_file(cls, filepath): pass def new_brick_file(cls): pass def pop_brick_breadcrumb(cls): pass + def remove_brick(cls, brick_uri): pass def run_assign_brick_reference(cls, element=None, library=None, brick_uri=None): pass def run_refresh_brick_viewer(cls): pass def run_view_brick_class(cls, brick_class=None): pass diff --git a/src/blenderbim/blenderbim/tool/brick.py b/src/blenderbim/blenderbim/tool/brick.py index eb16214b95..8a2cb1d5dd 100644 --- a/src/blenderbim/blenderbim/tool/brick.py +++ b/src/blenderbim/blenderbim/tool/brick.py @@ -278,8 +278,9 @@ class Brick(blenderbim.core.tool.Brick): return name @classmethod - def run_add_brick_feed(source=None, destination=None): - return blenderbim.core.brick.add_brick_feed(tool.Ifc, tool.Brick, source=source, destination=destination) + def remove_brick(cls, brick_uri): + for triple in BrickStore.graph.triples((URIRef(brick_uri), None, None)): + BrickStore.graph.remove(triple) @classmethod def run_assign_brick_reference(cls, element=None, library=None, brick_uri=None): diff --git a/src/blenderbim/test/bim/feature/brick.feature b/src/blenderbim/test/bim/feature/brick.feature index 590d6dfbe4..18597c8bdc 100644 --- a/src/blenderbim/test/bim/feature/brick.feature +++ b/src/blenderbim/test/bim/feature/brick.feature @@ -50,6 +50,13 @@ Scenario: Assign brick reference When I press "bim.assign_brick_reference" Then nothing happens +Scenario: Add brick - vanilla brick with no IFC + Given an empty Blender session + And I press "bim.new_brick_file" + And I set "scene.BIMBrickProperties.namespace" to "https://example.org/digitaltwin#" + When I press "bim.add_brick" + Then nothing happens + Scenario: Add brick - without a brick IFC library Given an empty IFC project And I add a cube @@ -58,7 +65,7 @@ Scenario: Add brick - without a brick IFC library And I press "bim.assign_class" And I press "bim.load_brick_project(filepath='{cwd}/test/files/spaces.ttl')" And the object "IfcChiller/Cube" is selected - And I set "scene.BIMBrickProperties.namespace" to "http://example.org/digitaltwin#" + And I set "scene.BIMBrickProperties.namespace" to "https://example.org/digitaltwin#" When I press "bim.add_brick" Then nothing happens @@ -71,7 +78,7 @@ Scenario: Add brick - with a brick IFC library And I press "bim.load_brick_project(filepath='{cwd}/test/files/spaces.ttl')" And I press "bim.convert_brick_project" And the object "IfcChiller/Cube" is selected - And I set "scene.BIMBrickProperties.namespace" to "http://example.org/digitaltwin#" + And I set "scene.BIMBrickProperties.namespace" to "https://example.org/digitaltwin#" When I press "bim.add_brick" Then nothing happens @@ -79,7 +86,7 @@ Scenario: Add brick feed Given an empty IFC project And I press "bim.load_brick_project(filepath='{cwd}/test/files/spaces.ttl')" And I press "bim.convert_brick_project" - And I set "scene.BIMBrickProperties.namespace" to "http://example.org/digitaltwin#" + And I set "scene.BIMBrickProperties.namespace" to "https://example.org/digitaltwin#" And I add a cube And the object "Cube" is selected And I set "scene.BIMRootProperties.ifc_class" to "IfcUnitaryEquipment" @@ -101,7 +108,7 @@ Scenario: Convert IFC to brick Given an empty IFC project And I press "bim.load_brick_project(filepath='{cwd}/test/files/spaces.ttl')" And I press "bim.convert_brick_project" - And I set "scene.BIMBrickProperties.namespace" to "http://example.org/digitaltwin#" + And I set "scene.BIMBrickProperties.namespace" to "https://example.org/digitaltwin#" And I add a cube And the object "Cube" is selected And I set "scene.BIMRootProperties.ifc_class" to "IfcUnitaryEquipment" @@ -120,3 +127,16 @@ Scenario: Refresh brick viewer And I press "bim.new_brick_file" When I press "bim.refresh_brick_viewer" Then nothing happens + +Scenario: Remove brick - without a brick IFC library + Given an empty IFC project + And I add a cube + And the object "Cube" is selected + And I set "scene.BIMRootProperties.ifc_class" to "IfcChiller" + And I press "bim.assign_class" + And I press "bim.load_brick_project(filepath='{cwd}/test/files/spaces.ttl')" + And the object "IfcChiller/Cube" is selected + And I set "scene.BIMBrickProperties.namespace" to "https://example.org/digitaltwin#" + And I press "bim.add_brick" + When I press "bim.remove_brick" + Then nothing happens diff --git a/src/blenderbim/test/core/test_brick.py b/src/blenderbim/test/core/test_brick.py index 23aa28e9a7..2b5eb70855 100644 --- a/src/blenderbim/test/core/test_brick.py +++ b/src/blenderbim/test/core/test_brick.py @@ -165,3 +165,23 @@ class TestRefreshBrickViewer: brick.run_view_brick_class(brick_class="class").should_be_called() brick.pop_brick_breadcrumb().should_be_called() subject.refresh_brick_viewer(brick) + + +class TestRemoveBrick: + def test_run(self, ifc, brick): + brick.get_library_brick_reference("library", "brick_uri").should_be_called().will_return("reference") + ifc.run("library.remove_reference", reference="reference").should_be_called() + brick.remove_brick("brick_uri").should_be_called() + brick.run_refresh_brick_viewer().should_be_called() + subject.remove_brick(ifc, brick, library="library", brick_uri="brick_uri") + + def test_do_not_remove_reference_if_no_reference_exists(self, ifc, brick): + brick.get_library_brick_reference("library", "brick_uri").should_be_called().will_return(None) + brick.remove_brick("brick_uri").should_be_called() + brick.run_refresh_brick_viewer().should_be_called() + subject.remove_brick(ifc, brick, library="library", brick_uri="brick_uri") + + def test_do_not_check_references_if_no_library_specified(self, ifc, brick): + brick.remove_brick("brick_uri").should_be_called() + brick.run_refresh_brick_viewer().should_be_called() + subject.remove_brick(ifc, brick, library=None, brick_uri="brick_uri") diff --git a/src/blenderbim/test/files/spaces.ttl b/src/blenderbim/test/files/spaces.ttl index 760a53f1bb..32d05bdf3a 100644 --- a/src/blenderbim/test/files/spaces.ttl +++ b/src/blenderbim/test/files/spaces.ttl @@ -1,4 +1,4 @@ -@prefix digitaltwin: . +@prefix digitaltwin: . @prefix brick: . @prefix unit: . @prefix rdfs: . diff --git a/src/blenderbim/test/tool/test_brick.py b/src/blenderbim/test/tool/test_brick.py index 65bee9dbc9..855600d27b 100644 --- a/src/blenderbim/test/tool/test_brick.py +++ b/src/blenderbim/test/tool/test_brick.py @@ -345,6 +345,18 @@ class TestPopBrickBreadcrumb(NewFile): assert bpy.context.scene.BIMBrickProperties.brick_breadcrumbs[0].name == "foo" +class TestRemoveBrick(NewFile): + def test_run(self): + BrickStore.graph = brickschema.Graph() + result = subject.add_brick("http://example.org/digitaltwin#", "https://brickschema.org/schema/Brick#Equipment") + subject.remove_brick(result) + assert not list( + BrickStore.graph.triples( + (URIRef(result), None, None) + ) + ) + + class TestRunAssignBrickReference(NewFile): def test_nothing(self): pass diff --git a/src/ifc4d/README.md b/src/ifc4d/README.md index c841b270ea..c774d01f07 100644 --- a/src/ifc4d/README.md +++ b/src/ifc4d/README.md @@ -3,14 +3,20 @@ Ifc4D contains a series of utilities for converting to and from various 4D software. Currently supported: - Microsoft Project to IFC - - Oracle Primavera 6 (P6) to IFC + - Oracle Primavera 6 (P6) XML to IFC + - Oracle Primavera 6 (P6) XER to IFC + - Asta Powerproject to IFC Planned (would you like to contribute? Please reach out!): - IFC to Microsoft Project - IFC to Oracle Primavera 6 (P6) - - Asta Powerproject to IFC - IFC to Asta Powerproject - LibreProject to IFC - IFC to LibreProject - IFC to Gantt + + +## Useful links + + - [P6 EPPM XER Import/Export Data Map Guide](https://docs.oracle.com/cd/F12057_01/English/Mapping_and_Schema/xer_import_export_data_map_project/helpmain.htm?toc.htm?97881.htm)