From 5ba542488a6ca74987c5900497ca219880421132 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Wed, 12 Jan 2022 16:22:32 +1100 Subject: [PATCH] Implement adding plain bricks not based on IFC --- .../blenderbim/bim/module/brick/operator.py | 4 +- src/blenderbim/blenderbim/core/brick.py | 13 +++-- src/blenderbim/blenderbim/core/tool.py | 3 +- src/blenderbim/blenderbim/tool/brick.py | 18 +++++-- src/blenderbim/test/core/test_brick.py | 13 +++-- src/blenderbim/test/tool/test_brick.py | 47 ++++++++++++------- 6 files changed, 67 insertions(+), 31 deletions(-) diff --git a/src/blenderbim/blenderbim/bim/module/brick/operator.py b/src/blenderbim/blenderbim/bim/module/brick/operator.py index c339e836ec..2ddec413ad 100644 --- a/src/blenderbim/blenderbim/bim/module/brick/operator.py +++ b/src/blenderbim/blenderbim/bim/module/brick/operator.py @@ -122,7 +122,9 @@ class AddBrick(bpy.types.Operator, Operator): core.add_brick( tool.Ifc, tool.Brick, - obj=context.active_object, + obj=context.active_object + if context.selected_objects and tool.Ifc.get_entity(context.active_object) + else None, namespace=props.namespace, brick_class=props.brick_equipment_class, library=library, diff --git a/src/blenderbim/blenderbim/core/brick.py b/src/blenderbim/blenderbim/core/brick.py index 79f81d67c1..d92eac75c7 100644 --- a/src/blenderbim/blenderbim/core/brick.py +++ b/src/blenderbim/blenderbim/core/brick.py @@ -69,10 +69,13 @@ def assign_brick_reference(ifc, brick, obj=None, library=None, brick_uri=None): def add_brick(ifc, brick, obj=None, namespace=None, brick_class=None, library=None): - product = ifc.get_entity(obj) - brick_uri = brick.add_brick(product, namespace, brick_class) - if library: - brick.run_assign_brick_reference(obj=obj, library=library, brick_uri=brick_uri) + if obj: + product = ifc.get_entity(obj) + brick_uri = brick.add_brick_from_element(product, namespace, brick_class) + if library: + brick.run_assign_brick_reference(obj=obj, library=library, brick_uri=brick_uri) + else: + brick_uri = brick.add_brick(namespace, brick_class) brick.run_refresh_brick_viewer() @@ -85,7 +88,7 @@ def add_brick_feed(ifc, brick, source=None, destination=None): def convert_ifc_to_brick(brick, namespace=None, library=None): for obj, element in brick.get_convertable_brick_objects_and_elements(): - brick_uri = brick.add_brick(element, namespace, brick.get_brick_class(element)) + brick_uri = brick.add_brick_from_element(element, namespace, brick.get_brick_class(element)) if library: brick.run_assign_brick_reference(obj=obj, library=library, brick_uri=brick_uri) brick.run_refresh_brick_viewer() diff --git a/src/blenderbim/blenderbim/core/tool.py b/src/blenderbim/blenderbim/core/tool.py index c79392bb05..1de8210d8f 100644 --- a/src/blenderbim/blenderbim/core/tool.py +++ b/src/blenderbim/blenderbim/core/tool.py @@ -43,8 +43,9 @@ class Blender: pass @interface class Brick: - def add_brick(cls, element, namespace, brick_class): pass + def add_brick(cls, namespace, brick_class): pass def add_brick_breadcrumb(cls): pass + def add_brick_from_element(cls, element, namespace, brick_class): pass def add_brickifc_project(cls, namespace): pass def add_brickifc_reference(cls, brick, element, project): pass def add_feed(cls, source, destination): pass diff --git a/src/blenderbim/blenderbim/tool/brick.py b/src/blenderbim/blenderbim/tool/brick.py index bf4f985717..e76ee8a1a1 100644 --- a/src/blenderbim/blenderbim/tool/brick.py +++ b/src/blenderbim/blenderbim/tool/brick.py @@ -35,12 +35,11 @@ except: class Brick(blenderbim.core.tool.Brick): @classmethod - def add_brick(cls, element, namespace, brick_class): + def add_brick(cls, namespace, brick_class): ns = Namespace(namespace) - brick = ns[element.GlobalId] + brick = ns[ifcopenshell.guid.expand(ifcopenshell.guid.new())] BrickStore.graph.add((brick, RDF.type, URIRef(brick_class))) - if element.Name: - BrickStore.graph.add((brick, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal(element.Name))) + BrickStore.graph.add((brick, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal("Unnamed"))) return str(brick) @classmethod @@ -48,6 +47,15 @@ class Brick(blenderbim.core.tool.Brick): new = bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.add() new.name = bpy.context.scene.BIMBrickProperties.active_brick_class + @classmethod + def add_brick_from_element(cls, element, namespace, brick_class): + ns = Namespace(namespace) + brick = ns[element.GlobalId] + BrickStore.graph.add((brick, RDF.type, URIRef(brick_class))) + if element.Name: + BrickStore.graph.add((brick, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal(element.Name))) + return str(brick) + @classmethod def add_brickifc_project(cls, namespace): project = tool.Ifc.get().by_type("IfcProject")[0] @@ -263,6 +271,8 @@ class Brick(blenderbim.core.tool.Brick): BrickStore.schema.load_file(schema_path) BrickStore.graph = brickschema.Graph() + BrickStore.schema BrickStore.graph.bind("digitaltwin", Namespace("https://example.org/digitaltwin#")) + BrickStore.graph.bind("brick", Namespace("https://brickschema.org/schema/Brick#")) + BrickStore.graph.bind("rdfs", Namespace("http://www.w3.org/2000/01/rdf-schema#")) @classmethod def pop_brick_breadcrumb(cls): diff --git a/src/blenderbim/test/core/test_brick.py b/src/blenderbim/test/core/test_brick.py index dd1a294ac8..b6a4b3ce9b 100644 --- a/src/blenderbim/test/core/test_brick.py +++ b/src/blenderbim/test/core/test_brick.py @@ -116,19 +116,24 @@ class TestAssignBrickReference: class TestAddBrick: - def test_adding_a_brick(self, ifc, brick): + def test_adding_a_brick_from_an_element(self, ifc, brick): ifc.get_entity("obj").should_be_called().will_return("product") - brick.add_brick("product", "namespace", "brick_class").should_be_called().will_return("brick_uri") + brick.add_brick_from_element("product", "namespace", "brick_class").should_be_called().will_return("brick_uri") brick.run_refresh_brick_viewer().should_be_called() subject.add_brick(ifc, brick, obj="obj", namespace="namespace", brick_class="brick_class", library=None) def test_adding_a_brick_an_auto_assigning_it_to_the_ifc_element(self, ifc, brick): ifc.get_entity("obj").should_be_called().will_return("product") - brick.add_brick("product", "namespace", "brick_class").should_be_called().will_return("brick_uri") + brick.add_brick_from_element("product", "namespace", "brick_class").should_be_called().will_return("brick_uri") brick.run_assign_brick_reference(obj="obj", library="library", brick_uri="brick_uri").should_be_called() brick.run_refresh_brick_viewer().should_be_called() subject.add_brick(ifc, brick, obj="obj", 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() + brick.run_refresh_brick_viewer().should_be_called() + subject.add_brick(ifc, brick, obj=None, namespace="namespace", brick_class="brick_class", library=None) + class TestAddBrickFeed: def test_run(self, ifc, brick): @@ -145,7 +150,7 @@ class TestConvertIfcToBrick: def test_run(self, brick): brick.get_convertable_brick_objects_and_elements().should_be_called().will_return([("obj", "element")]) brick.get_brick_class("element").should_be_called().will_return("brick_class") - brick.add_brick("element", "namespace", "brick_class").should_be_called().will_return("brick_uri") + brick.add_brick_from_element("element", "namespace", "brick_class").should_be_called().will_return("brick_uri") brick.run_assign_brick_reference(obj="obj", library="library", brick_uri="brick_uri").should_be_called() brick.run_refresh_brick_viewer().should_be_called() subject.convert_ifc_to_brick(brick, namespace="namespace", library="library") diff --git a/src/blenderbim/test/tool/test_brick.py b/src/blenderbim/test/tool/test_brick.py index e1ecc7d94d..02e1f29b98 100644 --- a/src/blenderbim/test/tool/test_brick.py +++ b/src/blenderbim/test/tool/test_brick.py @@ -35,13 +35,39 @@ 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" + ) + assert "http://example.org/digitaltwin#" in result + assert list( + BrickStore.graph.triples((URIRef(result), RDF.type, URIRef("https://brickschema.org/schema/Brick#Equipment"))) + ) + assert list( + BrickStore.graph.triples( + (URIRef(result), URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal("Unnamed")) + ) + ) + + +class TestAddBrickBreadcrumb(NewFile): + def test_run(self): + subject.set_active_brick_class("brick_class") + subject.add_brick_breadcrumb() + assert bpy.context.scene.BIMBrickProperties.brick_breadcrumbs[0].name == "brick_class" + subject.add_brick_breadcrumb() + assert bpy.context.scene.BIMBrickProperties.brick_breadcrumbs[1].name == "brick_class" + + +class TestAddBrickFromElement(NewFile): def test_run(self): ifc = ifcopenshell.file() element = ifc.createIfcChiller() element.Name = "Chiller" element.GlobalId = ifcopenshell.guid.new() BrickStore.graph = brickschema.Graph() - result = subject.add_brick( + result = subject.add_brick_from_element( element, "http://example.org/digitaltwin#", "https://brickschema.org/schema/Brick#Equipment" ) uri = f"http://example.org/digitaltwin#{element.GlobalId}" @@ -56,15 +82,6 @@ class TestAddBrick(NewFile): ) -class TestAddBrickBreadcrumb(NewFile): - def test_run(self): - subject.set_active_brick_class("brick_class") - subject.add_brick_breadcrumb() - assert bpy.context.scene.BIMBrickProperties.brick_breadcrumbs[0].name == "brick_class" - subject.add_brick_breadcrumb() - assert bpy.context.scene.BIMBrickProperties.brick_breadcrumbs[1].name == "brick_class" - - class TestAddBrickifcProject(NewFile): def test_run(self): ifc = ifcopenshell.file() @@ -313,14 +330,12 @@ class TestNewBrickFile(NewFile): BrickStore.schema.load_file(schema_path) # This is the actual test - ns_alias = "digitaltwin" - ns_uri = "https://example.org/digitaltwin#" subject.new_brick_file() assert BrickStore.graph - for ns in BrickStore.graph.namespaces(): - if ns[0] == ns_alias and ns[1].toPython() == ns_uri: - return - assert False + namespaces = [(ns[0], ns[1].toPython()) for ns in BrickStore.graph.namespaces()] + assert ("digitaltwin", "https://example.org/digitaltwin#") in namespaces + assert ("brick", "https://brickschema.org/schema/Brick#") in namespaces + assert ("rdfs", "http://www.w3.org/2000/01/rdf-schema#") in namespaces class TestPopBrickBreadcrumb(NewFile):