Files
IfcOpenShell/src/blenderbim/blenderbim/tool/brick.py
T

292 lines
10 KiB
Python

# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# 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 <http://www.gnu.org/licenses/>.
import os
import bpy
import ifcopenshell
import ifcopenshell.util.brick
import blenderbim.core.tool
import blenderbim.tool as tool
try:
import brickschema
import urllib.parse
from rdflib import Literal, URIRef, Namespace
from rdflib.namespace import RDF
except:
# See #1860
print("Warning: brickschema not available.")
class Brick(blenderbim.core.tool.Brick):
@classmethod
def add_brick(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_brick_breadcrumb(cls):
new = bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.add()
new.name = bpy.context.scene.BIMBrickProperties.active_brick_class
@classmethod
def add_brickifc_project(cls, namespace):
project = tool.Ifc.get().by_type("IfcProject")[0]
ns = Namespace(namespace)
ns_brickifc = Namespace("https://brickschema.org/extension/ifc#")
BrickStore.graph.bind("brickifc", ns_brickifc)
brick_project = ns[project.GlobalId]
BrickStore.graph.add((brick_project, RDF.type, ns_brickifc["Project"]))
if project.Name:
BrickStore.graph.add(
(brick_project, URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal(project.Name))
)
BrickStore.graph.add((brick_project, ns_brickifc["projectID"], Literal(project.GlobalId)))
BrickStore.graph.add(
(brick_project, ns_brickifc["fileLocation"], Literal(bpy.context.scene.BIMProperties.ifc_file))
)
return str(brick_project)
@classmethod
def add_brickifc_reference(cls, brick, element, project):
ns_brickifc = Namespace("https://brickschema.org/extension/ifc#")
BrickStore.graph.bind("brickifc", ns_brickifc)
BrickStore.graph.add(
(
URIRef(brick),
ns_brickifc["hasIFCReference"],
[
(ns_brickifc["hasProjectReference"], URIRef(project)),
(ns_brickifc["globalID"], Literal(element.GlobalId)),
],
)
)
@classmethod
def add_feed(cls, source, destination):
ns_brick = Namespace("https://brickschema.org/schema/Brick#")
BrickStore.graph.add((URIRef(source), ns_brick["feeds"], URIRef(destination)))
@classmethod
def clear_brick_browser(cls):
bpy.context.scene.BIMBrickProperties.bricks.clear()
@classmethod
def clear_project(cls):
BrickStore.graph = None
bpy.context.scene.BIMBrickProperties.active_brick_class == ""
bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.clear()
@classmethod
def export_brick_attributes(cls, brick_uri):
if tool.Ifc.get_schema() == "IFC2X3":
return {"ItemReference": brick_uri, "Name": brick_uri.split("#")[-1]}
else:
return {"Identification": brick_uri, "Name": brick_uri.split("#")[-1]}
@classmethod
def get_brick(cls, element):
for rel in element.HasAssociations:
if rel.is_a("IfcRelAssociatesLibrary"):
if tool.Ifc.get_schema() == "IFC2X3" and "#" in rel.RelatingLibrary.ItemReference:
return rel.RelatingLibrary.ItemReference
if tool.Ifc.get_schema() != "IFC2X3" and "#" in rel.RelatingLibrary.Identification:
return rel.RelatingLibrary.Identification
@classmethod
def get_brick_class(cls, element):
return ifcopenshell.util.brick.get_brick_type(element)
@classmethod
def get_brick_path(cls):
return BrickStore.path
@classmethod
def get_brick_path_name(cls):
return os.path.basename(BrickStore.path)
@classmethod
def get_brickifc_project(cls):
project = tool.Ifc.get().by_type("IfcProject")[0]
query = BrickStore.graph.query(
"""
PREFIX brickifc: <https://brickschema.org/extension/ifc#>
SELECT ?proj WHERE {
?proj a brickifc:Project .
?proj brickifc:projectID "{project_globalid}"
}
LIMIT 1
""".replace(
"{project_globalid}", project.GlobalId
)
)
results = list(query)
if results:
return results[0][0].toPython()
@classmethod
def get_convertable_brick_objects_and_elements(cls):
results = []
for element in ifcopenshell.util.brick.get_brick_elements(tool.Ifc.get()):
obj = tool.Ifc.get_object(element)
if obj:
results.append((obj, element))
return results
@classmethod
def get_item_class(cls, item):
query = BrickStore.graph.query(
"""
PREFIX brick: <https://brickschema.org/schema/Brick#>
SELECT ?class WHERE {
<{item}> a ?class .
}
LIMIT 1
""".replace(
"{item}", item
)
)
for row in query:
return row.get("class").toPython().split("#")[-1]
@classmethod
def get_library_brick_reference(cls, library, brick_uri):
if tool.Ifc.get_schema() == "IFC2X3":
for reference in library.LibraryReference or []:
if reference.ItemReference == brick_uri:
return reference
else:
for reference in library.HasLibraryReferences or []:
if reference.Identification == brick_uri:
return reference
@classmethod
def get_namespace(cls, uri):
return uri.split("#")[0] + "#"
@classmethod
def import_brick_classes(cls, brick_class):
query = BrickStore.graph.query(
"""
PREFIX brick: <https://brickschema.org/schema/Brick#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?group (count(?item) as ?total_items) ?label WHERE {
?group rdfs:subClassOf brick:{brick_class} .
?item rdf:type/rdfs:subClassOf* ?group .
OPTIONAL {
?group rdfs:label ?label
}
}
GROUP BY ?group
ORDER BY asc(?group)
""".replace(
"{brick_class}", brick_class
)
)
for row in query:
new = bpy.context.scene.BIMBrickProperties.bricks.add()
label = row.get("label")
if label:
new.label = label.toPython()
new.name = row.get("group").toPython().split("#")[-1]
new.uri = row.get("group").toPython()
new.total_items = row.get("total_items").toPython()
@classmethod
def import_brick_items(cls, brick_class):
query = BrickStore.graph.query(
"""
PREFIX brick: <https://brickschema.org/schema/Brick#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?item ?label WHERE {
?item rdf:type brick:{brick_class} .
OPTIONAL {
?item rdfs:label ?label
}
}
ORDER BY asc(?item)
""".replace(
"{brick_class}", brick_class
)
)
for row in query:
new = bpy.context.scene.BIMBrickProperties.bricks.add()
label = row.get("label")
if label:
new.label = label.toPython()
new.name = row.get("item").toPython().split("#")[-1]
new.uri = row.get("item").toPython()
@classmethod
def load_brick_file(cls, filepath):
if not BrickStore.schema:
BrickStore.schema = brickschema.Graph()
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.path = filepath
@classmethod
def pop_brick_breadcrumb(cls):
crumb = bpy.context.scene.BIMBrickProperties.brick_breadcrumbs[-1]
name = crumb.name
last_index = len(bpy.context.scene.BIMBrickProperties.brick_breadcrumbs) - 1
bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.remove(last_index)
return name
@classmethod
def run_add_brick(cls, obj=None, namespace=None, brick_class=None, library=None):
return blenderbim.core.brick.add_brick(
tool.Ifc, tool.Brick, obj=obj, namespace=namespace, brick_class=brick_class, library=library
)
@classmethod
def run_assign_brick_reference(cls, obj=None, library=None, brick_uri=None):
return blenderbim.core.brick.assign_brick_reference(
tool.Ifc, tool.Brick, obj=obj, library=library, brick_uri=brick_uri
)
@classmethod
def select_browser_item(cls, item):
name = item.split("#")[-1]
props = bpy.context.scene.BIMBrickProperties
props.active_brick_index = props.bricks.find(name)
@classmethod
def set_active_brick_class(cls, brick_class):
bpy.context.scene.BIMBrickProperties.active_brick_class = brick_class
class BrickStore:
schema = None
graph = None
path = None
@staticmethod
def purge():
BrickStore.schema = None
BrickStore.graph = None
BrickStore.path = None