Skip to content
This repository was archived by the owner on Nov 24, 2024. It is now read-only.

Commit 136e1c3

Browse files
authored
Merge pull request IfcOpenShell#3364 from IfcOpenShell/interface-to-interact-with-Brickschema
Interface to interact with brickschema PR #1
2 parents c094517 + e6dc1d1 commit 136e1c3

File tree

8 files changed

+106
-30
lines changed

8 files changed

+106
-30
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,7 @@ src/ifcopenshell-python/ifcopenshell/_ifcopenshell_wrapper.so
9494
src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py
9595

9696
# apple
97-
.DS_Store
97+
.DS_Store
98+
99+
# Brickschema
100+
src/blenderbim/blenderbim/bim/schema/Brick.ttl

src/blenderbim/blenderbim/bim/module/brick/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
operator.RewindBrickClass,
3434
operator.ViewBrickClass,
3535
operator.ViewBrickItem,
36+
operator.UndoBrick,
37+
operator.RedoBrick,
38+
operator.SerializeBrick,
3639
prop.Brick,
3740
prop.BIMBrickProperties,
3841
ui.BIM_PT_brickschema,

src/blenderbim/blenderbim/bim/module/brick/data.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ def namespaces(cls):
110110
return []
111111
results = []
112112
for alias, uri in BrickStore.graph.namespaces():
113-
results.append((uri, f"{alias}: {uri}", ""))
113+
# results.append((uri, f"{alias}: {uri}", ""))
114+
results.append((uri, f"{alias}", ""))
114115
return results
115116

116117
@classmethod

src/blenderbim/blenderbim/bim/module/brick/operator.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,24 @@ def _execute(self, context):
189189
library=tool.Ifc.get().by_id(int(props.libraries)) if props.libraries else None,
190190
brick_uri=props.bricks[props.active_brick_index].uri,
191191
)
192+
193+
class UndoBrick(bpy.types.Operator, Operator):
194+
bl_idname = "bim.undo_brick"
195+
bl_label = "Undo Brick"
196+
197+
def _execute(self, context):
198+
core.undo_brick(tool.Brick)
199+
200+
class RedoBrick(bpy.types.Operator, Operator):
201+
bl_idname = "bim.redo_brick"
202+
bl_label = "Redo Brick"
203+
204+
def _execute(self, context):
205+
core.redo_brick(tool.Brick)
206+
207+
class SerializeBrick(bpy.types.Operator, Operator):
208+
bl_idname = "bim.serialize_brick"
209+
bl_label = "Serialize Brick"
210+
211+
def _execute(self, context):
212+
core.serialize_brick(tool.Brick)

src/blenderbim/blenderbim/bim/module/brick/ui.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ def draw(self, context):
5858
row.operator("bim.add_brick_feed", text="", icon="PLUGIN")
5959
row.operator("bim.remove_brick", text="", icon="X")
6060

61+
row = self.layout.row(align=True)
62+
row.operator("bim.undo_brick", icon="LOOP_BACK")
63+
row.operator("bim.redo_brick", icon="LOOP_FORWARDS")
64+
65+
row = self.layout.row(align=True)
66+
row.operator("bim.serialize_brick")
67+
6168
self.layout.template_list("BIM_UL_bricks", "", self.props, "bricks", self.props, "active_brick_index")
6269

6370
for attribute in BrickschemaData.data["attributes"]:

src/blenderbim/blenderbim/core/brick.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,14 @@ def remove_brick(ifc, brick, library=None, brick_uri=None):
109109
ifc.run("library.remove_reference", reference=reference)
110110
brick.remove_brick(brick_uri)
111111
brick.run_refresh_brick_viewer()
112+
113+
def undo_brick(brick):
114+
brick.undo_brick()
115+
brick.run_refresh_brick_viewer()
116+
117+
def redo_brick(brick):
118+
brick.redo_brick()
119+
brick.run_refresh_brick_viewer()
120+
121+
def serialize_brick(brick, file_name="BlenderBIMSerializeTest.ttl"):
122+
brick.serialize_brick(file_name)

src/blenderbim/blenderbim/tool/brick.py

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,28 @@
2525

2626
try:
2727
import brickschema
28+
import brickschema.persistent
2829
import urllib.parse
2930
from rdflib import Literal, URIRef, Namespace
3031
from rdflib.namespace import RDF
3132
except:
3233
# See #1860
3334
print("Warning: brickschema not available.")
3435

36+
# silence known rdflib_sqlalchemy TypeError warning
37+
# see https://github.com/BrickSchema/Brick/issues/513#issuecomment-1558493675
38+
import logging
39+
logger = logging.getLogger("rdflib")
40+
logger.setLevel(logging.ERROR)
3541

3642
class Brick(blenderbim.core.tool.Brick):
3743
@classmethod
3844
def add_brick(cls, namespace, brick_class):
3945
ns = Namespace(namespace)
4046
brick = ns[ifcopenshell.guid.expand(ifcopenshell.guid.new())]
41-
BrickStore.graph.add((brick, RDF.type, URIRef(brick_class)))
42-
BrickStore.graph.add((brick, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal("Unnamed")))
47+
with BrickStore.graph.new_changeset("PROJECT") as cs:
48+
cs.add((brick, RDF.type, URIRef(brick_class)))
49+
cs.add((brick, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal("Unnamed")))
4350
return str(brick)
4451

4552
@classmethod
@@ -100,7 +107,7 @@ def clear_brick_browser(cls):
100107

101108
@classmethod
102109
def clear_project(cls):
103-
BrickStore.graph = None
110+
BrickStore.purge()
104111
bpy.context.scene.BIMBrickProperties.active_brick_class == ""
105112
bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.clear()
106113

@@ -249,24 +256,24 @@ def import_brick_items(cls, brick_class):
249256

250257
@classmethod
251258
def load_brick_file(cls, filepath):
252-
if not BrickStore.schema:
253-
BrickStore.schema = brickschema.Graph()
259+
if not BrickStore.schema: # important check for running under test cases
254260
cwd = os.path.dirname(os.path.realpath(__file__))
255-
schema_path = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl")
256-
BrickStore.schema.load_file(schema_path)
257-
BrickStore.graph = brickschema.Graph().load_file(filepath) + BrickStore.schema
261+
BrickStore.schema = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl")
262+
BrickStore.graph = brickschema.persistent.VersionedGraphCollection("sqlite://")
263+
with BrickStore.graph.new_changeset("SCHEMA") as cs:
264+
cs.load_file(BrickStore.schema)
265+
with BrickStore.graph.new_changeset("PROJECT") as cs:
266+
cs.load_file(filepath)
258267
BrickStore.path = filepath
259268

260269
@classmethod
261270
def new_brick_file(cls):
262-
if not BrickStore.schema:
263-
BrickStore.schema = brickschema.Graph()
264-
#BrickStore.schema = brickschema.persistent.VersionedGraphCollection("sqlite://")
271+
if not BrickStore.schema: # important check for running under test cases
265272
cwd = os.path.dirname(os.path.realpath(__file__))
266-
schema_path = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl")
267-
BrickStore.schema.load_file(schema_path)
268-
#BrickStore.schema.load_graph(schema_path)
269-
BrickStore.graph = brickschema.Graph() + BrickStore.schema
273+
BrickStore.schema = os.path.join(cwd, "..", "bim", "schema", "Brick.ttl")
274+
BrickStore.graph = brickschema.persistent.VersionedGraphCollection("sqlite://")
275+
with BrickStore.graph.new_changeset("SCHEMA") as cs:
276+
cs.load_file(BrickStore.schema)
270277
BrickStore.graph.bind("digitaltwin", Namespace("https://example.org/digitaltwin#"))
271278
BrickStore.graph.bind("brick", Namespace("https://brickschema.org/schema/Brick#"))
272279
BrickStore.graph.bind("rdfs", Namespace("http://www.w3.org/2000/01/rdf-schema#"))
@@ -281,8 +288,10 @@ def pop_brick_breadcrumb(cls):
281288

282289
@classmethod
283290
def remove_brick(cls, brick_uri):
284-
for triple in BrickStore.graph.triples((URIRef(brick_uri), None, None)):
285-
BrickStore.graph.remove(triple)
291+
if(BrickStore.graph.triples((URIRef(brick_uri), None, None))):
292+
with BrickStore.graph.new_changeset("PROJECT") as cs:
293+
for triple in BrickStore.graph.triples((URIRef(brick_uri), None, None)):
294+
cs.remove(triple)
286295

287296
@classmethod
288297
def run_assign_brick_reference(cls, element=None, library=None, brick_uri=None):
@@ -308,14 +317,39 @@ def select_browser_item(cls, item):
308317
def set_active_brick_class(cls, brick_class):
309318
bpy.context.scene.BIMBrickProperties.active_brick_class = brick_class
310319

320+
@classmethod
321+
def undo_brick(cls):
322+
if(len(BrickStore.graph.versions()) > 1):
323+
BrickStore.graph.undo()
311324

312-
class BrickStore:
313-
schema = None
314-
graph = None
315-
path = None
325+
@classmethod
326+
def redo_brick(cls):
327+
with BrickStore.graph.conn() as conn:
328+
redo_record = conn.execute(
329+
"SELECT * from redos " "ORDER BY timestamp ASC LIMIT 1"
330+
).fetchone()
331+
if redo_record is not None:
332+
BrickStore.graph.redo()
316333

334+
@classmethod
335+
def serialize_brick(cls, file_name):
336+
#temporary file path, could either be user selected for "save as" or use the BrickStore.path for simply "save"
337+
cwd = os.path.dirname(os.path.realpath(__file__))
338+
dest = os.path.join(cwd, "..", "bim", "schema", file_name)
339+
BrickStore.get_project().serialize(destination=dest, format="turtle")
340+
341+
class BrickStore:
342+
schema = None # this is now a os path
343+
path = None # file path if the project was loaded in
344+
graph = None # this is the VersionedGraphCollection with 2 arbitrarily named graphs: "schema" and "project"
345+
# "SCHEMA" holds the Brick.ttl metadata; "PROJECT" holds all the authored entities
346+
317347
@staticmethod
318348
def purge():
319349
BrickStore.schema = None
320350
BrickStore.graph = None
321-
BrickStore.path = None
351+
BrickStore.path = None
352+
353+
@classmethod
354+
def get_project(cls):
355+
return BrickStore.graph.graph_at(graph="PROJECT")

src/blenderbim/test/tool/test_brick.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,8 @@ def test_run(self):
307307
class TestLoadBrickFile(NewFile):
308308
def test_run(self):
309309
# We stub the schema to make tests run faster
310-
BrickStore.schema = brickschema.Graph()
311310
cwd = os.path.dirname(os.path.realpath(__file__))
312-
schema_path = os.path.join(cwd, "..", "files", "BrickStub.ttl")
313-
BrickStore.schema.load_file(schema_path)
311+
BrickStore.schema = os.path.join(cwd, "..", "files", "BrickStub.ttl")
314312

315313
# This is the actual test
316314
cwd = os.path.dirname(os.path.realpath(__file__))
@@ -322,10 +320,8 @@ def test_run(self):
322320
class TestNewBrickFile(NewFile):
323321
def test_run(self):
324322
# We stub the schema to make tests run faster
325-
BrickStore.schema = brickschema.Graph()
326323
cwd = os.path.dirname(os.path.realpath(__file__))
327-
schema_path = os.path.join(cwd, "..", "files", "BrickStub.ttl")
328-
BrickStore.schema.load_file(schema_path)
324+
BrickStore.schema = os.path.join(cwd, "..", "files", "BrickStub.ttl")
329325

330326
# This is the actual test
331327
subject.new_brick_file()

0 commit comments

Comments
 (0)