Merge pull request #3364 from IfcOpenShell/interface-to-interact-with-Brickschema

Interface to interact with brickschema PR #1
This commit is contained in:
Dion Moult
2023-07-03 09:55:09 +10:00
committed by GitHub
8 changed files with 106 additions and 30 deletions
+4 -1
View File
@@ -94,4 +94,7 @@ src/ifcopenshell-python/ifcopenshell/_ifcopenshell_wrapper.so
src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py
# apple
.DS_Store
.DS_Store
# Brickschema
src/blenderbim/blenderbim/bim/schema/Brick.ttl
@@ -33,6 +33,9 @@ classes = (
operator.RewindBrickClass,
operator.ViewBrickClass,
operator.ViewBrickItem,
operator.UndoBrick,
operator.RedoBrick,
operator.SerializeBrick,
prop.Brick,
prop.BIMBrickProperties,
ui.BIM_PT_brickschema,
@@ -110,7 +110,8 @@ class BrickschemaData:
return []
results = []
for alias, uri in BrickStore.graph.namespaces():
results.append((uri, f"{alias}: {uri}", ""))
# results.append((uri, f"{alias}: {uri}", ""))
results.append((uri, f"{alias}", ""))
return results
@classmethod
@@ -189,3 +189,24 @@ class RemoveBrick(bpy.types.Operator, Operator):
library=tool.Ifc.get().by_id(int(props.libraries)) if props.libraries else None,
brick_uri=props.bricks[props.active_brick_index].uri,
)
class UndoBrick(bpy.types.Operator, Operator):
bl_idname = "bim.undo_brick"
bl_label = "Undo Brick"
def _execute(self, context):
core.undo_brick(tool.Brick)
class RedoBrick(bpy.types.Operator, Operator):
bl_idname = "bim.redo_brick"
bl_label = "Redo Brick"
def _execute(self, context):
core.redo_brick(tool.Brick)
class SerializeBrick(bpy.types.Operator, Operator):
bl_idname = "bim.serialize_brick"
bl_label = "Serialize Brick"
def _execute(self, context):
core.serialize_brick(tool.Brick)
@@ -58,6 +58,13 @@ class BIM_PT_brickschema(Panel):
row.operator("bim.add_brick_feed", text="", icon="PLUGIN")
row.operator("bim.remove_brick", text="", icon="X")
row = self.layout.row(align=True)
row.operator("bim.undo_brick", icon="LOOP_BACK")
row.operator("bim.redo_brick", icon="LOOP_FORWARDS")
row = self.layout.row(align=True)
row.operator("bim.serialize_brick")
self.layout.template_list("BIM_UL_bricks", "", self.props, "bricks", self.props, "active_brick_index")
for attribute in BrickschemaData.data["attributes"]:
+11
View File
@@ -109,3 +109,14 @@ def remove_brick(ifc, brick, library=None, brick_uri=None):
ifc.run("library.remove_reference", reference=reference)
brick.remove_brick(brick_uri)
brick.run_refresh_brick_viewer()
def undo_brick(brick):
brick.undo_brick()
brick.run_refresh_brick_viewer()
def redo_brick(brick):
brick.redo_brick()
brick.run_refresh_brick_viewer()
def serialize_brick(brick, file_name="BlenderBIMSerializeTest.ttl"):
brick.serialize_brick(file_name)
+56 -22
View File
@@ -25,6 +25,7 @@ import blenderbim.tool as tool
try:
import brickschema
import brickschema.persistent
import urllib.parse
from rdflib import Literal, URIRef, Namespace
from rdflib.namespace import RDF
@@ -32,14 +33,20 @@ except:
# See #1860
print("Warning: brickschema not available.")
# silence known rdflib_sqlalchemy TypeError warning
# see https://github.com/BrickSchema/Brick/issues/513#issuecomment-1558493675
import logging
logger = logging.getLogger("rdflib")
logger.setLevel(logging.ERROR)
class Brick(blenderbim.core.tool.Brick):
@classmethod
def add_brick(cls, namespace, brick_class):
ns = Namespace(namespace)
brick = ns[ifcopenshell.guid.expand(ifcopenshell.guid.new())]
BrickStore.graph.add((brick, RDF.type, URIRef(brick_class)))
BrickStore.graph.add((brick, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal("Unnamed")))
with BrickStore.graph.new_changeset("PROJECT") as cs:
cs.add((brick, RDF.type, URIRef(brick_class)))
cs.add((brick, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal("Unnamed")))
return str(brick)
@classmethod
@@ -100,7 +107,7 @@ class Brick(blenderbim.core.tool.Brick):
@classmethod
def clear_project(cls):
BrickStore.graph = None
BrickStore.purge()
bpy.context.scene.BIMBrickProperties.active_brick_class == ""
bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.clear()
@@ -249,24 +256,24 @@ class Brick(blenderbim.core.tool.Brick):
@classmethod
def load_brick_file(cls, filepath):
if not BrickStore.schema:
BrickStore.schema = brickschema.Graph()
if not BrickStore.schema: # important check for running under test cases
cwd = os.path.dirname(os.path.realpath(__file__))
schema_path = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl")
BrickStore.schema.load_file(schema_path)
BrickStore.graph = brickschema.Graph().load_file(filepath) + BrickStore.schema
BrickStore.schema = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl")
BrickStore.graph = brickschema.persistent.VersionedGraphCollection("sqlite://")
with BrickStore.graph.new_changeset("SCHEMA") as cs:
cs.load_file(BrickStore.schema)
with BrickStore.graph.new_changeset("PROJECT") as cs:
cs.load_file(filepath)
BrickStore.path = filepath
@classmethod
def new_brick_file(cls):
if not BrickStore.schema:
BrickStore.schema = brickschema.Graph()
#BrickStore.schema = brickschema.persistent.VersionedGraphCollection("sqlite://")
if not BrickStore.schema: # important check for running under test cases
cwd = os.path.dirname(os.path.realpath(__file__))
schema_path = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl")
BrickStore.schema.load_file(schema_path)
#BrickStore.schema.load_graph(schema_path)
BrickStore.graph = brickschema.Graph() + BrickStore.schema
BrickStore.schema = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl")
BrickStore.graph = brickschema.persistent.VersionedGraphCollection("sqlite://")
with BrickStore.graph.new_changeset("SCHEMA") as cs:
cs.load_file(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#"))
@@ -281,8 +288,10 @@ class Brick(blenderbim.core.tool.Brick):
@classmethod
def remove_brick(cls, brick_uri):
for triple in BrickStore.graph.triples((URIRef(brick_uri), None, None)):
BrickStore.graph.remove(triple)
if(BrickStore.graph.triples((URIRef(brick_uri), None, None))):
with BrickStore.graph.new_changeset("PROJECT") as cs:
for triple in BrickStore.graph.triples((URIRef(brick_uri), None, None)):
cs.remove(triple)
@classmethod
def run_assign_brick_reference(cls, element=None, library=None, brick_uri=None):
@@ -308,14 +317,39 @@ class Brick(blenderbim.core.tool.Brick):
def set_active_brick_class(cls, brick_class):
bpy.context.scene.BIMBrickProperties.active_brick_class = brick_class
@classmethod
def undo_brick(cls):
if(len(BrickStore.graph.versions()) > 1):
BrickStore.graph.undo()
@classmethod
def redo_brick(cls):
with BrickStore.graph.conn() as conn:
redo_record = conn.execute(
"SELECT * from redos " "ORDER BY timestamp ASC LIMIT 1"
).fetchone()
if redo_record is not None:
BrickStore.graph.redo()
@classmethod
def serialize_brick(cls, file_name):
#temporary file path, could either be user selected for "save as" or use the BrickStore.path for simply "save"
cwd = os.path.dirname(os.path.realpath(__file__))
dest = os.path.join(cwd, "..", "bim", "schema", file_name)
BrickStore.get_project().serialize(destination=dest, format="turtle")
class BrickStore:
schema = None
graph = None
path = None
schema = None # this is now a os path
path = None # file path if the project was loaded in
graph = None # this is the VersionedGraphCollection with 2 arbitrarily named graphs: "schema" and "project"
# "SCHEMA" holds the Brick.ttl metadata; "PROJECT" holds all the authored entities
@staticmethod
def purge():
BrickStore.schema = None
BrickStore.graph = None
BrickStore.path = None
BrickStore.path = None
@classmethod
def get_project(cls):
return BrickStore.graph.graph_at(graph="PROJECT")
+2 -6
View File
@@ -307,10 +307,8 @@ class TestImportBrickItems(NewFile):
class TestLoadBrickFile(NewFile):
def test_run(self):
# We stub the schema to make tests run faster
BrickStore.schema = brickschema.Graph()
cwd = os.path.dirname(os.path.realpath(__file__))
schema_path = os.path.join(cwd, "..", "files", "BrickStub.ttl")
BrickStore.schema.load_file(schema_path)
BrickStore.schema = os.path.join(cwd, "..", "files", "BrickStub.ttl")
# This is the actual test
cwd = os.path.dirname(os.path.realpath(__file__))
@@ -322,10 +320,8 @@ class TestLoadBrickFile(NewFile):
class TestNewBrickFile(NewFile):
def test_run(self):
# We stub the schema to make tests run faster
BrickStore.schema = brickschema.Graph()
cwd = os.path.dirname(os.path.realpath(__file__))
schema_path = os.path.join(cwd, "..", "files", "BrickStub.ttl")
BrickStore.schema.load_file(schema_path)
BrickStore.schema = os.path.join(cwd, "..", "files", "BrickStub.ttl")
# This is the actual test
subject.new_brick_file()