mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
typing
This commit is contained in:
@@ -52,7 +52,7 @@ class BrickschemaData:
|
||||
def active_relations(cls):
|
||||
if BrickStore.graph is None:
|
||||
return []
|
||||
props = bpy.context.scene.BIMBrickProperties
|
||||
props = tool.Brick.get_brick_props()
|
||||
try:
|
||||
brick = props.bricks[props.active_brick_index]
|
||||
except:
|
||||
|
||||
@@ -36,7 +36,7 @@ class LoadBrickProject(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
if os.path.exists(self.filepath) and "ttl" in os.path.splitext(self.filepath)[1].lower():
|
||||
root = context.scene.BIMBrickProperties.brick_list_root
|
||||
root = tool.Brick.get_brick_props().brick_list_root
|
||||
core.load_brick_project(tool.Brick, filepath=self.filepath, brick_root=root)
|
||||
else:
|
||||
self.report({"ERROR"}, f"Failed to load {self.filepath}")
|
||||
@@ -111,10 +111,10 @@ class AssignBrickReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_description = "Assign the selected Ifc entity to the selected Brick entity"
|
||||
|
||||
def _execute(self, context):
|
||||
if not context.active_object:
|
||||
if not (obj := context.active_object) or not (element := tool.Ifc.get_entity(obj)):
|
||||
self.report({"ERROR"}, f"No Ifc selected")
|
||||
return
|
||||
props = context.scene.BIMBrickProperties
|
||||
props = tool.Brick.get_brick_props()
|
||||
try:
|
||||
props.bricks[props.active_brick_index]
|
||||
except:
|
||||
@@ -123,7 +123,7 @@ class AssignBrickReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||
core.assign_brick_reference(
|
||||
tool.Ifc,
|
||||
tool.Brick,
|
||||
element=tool.Ifc.get_entity(context.active_object),
|
||||
element=element,
|
||||
library=tool.Ifc.get().by_id(int(props.libraries)),
|
||||
brick_uri=props.bricks[props.active_brick_index].uri,
|
||||
)
|
||||
@@ -136,7 +136,7 @@ class AddBrick(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_description = "Create the Brick entity"
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBrickProperties
|
||||
props = tool.Brick.get_brick_props()
|
||||
core.add_brick(
|
||||
tool.Ifc,
|
||||
tool.Brick,
|
||||
@@ -155,7 +155,7 @@ class AddBrickRelation(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_description = "Create the Brick relationship"
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBrickProperties
|
||||
props = tool.Brick.get_brick_props()
|
||||
brick = props.bricks[props.active_brick_index]
|
||||
if props.new_brick_relation_type == "http://www.w3.org/2000/01/rdf-schema#label":
|
||||
object = props.new_brick_relation_object
|
||||
@@ -173,7 +173,7 @@ class ConvertIfcToBrick(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_description = "Convert Ifc entities and relations to Brick entities and relations"
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBrickProperties
|
||||
props = tool.Brick.get_brick_props()
|
||||
library = None
|
||||
if props.libraries:
|
||||
library = tool.Ifc.get().by_id(int(props.libraries))
|
||||
@@ -201,7 +201,8 @@ class NewBrickFile(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
def _execute(self, context):
|
||||
root = context.scene.BIMBrickProperties.brick_list_root
|
||||
props = tool.Brick.get_brick_props()
|
||||
root = props.brick_list_root
|
||||
core.new_brick_file(tool.Brick, brick_root=root)
|
||||
|
||||
def rollback(self, data):
|
||||
@@ -230,7 +231,7 @@ class RemoveBrick(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_description = "Delete this entity"
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBrickProperties
|
||||
props = tool.Brick.get_brick_props()
|
||||
core.remove_brick(
|
||||
tool.Ifc,
|
||||
tool.Brick,
|
||||
@@ -273,7 +274,7 @@ class AddBrickNamespace(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_description = "Bind a new namespace to the Brick project"
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBrickProperties
|
||||
props = tool.Brick.get_brick_props()
|
||||
alias = props.new_brick_namespace_alias
|
||||
uri = props.new_brick_namespace_uri
|
||||
core.add_brick_namespace(tool.Brick, alias=alias, uri=uri)
|
||||
@@ -288,6 +289,6 @@ class RemoveBrickRelation(bpy.types.Operator, tool.Ifc.Operator):
|
||||
object: bpy.props.StringProperty(name="Object")
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMBrickProperties
|
||||
props = tool.Brick.get_brick_props()
|
||||
brick = props.bricks[props.active_brick_index]
|
||||
core.remove_brick_relation(tool.Brick, brick_uri=brick.uri, predicate=self.predicate, object=self.object)
|
||||
|
||||
@@ -33,6 +33,7 @@ from bpy.props import (
|
||||
import bonsai.core.brick as core
|
||||
import bonsai.tool.brick as tool
|
||||
from bonsai.tool.brick import BrickStore
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
||||
def update_active_brick_index(self, context):
|
||||
@@ -74,13 +75,13 @@ def get_brick_relations(self, context):
|
||||
return BRICK_RELATIONS_ENUM_ITEMS
|
||||
|
||||
|
||||
def update_view(self, context):
|
||||
root = context.scene.BIMBrickProperties.brick_list_root
|
||||
def update_view(self: "BIMBrickProperties", context: bpy.types.Context) -> None:
|
||||
root = self.brick_list_root
|
||||
core.set_brick_list_root(tool.Brick, brick_root=root, split_screen=False)
|
||||
|
||||
|
||||
def split_screen_update_view(self, context):
|
||||
root = context.scene.BIMBrickProperties.split_screen_brick_list_root
|
||||
def split_screen_update_view(self: "BIMBrickProperties", context: bpy.types.Context) -> None:
|
||||
root = self.split_screen_brick_list_root
|
||||
core.set_brick_list_root(tool.Brick, brick_root=root, split_screen=True)
|
||||
|
||||
|
||||
@@ -90,6 +91,11 @@ class Brick(PropertyGroup):
|
||||
uri: StringProperty(name="URI")
|
||||
total_items: IntProperty(name="Total Items")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
label: str
|
||||
uri: str
|
||||
total_items: int
|
||||
|
||||
|
||||
class BIMBrickProperties(PropertyGroup):
|
||||
active_brick_class: StringProperty(name="Active Brick Class")
|
||||
@@ -124,3 +130,28 @@ class BIMBrickProperties(PropertyGroup):
|
||||
split_screen_brick_list_root: EnumProperty(
|
||||
name="Split Screen Brick List Root", items=get_brick_roots, update=split_screen_update_view
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
active_brick_class: str
|
||||
brick_breadcrumbs: bpy.types.bpy_prop_collection_idprop[StrProperty]
|
||||
bricks: bpy.types.bpy_prop_collection_idprop[Brick]
|
||||
active_brick_index: int
|
||||
libraries: str
|
||||
set_list_root_toggled: bool
|
||||
brick_list_root: str
|
||||
namespace: str
|
||||
new_brick_namespace_alias: str
|
||||
new_brick_namespace_uri: str
|
||||
new_brick_label: str
|
||||
brick_entity_create_type: str
|
||||
brick_entity_class: str
|
||||
brick_create_relations_toggled: bool
|
||||
brick_edit_relations_toggled: bool
|
||||
new_brick_relation_type: str
|
||||
new_brick_relation_object: str
|
||||
split_screen_toggled: bool
|
||||
split_screen_bricks: bpy.types.bpy_prop_collection_idprop[Brick]
|
||||
split_screen_active_brick_index: int
|
||||
split_screen_active_brick_class: str
|
||||
split_screen_brick_breadcrumbs: bpy.types.bpy_prop_collection_idprop[StrProperty]
|
||||
split_screen_brick_list_root: str
|
||||
|
||||
@@ -45,7 +45,7 @@ class BIM_PT_brickschema_project_info(Panel):
|
||||
bl_parent_id = "BIM_PT_brickschema"
|
||||
|
||||
def draw(self, context):
|
||||
self.props = context.scene.BIMBrickProperties
|
||||
self.props = tool.Brick.get_brick_props()
|
||||
|
||||
if not BrickschemaData.data["is_loaded"]:
|
||||
row = self.layout.row(align=True)
|
||||
@@ -87,7 +87,7 @@ class BIM_PT_brickschema_namespaces(Panel):
|
||||
return BrickStore.graph != None
|
||||
|
||||
def draw(self, context):
|
||||
self.props = context.scene.BIMBrickProperties
|
||||
self.props = tool.Brick.get_brick_props()
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Active Namespace:")
|
||||
@@ -122,7 +122,7 @@ class BIM_PT_brickschema_create_entity(Panel):
|
||||
return BrickStore.graph != None
|
||||
|
||||
def draw(self, context):
|
||||
self.props = context.scene.BIMBrickProperties
|
||||
self.props = tool.Brick.get_brick_props()
|
||||
# TO DO: hide this if selected entity already has a reference, or something similar
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
@@ -156,7 +156,7 @@ class BIM_PT_brickschema_viewport(Panel):
|
||||
return BrickStore.graph != None
|
||||
|
||||
def draw(self, context):
|
||||
self.props = context.scene.BIMBrickProperties
|
||||
self.props = tool.Brick.get_brick_props()
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.column().alignment = "RIGHT"
|
||||
@@ -292,7 +292,7 @@ class BIM_PT_ifc_brickschema_references(Panel):
|
||||
def draw(self, context):
|
||||
if not BrickschemaReferencesData.is_loaded:
|
||||
BrickschemaReferencesData.load()
|
||||
self.props = context.scene.BIMBrickProperties
|
||||
self.props = tool.Brick.get_brick_props()
|
||||
|
||||
if not BrickschemaReferencesData.data["is_loaded"]:
|
||||
row = self.layout.row()
|
||||
|
||||
@@ -21,6 +21,7 @@ import bmesh
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.api.root
|
||||
import ifcopenshell.util.schema
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.shape_builder
|
||||
@@ -149,10 +150,9 @@ class ReassignClass(bpy.types.Operator, tool.Ifc.Operator):
|
||||
elements_to_update = elements_to_update | set(elements_to_reassign)
|
||||
objects_to_update = set(o for e in elements_to_update if (o := tool.Ifc.get_object(e)))
|
||||
|
||||
reassigned_elements = set()
|
||||
reassigned_elements: set[ifcopenshell.entity_instance] = set()
|
||||
for element, ifc_class_ in elements_to_reassign.items():
|
||||
element = ifcopenshell.api.run(
|
||||
"root.reassign_class",
|
||||
element = ifcopenshell.api.root.reassign_class(
|
||||
self.file,
|
||||
product=element,
|
||||
ifc_class=ifc_class_,
|
||||
|
||||
@@ -16,8 +16,16 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Optional, Union
|
||||
|
||||
def load_brick_project(brick, filepath=None, brick_root=None):
|
||||
if TYPE_CHECKING:
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import bonsai.tool as tool
|
||||
|
||||
|
||||
def load_brick_project(brick: tool.Brick, filepath: str, brick_root: str) -> None:
|
||||
brick.load_brick_file(filepath)
|
||||
brick.import_brick_classes(brick_root)
|
||||
brick.import_brick_classes(brick_root, split_screen=True)
|
||||
@@ -25,7 +33,7 @@ def load_brick_project(brick, filepath=None, brick_root=None):
|
||||
brick.set_active_brick_class(brick_root, split_screen=True)
|
||||
|
||||
|
||||
def new_brick_file(brick, brick_root=None):
|
||||
def new_brick_file(brick: tool.Brick, brick_root: str) -> None:
|
||||
brick.new_brick_file()
|
||||
brick.import_brick_classes(brick_root)
|
||||
brick.import_brick_classes(brick_root, split_screen=True)
|
||||
@@ -33,7 +41,7 @@ def new_brick_file(brick, brick_root=None):
|
||||
brick.set_active_brick_class(brick_root, split_screen=True)
|
||||
|
||||
|
||||
def view_brick_class(brick, brick_class=None, split_screen=False):
|
||||
def view_brick_class(brick: tool.Brick, brick_class: str, split_screen: bool = False) -> None:
|
||||
brick.add_brick_breadcrumb(split_screen=split_screen)
|
||||
brick.clear_brick_browser(split_screen=split_screen)
|
||||
brick.import_brick_classes(brick_class, split_screen=split_screen)
|
||||
@@ -41,13 +49,13 @@ def view_brick_class(brick, brick_class=None, split_screen=False):
|
||||
brick.set_active_brick_class(brick_class, split_screen=split_screen)
|
||||
|
||||
|
||||
def view_brick_item(brick, item=None, split_screen=False):
|
||||
def view_brick_item(brick: tool.Brick, item: str, split_screen: bool = False) -> None:
|
||||
brick_class = brick.get_item_class(item)
|
||||
brick.run_view_brick_class(brick_class=brick_class, split_screen=split_screen)
|
||||
brick.select_browser_item(item, split_screen=split_screen)
|
||||
|
||||
|
||||
def rewind_brick_class(brick, split_screen=False):
|
||||
def rewind_brick_class(brick: tool.Brick, split_screen: bool = False) -> None:
|
||||
previous_class = brick.pop_brick_breadcrumb(split_screen=split_screen)
|
||||
brick.clear_brick_browser(split_screen=split_screen)
|
||||
brick.import_brick_classes(previous_class, split_screen=split_screen)
|
||||
@@ -55,7 +63,7 @@ def rewind_brick_class(brick, split_screen=False):
|
||||
brick.set_active_brick_class(previous_class, split_screen=split_screen)
|
||||
|
||||
|
||||
def close_brick_project(brick):
|
||||
def close_brick_project(brick: tool.Brick) -> None:
|
||||
brick.clear_project()
|
||||
brick.clear_brick_browser()
|
||||
brick.clear_brick_browser(split_screen=True)
|
||||
@@ -63,13 +71,19 @@ def close_brick_project(brick):
|
||||
brick.clear_breadcrumbs(split_screen=True)
|
||||
|
||||
|
||||
def convert_brick_project(ifc, brick):
|
||||
def convert_brick_project(ifc: tool.Ifc, brick: tool.Brick) -> None:
|
||||
library = ifc.run("library.add_library", name=brick.get_brick_path_name())
|
||||
if ifc.get_schema() != "IFC2X3":
|
||||
ifc.run("library.edit_library", library=library, attributes={"Location": brick.get_brick_path()})
|
||||
|
||||
|
||||
def assign_brick_reference(ifc, brick, element=None, library=None, brick_uri=None):
|
||||
def assign_brick_reference(
|
||||
ifc: tool.Ifc,
|
||||
brick: tool.Brick,
|
||||
element: ifcopenshell.entity_instance,
|
||||
library: ifcopenshell.entity_instance,
|
||||
brick_uri: str,
|
||||
) -> None:
|
||||
reference = brick.get_library_brick_reference(library, brick_uri)
|
||||
if not reference:
|
||||
reference = ifc.run("library.add_reference", library=library)
|
||||
@@ -81,7 +95,15 @@ def assign_brick_reference(ifc, brick, element=None, library=None, brick_uri=Non
|
||||
brick.add_brickifc_reference(brick_uri, element, project)
|
||||
|
||||
|
||||
def add_brick(ifc, brick, element=None, namespace=None, brick_class=None, library=None, label="Unnamed"):
|
||||
def add_brick(
|
||||
ifc: tool.Ifc,
|
||||
brick: tool.Brick,
|
||||
element: Union[ifcopenshell.entity_instance, None],
|
||||
namespace: str,
|
||||
brick_class: str,
|
||||
library: Union[str, None],
|
||||
label: str = "Unnamed",
|
||||
) -> None:
|
||||
if element:
|
||||
brick_uri = brick.add_brick_from_element(element, namespace, brick_class)
|
||||
if library:
|
||||
@@ -91,12 +113,12 @@ def add_brick(ifc, brick, element=None, namespace=None, brick_class=None, librar
|
||||
brick.run_refresh_brick_viewer()
|
||||
|
||||
|
||||
def add_brick_relation(brick, brick_uri=None, predicate=None, object=None):
|
||||
def add_brick_relation(brick: tool.Brick, brick_uri: str, predicate: str, object: str) -> None:
|
||||
brick.add_relation(brick_uri, predicate, object)
|
||||
brick.run_refresh_brick_viewer()
|
||||
|
||||
|
||||
def convert_ifc_to_brick(brick, namespace=None, library=None):
|
||||
def convert_ifc_to_brick(brick: tool.Brick, namespace: str, library: Union[ifcopenshell.entity_instance, None]) -> None:
|
||||
# convert spaces to brick
|
||||
spaces = brick.get_convertable_brick_spaces()
|
||||
space_uris = {}
|
||||
@@ -141,14 +163,14 @@ def convert_ifc_to_brick(brick, namespace=None, library=None):
|
||||
brick.run_refresh_brick_viewer()
|
||||
|
||||
|
||||
def refresh_brick_viewer(brick):
|
||||
def refresh_brick_viewer(brick: tool.Brick) -> None:
|
||||
brick.run_view_brick_class(brick_class=brick.get_active_brick_class())
|
||||
brick.pop_brick_breadcrumb()
|
||||
brick.run_view_brick_class(brick_class=brick.get_active_brick_class(split_screen=True), split_screen=True)
|
||||
brick.pop_brick_breadcrumb(split_screen=True)
|
||||
|
||||
|
||||
def remove_brick(ifc, brick, library=None, brick_uri=None):
|
||||
def remove_brick(ifc: tool.Ifc, brick: tool.Brick, library: ifcopenshell.entity_instance, brick_uri: str) -> None:
|
||||
if library:
|
||||
reference = brick.get_library_brick_reference(library, brick_uri)
|
||||
if reference:
|
||||
@@ -157,18 +179,18 @@ def remove_brick(ifc, brick, library=None, brick_uri=None):
|
||||
brick.run_refresh_brick_viewer()
|
||||
|
||||
|
||||
def serialize_brick(brick):
|
||||
def serialize_brick(brick: tool.Brick) -> None:
|
||||
brick.serialize_brick()
|
||||
|
||||
|
||||
def add_brick_namespace(brick, alias=None, uri=None):
|
||||
def add_brick_namespace(brick: tool.Brick, alias: str, uri: str) -> None:
|
||||
brick.add_namespace(alias, uri)
|
||||
|
||||
|
||||
def set_brick_list_root(brick, brick_root=None, split_screen=False):
|
||||
def set_brick_list_root(brick: tool.Brick, brick_root: str, split_screen: bool = False) -> None:
|
||||
brick.run_view_brick_class(brick_class=brick_root, split_screen=split_screen)
|
||||
brick.clear_breadcrumbs(split_screen=split_screen)
|
||||
|
||||
|
||||
def remove_brick_relation(brick, brick_uri=None, predicate=None, object=None):
|
||||
def remove_brick_relation(brick: tool.Brick, brick_uri: str, predicate: str, object: str) -> None:
|
||||
brick.remove_relation(brick_uri, predicate, object)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import annotations
|
||||
import os
|
||||
import bpy
|
||||
import datetime
|
||||
@@ -29,6 +30,7 @@ import bonsai.core.tool
|
||||
import bonsai.tool as tool
|
||||
from pathlib import Path
|
||||
from contextlib import contextmanager
|
||||
from typing import Generator, Any, Union, TYPE_CHECKING
|
||||
|
||||
try:
|
||||
import brickschema
|
||||
@@ -41,6 +43,11 @@ except:
|
||||
# See #1860
|
||||
print("Warning: brickschema not available.")
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import brickschema
|
||||
from rdflib import Literal, URIRef, Namespace, BNode
|
||||
from bonsai.bim.module.brick.prop import BIMBrickProperties
|
||||
|
||||
# silence known rdflib_sqlalchemy TypeError warning
|
||||
# see https://github.com/BrickSchema/Brick/issues/513#issuecomment-1558493675
|
||||
import logging
|
||||
@@ -51,7 +58,11 @@ logger.setLevel(logging.ERROR)
|
||||
|
||||
class Brick(bonsai.core.tool.Brick):
|
||||
@classmethod
|
||||
def add_brick(cls, namespace, brick_class, label):
|
||||
def get_brick_props(cls) -> BIMBrickProperties:
|
||||
return bpy.context.scene.BIMBrickProperties
|
||||
|
||||
@classmethod
|
||||
def add_brick(cls, namespace: str, brick_class: str, label: str) -> str:
|
||||
ns = Namespace(namespace)
|
||||
brick = ns[ifcopenshell.guid.expand(ifcopenshell.guid.new())]
|
||||
with BrickStore.new_changeset() as cs:
|
||||
@@ -60,8 +71,8 @@ class Brick(bonsai.core.tool.Brick):
|
||||
return str(brick)
|
||||
|
||||
@classmethod
|
||||
def add_brick_breadcrumb(cls, split_screen=False):
|
||||
props = bpy.context.scene.BIMBrickProperties
|
||||
def add_brick_breadcrumb(cls, split_screen: bool = False) -> None:
|
||||
props = tool.Brick.get_brick_props()
|
||||
if split_screen:
|
||||
new = props.split_screen_brick_breadcrumbs.add()
|
||||
new.name = props.split_screen_active_brick_class
|
||||
@@ -70,7 +81,7 @@ class Brick(bonsai.core.tool.Brick):
|
||||
new.name = props.active_brick_class
|
||||
|
||||
@classmethod
|
||||
def add_brick_from_element(cls, element, namespace, brick_class):
|
||||
def add_brick_from_element(cls, element: ifcopenshell.entity_instance, namespace: str, brick_class: str) -> str:
|
||||
ns = Namespace(namespace)
|
||||
brick = ns[element.GlobalId]
|
||||
with BrickStore.new_changeset() as cs:
|
||||
@@ -82,7 +93,7 @@ class Brick(bonsai.core.tool.Brick):
|
||||
return str(brick)
|
||||
|
||||
@classmethod
|
||||
def add_brickifc_project(cls, namespace):
|
||||
def add_brickifc_project(cls, namespace: str) -> str:
|
||||
project = tool.Ifc.get().by_type("IfcProject")[0]
|
||||
ns = Namespace(namespace)
|
||||
brick_project = ns[project.GlobalId]
|
||||
@@ -96,7 +107,7 @@ class Brick(bonsai.core.tool.Brick):
|
||||
return str(brick_project)
|
||||
|
||||
@classmethod
|
||||
def add_brickifc_reference(cls, brick, element, project):
|
||||
def add_brickifc_reference(cls, brick: str, element: ifcopenshell.entity_instance, project: str) -> None:
|
||||
with BrickStore.new_changeset() as cs:
|
||||
bnode = BNode()
|
||||
cs.add((URIRef(brick), REF.hasExternalReference, bnode))
|
||||
@@ -107,23 +118,24 @@ class Brick(bonsai.core.tool.Brick):
|
||||
cs.add((bnode, REF.ifcName, Literal(element.Name)))
|
||||
|
||||
@classmethod
|
||||
def add_relation(cls, brick_uri, predicate, object):
|
||||
def add_relation(cls, brick_uri: str, predicate: str, object: str) -> None:
|
||||
props = tool.Brick.get_brick_props()
|
||||
if predicate == "http://www.w3.org/2000/01/rdf-schema#label":
|
||||
with BrickStore.new_changeset() as cs:
|
||||
cs.add((URIRef(brick_uri), URIRef(predicate), Literal(object)))
|
||||
bpy.context.scene.BIMBrickProperties.new_brick_relation_type = BrickStore.relationships[0]
|
||||
bpy.context.scene.BIMBrickProperties.add_brick_relation_failed = False
|
||||
props.new_brick_relation_type = BrickStore.relationships[0]
|
||||
props.add_brick_relation_failed = False
|
||||
return
|
||||
query = BrickStore.graph.query("ASK { <{object_uri}> a ?o . }".replace("{object_uri}", object))
|
||||
if query:
|
||||
with BrickStore.new_changeset() as cs:
|
||||
cs.add((URIRef(brick_uri), URIRef(predicate), URIRef(object)))
|
||||
bpy.context.scene.BIMBrickProperties.add_brick_relation_failed = False
|
||||
props.add_brick_relation_failed = False
|
||||
else:
|
||||
bpy.context.scene.BIMBrickProperties.add_brick_relation_failed = True
|
||||
props.add_brick_relation_failed = True
|
||||
|
||||
@classmethod
|
||||
def remove_relation(cls, brick_uri, predicate, object):
|
||||
def remove_relation(cls, brick_uri: str, predicate: str, object: str) -> None:
|
||||
with BrickStore.new_changeset() as cs:
|
||||
for s, p, o in BrickStore.graph.triples((brick_uri, predicate, object)):
|
||||
cs.remove((s, p, o))
|
||||
@@ -132,21 +144,22 @@ class Brick(bonsai.core.tool.Brick):
|
||||
cs.remove(triple)
|
||||
|
||||
@classmethod
|
||||
def clear_brick_browser(cls, split_screen=False):
|
||||
props = bpy.context.scene.BIMBrickProperties
|
||||
def clear_brick_browser(cls, split_screen: bool = False) -> None:
|
||||
props = cls.get_brick_props()
|
||||
if split_screen:
|
||||
props.split_screen_bricks.clear()
|
||||
else:
|
||||
props.bricks.clear()
|
||||
|
||||
@classmethod
|
||||
def clear_project(cls):
|
||||
def clear_project(cls) -> None:
|
||||
BrickStore.purge()
|
||||
bpy.context.scene.BIMBrickProperties.active_brick_class == ""
|
||||
bpy.context.scene.BIMBrickProperties.split_screen_active_brick_class == ""
|
||||
props = cls.get_brick_props()
|
||||
props.active_brick_class = ""
|
||||
props.split_screen_active_brick_class = ""
|
||||
|
||||
@classmethod
|
||||
def export_brick_attributes(cls, brick_uri):
|
||||
def export_brick_attributes(cls, brick_uri: str) -> dict[str, Any]:
|
||||
query = BrickStore.graph.query(
|
||||
"""
|
||||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
||||
@@ -169,13 +182,14 @@ class Brick(bonsai.core.tool.Brick):
|
||||
return {"Identification": brick_uri, "Name": name}
|
||||
|
||||
@classmethod
|
||||
def get_active_brick_class(cls, split_screen=False):
|
||||
def get_active_brick_class(cls, split_screen: bool = False) -> str:
|
||||
props = cls.get_brick_props()
|
||||
if split_screen:
|
||||
return bpy.context.scene.BIMBrickProperties.split_screen_active_brick_class
|
||||
return bpy.context.scene.BIMBrickProperties.active_brick_class
|
||||
return props.split_screen_active_brick_class
|
||||
return props.active_brick_class
|
||||
|
||||
@classmethod
|
||||
def get_brick(cls, element):
|
||||
def get_brick(cls, element: ifcopenshell.entity_instance) -> Union[str, None]:
|
||||
for rel in element.HasAssociations:
|
||||
if rel.is_a("IfcRelAssociatesLibrary"):
|
||||
if tool.Ifc.get_schema() == "IFC2X3" and "#" in rel.RelatingLibrary.ItemReference:
|
||||
@@ -184,21 +198,21 @@ class Brick(bonsai.core.tool.Brick):
|
||||
return rel.RelatingLibrary.Identification
|
||||
|
||||
@classmethod
|
||||
def get_brick_class(cls, element):
|
||||
def get_brick_class(cls, element: ifcopenshell.entity_instance) -> Union[str, None]:
|
||||
return ifcopenshell.util.brick.get_brick_type(element)
|
||||
|
||||
@classmethod
|
||||
def get_brick_path(cls):
|
||||
def get_brick_path(cls) -> Union[str, None]:
|
||||
return BrickStore.path
|
||||
|
||||
@classmethod
|
||||
def get_brick_path_name(cls):
|
||||
def get_brick_path_name(cls) -> str:
|
||||
if BrickStore.path:
|
||||
return os.path.basename(BrickStore.path)
|
||||
return "Unnamed"
|
||||
|
||||
@classmethod
|
||||
def get_brickifc_project(cls):
|
||||
def get_brickifc_project(cls) -> Union[str, None]:
|
||||
project = tool.Ifc.get().by_type("IfcProject")[0]
|
||||
query = BrickStore.graph.query(
|
||||
"""
|
||||
@@ -217,45 +231,46 @@ class Brick(bonsai.core.tool.Brick):
|
||||
return results[0][0].toPython()
|
||||
|
||||
@classmethod
|
||||
def get_convertable_brick_elements(cls):
|
||||
def get_convertable_brick_elements(cls) -> set[ifcopenshell.entity_instance]:
|
||||
equipment = set(tool.Ifc.get().by_type("IfcDistributionElement"))
|
||||
equipment -= set(tool.Ifc.get().by_type("IfcFlowSegment"))
|
||||
equipment -= set(tool.Ifc.get().by_type("IfcFlowFitting"))
|
||||
return equipment
|
||||
|
||||
@classmethod
|
||||
def get_convertable_brick_spaces(cls):
|
||||
def get_convertable_brick_spaces(cls) -> set[ifcopenshell.entity_instance]:
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
return set(tool.Ifc.get().by_type("IfcSpatialStructureElement"))
|
||||
return set(tool.Ifc.get().by_type("IfcSpatialElement"))
|
||||
|
||||
@classmethod
|
||||
def get_convertable_brick_systems(cls):
|
||||
def get_convertable_brick_systems(cls) -> set[ifcopenshell.entity_instance]:
|
||||
systems = set(tool.Ifc.get().by_type("IfcSystem"))
|
||||
systems -= set(tool.Ifc.get().by_type("IfcStructuralAnalysisModel"))
|
||||
systems -= set(tool.Ifc.get().by_type("IfcZone"))
|
||||
return systems
|
||||
|
||||
@classmethod
|
||||
def get_parent_space(cls, space):
|
||||
def get_parent_space(cls, space: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
|
||||
element = ifcopenshell.util.element.get_aggregate(space)
|
||||
assert element
|
||||
if not element.is_a("IfcProject"):
|
||||
return element
|
||||
|
||||
@classmethod
|
||||
def get_element_container(cls, element):
|
||||
def get_element_container(cls, element: ifcopenshell.entity_instance) -> Union[ifcopenshell.entity_instance, None]:
|
||||
return ifcopenshell.util.element.get_container(element)
|
||||
|
||||
@classmethod
|
||||
def get_element_systems(cls, element):
|
||||
def get_element_systems(cls, element: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
|
||||
return ifcopenshell.util.system.get_element_systems(element)
|
||||
|
||||
@classmethod
|
||||
def get_element_feeds(cls, element):
|
||||
def get_element_feeds(cls, element: ifcopenshell.entity_instance) -> set[ifcopenshell.entity_instance]:
|
||||
return ifcopenshell.util.brick.get_element_feeds(element)
|
||||
|
||||
@classmethod
|
||||
def get_item_class(cls, item):
|
||||
def get_item_class(cls, item: str) -> Union[str, None]:
|
||||
query = BrickStore.graph.query(
|
||||
"""
|
||||
PREFIX brick: <https://brickschema.org/schema/Brick#>
|
||||
@@ -271,7 +286,9 @@ class Brick(bonsai.core.tool.Brick):
|
||||
return row.get("class").toPython().split("#")[-1]
|
||||
|
||||
@classmethod
|
||||
def get_library_brick_reference(cls, library, brick_uri):
|
||||
def get_library_brick_reference(
|
||||
cls, library: ifcopenshell.entity_instance, brick_uri: str
|
||||
) -> Union[ifcopenshell.entity_instance, None]:
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
for reference in library.LibraryReference or []:
|
||||
if reference.ItemReference == brick_uri:
|
||||
@@ -282,11 +299,11 @@ class Brick(bonsai.core.tool.Brick):
|
||||
return reference
|
||||
|
||||
@classmethod
|
||||
def get_namespace(cls, uri):
|
||||
def get_namespace(cls, uri: str) -> str:
|
||||
return uri.split("#")[0] + "#"
|
||||
|
||||
@classmethod
|
||||
def import_brick_classes(cls, brick_class, split_screen=False):
|
||||
def import_brick_classes(cls, brick_class: str, split_screen: bool = False) -> None:
|
||||
query = BrickStore.graph.query(
|
||||
"""
|
||||
PREFIX brick: <https://brickschema.org/schema/Brick#>
|
||||
@@ -305,10 +322,11 @@ class Brick(bonsai.core.tool.Brick):
|
||||
"{brick_class}", brick_class
|
||||
)
|
||||
)
|
||||
props = tool.Brick.get_brick_props()
|
||||
if split_screen:
|
||||
bricks = bpy.context.scene.BIMBrickProperties.split_screen_bricks
|
||||
bricks = props.split_screen_bricks
|
||||
else:
|
||||
bricks = bpy.context.scene.BIMBrickProperties.bricks
|
||||
bricks = props.bricks
|
||||
for row in query:
|
||||
new = bricks.add()
|
||||
label = row.get("label")
|
||||
@@ -319,7 +337,7 @@ class Brick(bonsai.core.tool.Brick):
|
||||
new.total_items = row.get("total_items").toPython()
|
||||
|
||||
@classmethod
|
||||
def import_brick_items(cls, brick_class, split_screen=False):
|
||||
def import_brick_items(cls, brick_class: str, split_screen: bool = False) -> None:
|
||||
query = BrickStore.graph.query(
|
||||
"""
|
||||
PREFIX brick: <https://brickschema.org/schema/Brick#>
|
||||
@@ -336,10 +354,11 @@ class Brick(bonsai.core.tool.Brick):
|
||||
"{brick_class}", brick_class
|
||||
)
|
||||
)
|
||||
props = tool.Brick.get_brick_props()
|
||||
if split_screen:
|
||||
bricks = bpy.context.scene.BIMBrickProperties.split_screen_bricks
|
||||
bricks = props.split_screen_bricks
|
||||
else:
|
||||
bricks = bpy.context.scene.BIMBrickProperties.bricks
|
||||
bricks = props.bricks
|
||||
for row in query:
|
||||
new = bricks.add()
|
||||
label = row.get("label")
|
||||
@@ -349,7 +368,7 @@ class Brick(bonsai.core.tool.Brick):
|
||||
new.uri = row.get("item").toPython()
|
||||
|
||||
@classmethod
|
||||
def load_brick_file(cls, filepath):
|
||||
def load_brick_file(cls, filepath: str) -> None:
|
||||
if not BrickStore.schema: # important check for running under test cases
|
||||
BrickStore.schema = tool.Blender.get_data_dir_path(Path("brick", "Brick.ttl"))
|
||||
BrickStore.graph = brickschema.persistent.VersionedGraphCollection("sqlite://")
|
||||
@@ -365,7 +384,7 @@ class Brick(bonsai.core.tool.Brick):
|
||||
BrickStore.load_relationships()
|
||||
|
||||
@classmethod
|
||||
def new_brick_file(cls):
|
||||
def new_brick_file(cls) -> None:
|
||||
if not BrickStore.schema: # important check for running under test cases
|
||||
BrickStore.schema = tool.Blender.get_data_dir_path(Path("brick", "Brick.ttl"))
|
||||
BrickStore.graph = brickschema.persistent.VersionedGraphCollection("sqlite://")
|
||||
@@ -378,8 +397,8 @@ class Brick(bonsai.core.tool.Brick):
|
||||
BrickStore.load_relationships()
|
||||
|
||||
@classmethod
|
||||
def pop_brick_breadcrumb(cls, split_screen=False):
|
||||
props = bpy.context.scene.BIMBrickProperties
|
||||
def pop_brick_breadcrumb(cls, split_screen: bool = False) -> str:
|
||||
props = cls.get_brick_props()
|
||||
if split_screen:
|
||||
breadcrumbs = props.split_screen_brick_breadcrumbs
|
||||
else:
|
||||
@@ -391,7 +410,7 @@ class Brick(bonsai.core.tool.Brick):
|
||||
return name
|
||||
|
||||
@classmethod
|
||||
def remove_brick(cls, brick_uri):
|
||||
def remove_brick(cls, brick_uri: str) -> None:
|
||||
with BrickStore.new_changeset() as cs:
|
||||
for s, p, o in BrickStore.graph.triples((URIRef(brick_uri), None, None)):
|
||||
cs.remove((s, p, o))
|
||||
@@ -406,51 +425,55 @@ class Brick(bonsai.core.tool.Brick):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def run_refresh_brick_viewer(cls):
|
||||
def run_refresh_brick_viewer(cls) -> None:
|
||||
return bonsai.core.brick.refresh_brick_viewer(tool.Brick)
|
||||
|
||||
@classmethod
|
||||
def run_view_brick_class(cls, brick_class=None, split_screen=False):
|
||||
def run_view_brick_class(cls, brick_class: Union[str, None] = None, split_screen: bool = False) -> None:
|
||||
return bonsai.core.brick.view_brick_class(tool.Brick, brick_class=brick_class, split_screen=split_screen)
|
||||
|
||||
@classmethod
|
||||
def select_browser_item(cls, item, split_screen=False):
|
||||
def select_browser_item(cls, item: str, split_screen: bool = False) -> None:
|
||||
name = item.split("#")[-1]
|
||||
props = bpy.context.scene.BIMBrickProperties
|
||||
props = cls.get_brick_props()
|
||||
if split_screen:
|
||||
props.split_screen_active_brick_index = props.split_screen_bricks.find(name)
|
||||
else:
|
||||
props.active_brick_index = props.bricks.find(name)
|
||||
|
||||
@classmethod
|
||||
def set_active_brick_class(cls, brick_class, split_screen=False):
|
||||
props = bpy.context.scene.BIMBrickProperties
|
||||
def set_active_brick_class(cls, brick_class: str, split_screen: bool = False) -> None:
|
||||
props = cls.get_brick_props()
|
||||
if split_screen:
|
||||
props.split_screen_active_brick_class = brick_class
|
||||
else:
|
||||
props.active_brick_class = brick_class
|
||||
|
||||
@classmethod
|
||||
def serialize_brick(cls):
|
||||
def serialize_brick(cls) -> None:
|
||||
BrickStore.get_project().serialize(destination=BrickStore.path, format="turtle")
|
||||
BrickStore.set_last_saved()
|
||||
|
||||
@classmethod
|
||||
def add_namespace(cls, alias, uri):
|
||||
def add_namespace(cls, alias: str, uri: str) -> None:
|
||||
assert BrickStore.graph
|
||||
BrickStore.graph.bind(alias, Namespace(uri))
|
||||
BrickStore.load_namespaces()
|
||||
|
||||
@classmethod
|
||||
def clear_breadcrumbs(cls, split_screen=False):
|
||||
def clear_breadcrumbs(cls, split_screen: bool = False) -> None:
|
||||
props = cls.get_brick_props()
|
||||
if split_screen:
|
||||
bpy.context.scene.BIMBrickProperties.split_screen_brick_breadcrumbs.clear()
|
||||
props.split_screen_brick_breadcrumbs.clear()
|
||||
else:
|
||||
bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.clear()
|
||||
props.brick_breadcrumbs.clear()
|
||||
|
||||
|
||||
class BrickStore:
|
||||
schema = None # this is now a os path
|
||||
path: Union[str, None]
|
||||
path = None # file path if the project was loaded in
|
||||
graph: Union[brickschema.persistent.VersionedGraphCollection, None]
|
||||
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
|
||||
last_saved = None
|
||||
@@ -475,11 +498,11 @@ class BrickStore:
|
||||
BrickStore.relationships = []
|
||||
|
||||
@classmethod
|
||||
def get_project(cls):
|
||||
def get_project(cls) -> brickschema.graph.Graph:
|
||||
return BrickStore.graph.graph_at(graph="PROJECT")
|
||||
|
||||
@classmethod
|
||||
def load_sub_roots(cls):
|
||||
def load_sub_roots(cls) -> None:
|
||||
query = BrickStore.graph.query(
|
||||
"""
|
||||
PREFIX brick: <https://brickschema.org/schema/Brick#>
|
||||
@@ -505,7 +528,7 @@ class BrickStore:
|
||||
BrickStore.root_classes.append(sub_root)
|
||||
|
||||
@classmethod
|
||||
def load_namespaces(cls):
|
||||
def load_namespaces(cls) -> None:
|
||||
BrickStore.namespaces = []
|
||||
keyword_filter = [
|
||||
"brickschema.org",
|
||||
@@ -529,7 +552,7 @@ class BrickStore:
|
||||
BrickStore.namespaces.append((alias, str(uri)))
|
||||
|
||||
@classmethod
|
||||
def load_entity_classes(cls):
|
||||
def load_entity_classes(cls) -> None:
|
||||
for root_class in BrickStore.root_classes:
|
||||
query = BrickStore.graph.query(
|
||||
"""
|
||||
@@ -551,7 +574,7 @@ class BrickStore:
|
||||
BrickStore.entity_classes[root_class].append(uri)
|
||||
|
||||
@classmethod
|
||||
def load_relationships(cls):
|
||||
def load_relationships(cls) -> None:
|
||||
query = BrickStore.graph.query(
|
||||
"""
|
||||
PREFIX brick: <https://brickschema.org/schema/Brick#>
|
||||
@@ -565,30 +588,30 @@ class BrickStore:
|
||||
BrickStore.relationships.append(uri)
|
||||
|
||||
@classmethod
|
||||
def set_history_size(cls, size):
|
||||
def set_history_size(cls, size: int) -> None:
|
||||
cls.history_size = size
|
||||
while len(cls.history) > cls.history_size:
|
||||
cls.history.pop(0)
|
||||
|
||||
@classmethod
|
||||
def begin_transaction(cls):
|
||||
def begin_transaction(cls) -> None:
|
||||
cls.current_changesets = 0
|
||||
|
||||
@classmethod
|
||||
def end_transaction(cls):
|
||||
def end_transaction(cls) -> None:
|
||||
cls.history.append(cls.current_changesets)
|
||||
if len(cls.history) > cls.history_size:
|
||||
cls.history.pop(0)
|
||||
|
||||
@classmethod
|
||||
@contextmanager
|
||||
def new_changeset(cls):
|
||||
def new_changeset(cls) -> Generator[Any, None, None]:
|
||||
cls.current_changesets += 1
|
||||
with BrickStore.graph.new_changeset("PROJECT") as cs:
|
||||
yield cs
|
||||
|
||||
@classmethod
|
||||
def undo(cls):
|
||||
def undo(cls) -> None:
|
||||
if not BrickStore.graph or not BrickStore.history:
|
||||
return
|
||||
total_changesets = BrickStore.history.pop()
|
||||
@@ -597,7 +620,7 @@ class BrickStore:
|
||||
BrickStore.future.append(total_changesets)
|
||||
|
||||
@classmethod
|
||||
def redo(cls):
|
||||
def redo(cls) -> None:
|
||||
if not BrickStore.graph or not BrickStore.future:
|
||||
return
|
||||
total_changesets = BrickStore.future.pop()
|
||||
@@ -606,7 +629,7 @@ class BrickStore:
|
||||
BrickStore.history.append(total_changesets)
|
||||
|
||||
@classmethod
|
||||
def set_last_saved(cls):
|
||||
def set_last_saved(cls) -> None:
|
||||
save = os.path.getmtime(BrickStore.path)
|
||||
save = datetime.datetime.fromtimestamp(save)
|
||||
BrickStore.last_saved = f"{save.year}-{save.month}-{save.day} {save.hour}:{save.minute}"
|
||||
|
||||
@@ -59,16 +59,18 @@ 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"
|
||||
props = tool.Brick.get_brick_props()
|
||||
assert props.brick_breadcrumbs[0].name == "brick_class"
|
||||
subject.add_brick_breadcrumb()
|
||||
assert bpy.context.scene.BIMBrickProperties.brick_breadcrumbs[1].name == "brick_class"
|
||||
assert props.brick_breadcrumbs[1].name == "brick_class"
|
||||
|
||||
def test_run_split_screen(self):
|
||||
subject.set_active_brick_class("brick_class", split_screen=True)
|
||||
subject.add_brick_breadcrumb(split_screen=True)
|
||||
assert bpy.context.scene.BIMBrickProperties.split_screen_brick_breadcrumbs[0].name == "brick_class"
|
||||
props = tool.Brick.get_brick_props()
|
||||
assert props.split_screen_brick_breadcrumbs[0].name == "brick_class"
|
||||
subject.add_brick_breadcrumb(split_screen=True)
|
||||
assert bpy.context.scene.BIMBrickProperties.split_screen_brick_breadcrumbs[1].name == "brick_class"
|
||||
assert props.split_screen_brick_breadcrumbs[1].name == "brick_class"
|
||||
|
||||
|
||||
class TestAddBrickFromElement(NewFile):
|
||||
@@ -188,25 +190,28 @@ class TestRemoveRelation(NewFile):
|
||||
|
||||
class TestClearBrickBrowser(NewFile):
|
||||
def test_run(self):
|
||||
bpy.context.scene.BIMBrickProperties.bricks.add()
|
||||
props = tool.Brick.get_brick_props()
|
||||
props.bricks.add()
|
||||
subject.clear_brick_browser()
|
||||
assert len(bpy.context.scene.BIMBrickProperties.bricks) == 0
|
||||
assert len(props.bricks) == 0
|
||||
|
||||
def test_run_split_screen(self):
|
||||
bpy.context.scene.BIMBrickProperties.split_screen_bricks.add()
|
||||
props = tool.Brick.get_brick_props()
|
||||
props.split_screen_bricks.add()
|
||||
subject.clear_brick_browser(split_screen=True)
|
||||
assert len(bpy.context.scene.BIMBrickProperties.split_screen_bricks) == 0
|
||||
assert len(props.split_screen_bricks) == 0
|
||||
|
||||
|
||||
class TestClearProject(NewFile):
|
||||
def test_run(self):
|
||||
BrickStore.graph = "graph"
|
||||
bpy.context.scene.BIMBrickProperties.active_brick_class == "brick_class"
|
||||
bpy.context.scene.BIMBrickProperties.split_screen_active_brick_class == "brick_class2"
|
||||
props = tool.Brick.get_brick_props()
|
||||
props.active_brick_class = "brick_class"
|
||||
props.split_screen_active_brick_class = "brick_class2"
|
||||
subject.clear_project()
|
||||
assert BrickStore.graph is None
|
||||
assert bpy.context.scene.BIMBrickProperties.active_brick_class == ""
|
||||
assert bpy.context.scene.BIMBrickProperties.split_screen_active_brick_class == ""
|
||||
assert props.active_brick_class == ""
|
||||
assert props.split_screen_active_brick_class == ""
|
||||
|
||||
|
||||
class TestExportBrickAttributes(NewFile):
|
||||
@@ -374,13 +379,14 @@ class TestImportBrickClasses(NewFile):
|
||||
def test_run(self):
|
||||
TestLoadBrickFile().test_run()
|
||||
subject.import_brick_classes("Class")
|
||||
assert len(bpy.context.scene.BIMBrickProperties.bricks) == 2
|
||||
brick = bpy.context.scene.BIMBrickProperties.bricks[0]
|
||||
props = tool.Brick.get_brick_props()
|
||||
assert len(props.bricks) == 2
|
||||
brick = props.bricks[0]
|
||||
assert brick.name == "Building"
|
||||
assert brick.uri == "https://brickschema.org/schema/Brick#Building"
|
||||
assert brick.total_items == 1
|
||||
assert not brick.label
|
||||
brick = bpy.context.scene.BIMBrickProperties.bricks[1]
|
||||
brick = props.bricks[1]
|
||||
assert brick.name == "Location"
|
||||
assert brick.uri == "https://brickschema.org/schema/Brick#Location"
|
||||
assert brick.total_items == 1
|
||||
@@ -389,13 +395,14 @@ class TestImportBrickClasses(NewFile):
|
||||
def test_run_split_sccreen(self):
|
||||
TestLoadBrickFile().test_run()
|
||||
subject.import_brick_classes("Class", split_screen=True)
|
||||
assert len(bpy.context.scene.BIMBrickProperties.split_screen_bricks) == 2
|
||||
brick = bpy.context.scene.BIMBrickProperties.split_screen_bricks[0]
|
||||
props = tool.Brick.get_brick_props()
|
||||
assert len(props.split_screen_bricks) == 2
|
||||
brick = props.split_screen_bricks[0]
|
||||
assert brick.name == "Building"
|
||||
assert brick.uri == "https://brickschema.org/schema/Brick#Building"
|
||||
assert brick.total_items == 1
|
||||
assert not brick.label
|
||||
brick = bpy.context.scene.BIMBrickProperties.split_screen_bricks[1]
|
||||
brick = props.split_screen_bricks[1]
|
||||
assert brick.name == "Location"
|
||||
assert brick.uri == "https://brickschema.org/schema/Brick#Location"
|
||||
assert brick.total_items == 1
|
||||
@@ -406,8 +413,9 @@ class TestImportBrickItems(NewFile):
|
||||
def test_run(self):
|
||||
TestLoadBrickFile().test_run()
|
||||
subject.import_brick_items("Building")
|
||||
assert len(bpy.context.scene.BIMBrickProperties.bricks) == 1
|
||||
brick = bpy.context.scene.BIMBrickProperties.bricks[0]
|
||||
props = tool.Brick.get_brick_props()
|
||||
assert len(props.bricks) == 1
|
||||
brick = props.bricks[0]
|
||||
assert brick.name == "bldg"
|
||||
assert brick.label == "My Building"
|
||||
assert brick.uri == "https://example.org/digitaltwin#bldg"
|
||||
@@ -416,8 +424,9 @@ class TestImportBrickItems(NewFile):
|
||||
def test_run_split_screen(self):
|
||||
TestLoadBrickFile().test_run()
|
||||
subject.import_brick_items("Building", split_screen=True)
|
||||
assert len(bpy.context.scene.BIMBrickProperties.split_screen_bricks) == 1
|
||||
brick = bpy.context.scene.BIMBrickProperties.split_screen_bricks[0]
|
||||
props = tool.Brick.get_brick_props()
|
||||
assert len(props.split_screen_bricks) == 1
|
||||
brick = props.split_screen_bricks[0]
|
||||
assert brick.name == "bldg"
|
||||
assert brick.label == "My Building"
|
||||
assert brick.uri == "https://example.org/digitaltwin#bldg"
|
||||
@@ -456,18 +465,20 @@ class TestNewBrickFile(NewFile):
|
||||
|
||||
class TestPopBrickBreadcrumb(NewFile):
|
||||
def test_run(self):
|
||||
bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.add().name = "foo"
|
||||
bpy.context.scene.BIMBrickProperties.brick_breadcrumbs.add().name = "bar"
|
||||
props = tool.Brick.get_brick_props()
|
||||
props.brick_breadcrumbs.add().name = "foo"
|
||||
props.brick_breadcrumbs.add().name = "bar"
|
||||
assert subject.pop_brick_breadcrumb() == "bar"
|
||||
assert len(bpy.context.scene.BIMBrickProperties.brick_breadcrumbs) == 1
|
||||
assert bpy.context.scene.BIMBrickProperties.brick_breadcrumbs[0].name == "foo"
|
||||
assert len(props.brick_breadcrumbs) == 1
|
||||
assert props.brick_breadcrumbs[0].name == "foo"
|
||||
|
||||
def test_run_split_screen(self):
|
||||
bpy.context.scene.BIMBrickProperties.split_screen_brick_breadcrumbs.add().name = "foo"
|
||||
bpy.context.scene.BIMBrickProperties.split_screen_brick_breadcrumbs.add().name = "bar"
|
||||
props = tool.Brick.get_brick_props()
|
||||
props.split_screen_brick_breadcrumbs.add().name = "foo"
|
||||
props.split_screen_brick_breadcrumbs.add().name = "bar"
|
||||
assert subject.pop_brick_breadcrumb(split_screen=True) == "bar"
|
||||
assert len(bpy.context.scene.BIMBrickProperties.split_screen_brick_breadcrumbs) == 1
|
||||
assert bpy.context.scene.BIMBrickProperties.split_screen_brick_breadcrumbs[0].name == "foo"
|
||||
assert len(props.split_screen_brick_breadcrumbs) == 1
|
||||
assert props.split_screen_brick_breadcrumbs[0].name == "foo"
|
||||
|
||||
|
||||
class TestRemoveBrick(NewFile):
|
||||
@@ -512,19 +523,22 @@ class TestRunViewBrickClass(NewFile):
|
||||
class TestSelectBrowserItem(NewFile):
|
||||
def test_run(self):
|
||||
subject.set_active_brick_class("brick_class")
|
||||
assert bpy.context.scene.BIMBrickProperties.active_brick_class == "brick_class"
|
||||
props = tool.Brick.get_brick_props()
|
||||
assert props.active_brick_class == "brick_class"
|
||||
|
||||
def test_run(self):
|
||||
subject.set_active_brick_class("brick_class", split_screen=True)
|
||||
assert bpy.context.scene.BIMBrickProperties.split_screen_active_brick_class == "brick_class"
|
||||
props = tool.Brick.get_brick_props()
|
||||
assert props.split_screen_active_brick_class == "brick_class"
|
||||
|
||||
|
||||
class TestSetActiveBrickClass(NewFile):
|
||||
def test_run(self):
|
||||
bpy.context.scene.BIMBrickProperties.bricks.add().name = "foo"
|
||||
bpy.context.scene.BIMBrickProperties.bricks.add().name = "bar"
|
||||
props = tool.Brick.get_brick_props()
|
||||
props.bricks.add().name = "foo"
|
||||
props.bricks.add().name = "bar"
|
||||
subject.select_browser_item("namespace#bar")
|
||||
assert bpy.context.scene.BIMBrickProperties.active_brick_index == 1
|
||||
assert props.active_brick_index == 1
|
||||
|
||||
|
||||
class TestSerializeBrick(NewFile):
|
||||
|
||||
@@ -27,7 +27,7 @@ import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.type
|
||||
import ifcopenshell.util.schema
|
||||
import ifcopenshell.util.element
|
||||
from typing import Optional, Union, Literal, Any
|
||||
from typing import Optional, Union, Literal
|
||||
|
||||
|
||||
def reassign_class(
|
||||
@@ -56,7 +56,6 @@ def reassign_class(
|
||||
Reassigning type class to occurrence (and vice versa) is supported.
|
||||
|
||||
:param product: The IfcProduct that you want to change the class of.
|
||||
:type product: ifcopenshell.entity_instance
|
||||
:param ifc_class: The new IFC class you want to change it to.
|
||||
:param predefined_type: In case you want to change the predefined type
|
||||
too. User defined types are also allowed, just type what you want.
|
||||
@@ -77,25 +76,18 @@ def reassign_class(
|
||||
"""
|
||||
usecase = Usecase()
|
||||
usecase.file = file
|
||||
usecase.settings = {
|
||||
"product": product,
|
||||
"ifc_class": ifc_class,
|
||||
"predefined_type": predefined_type,
|
||||
}
|
||||
return usecase.execute()
|
||||
return usecase.execute(product, ifc_class, predefined_type)
|
||||
|
||||
|
||||
class Usecase:
|
||||
file: ifcopenshell.file
|
||||
settings: dict[str, Any]
|
||||
|
||||
def execute(self):
|
||||
ifc_class: str = self.settings["ifc_class"]
|
||||
product: ifcopenshell.entity_instance = self.settings["product"]
|
||||
predefined_type: Union[str, None] = self.settings["predefined_type"]
|
||||
|
||||
def execute(
|
||||
self, product: ifcopenshell.entity_instance, ifc_class: str, predefined_type: Union[str, None]
|
||||
) -> ifcopenshell.entity_instance:
|
||||
was_type_product_before = product.is_a("IfcTypeProduct")
|
||||
schema = ifcopenshell.schema_by_name(self.file.schema)
|
||||
is_type_product_after: bool
|
||||
is_type_product_after = schema.declaration_by_name(ifc_class)._is("IfcTypeProduct")
|
||||
|
||||
if was_type_product_before == is_type_product_after:
|
||||
|
||||
@@ -28,9 +28,7 @@ def unassign_type(file: ifcopenshell.file, related_objects: list[ifcopenshell.en
|
||||
and material usages associated with the previously assigned type.
|
||||
|
||||
:param related_objects: List of IfcElement occurrences.
|
||||
:type related_objects: list[ifcopenshell.entity_instance]
|
||||
:return: None
|
||||
:rtype: None
|
||||
|
||||
Example:
|
||||
|
||||
@@ -50,23 +48,21 @@ def unassign_type(file: ifcopenshell.file, related_objects: list[ifcopenshell.en
|
||||
# Change our mind. Maybe it's a different type?
|
||||
ifcopenshell.api.type.unassign_type(model, related_objects=[furniture])
|
||||
"""
|
||||
settings = {"related_objects": related_objects}
|
||||
|
||||
related_objects = set(settings["related_objects"])
|
||||
related_objects_set = set(related_objects)
|
||||
|
||||
if file.schema == "IFC2X3":
|
||||
rels = set(
|
||||
rel
|
||||
for object in related_objects
|
||||
for object in related_objects_set
|
||||
if (rel := next((rel for rel in object.IsDefinedBy if rel.is_a("IfcRelDefinesByType")), None))
|
||||
)
|
||||
else:
|
||||
rels = set(rel for object in related_objects if (rel := next((rel for rel in object.IsTypedBy), None)))
|
||||
rels = set(rel for object in related_objects_set if (rel := next((rel for rel in object.IsTypedBy), None)))
|
||||
|
||||
for rel in rels:
|
||||
related_objects = set(rel.RelatedObjects) - related_objects
|
||||
if related_objects:
|
||||
rel.RelatedObjects = list(related_objects)
|
||||
related_objects_set = set(rel.RelatedObjects) - related_objects_set
|
||||
if related_objects_set:
|
||||
rel.RelatedObjects = list(related_objects_set)
|
||||
ifcopenshell.api.owner.update_owner_history(file, **{"element": rel})
|
||||
else:
|
||||
history = rel.OwnerHistory
|
||||
|
||||
@@ -21,6 +21,7 @@ import json
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.classification
|
||||
from typing import Union
|
||||
|
||||
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
@@ -31,7 +32,7 @@ with open(os.path.join(cwd, "ifc4_to_brick.json")) as f:
|
||||
ifc4_to_brick_map = json.load(f)
|
||||
|
||||
|
||||
def get_brick_type(element):
|
||||
def get_brick_type(element: ifcopenshell.entity_instance) -> Union[str, None]:
|
||||
references = ifcopenshell.util.classification.get_references(element)
|
||||
for reference in references:
|
||||
system = ifcopenshell.util.classification.get_classification(reference)
|
||||
@@ -61,10 +62,10 @@ def get_brick_type(element):
|
||||
return f"https://brickschema.org/schema/Brick#System"
|
||||
|
||||
|
||||
def get_element_feeds(element):
|
||||
def get_element_feeds(element: ifcopenshell.entity_instance) -> set[ifcopenshell.entity_instance]:
|
||||
current_element = element
|
||||
processed_elements = set()
|
||||
downstream_equipment = set()
|
||||
downstream_equipment: set[ifcopenshell.entity_instance] = set()
|
||||
|
||||
# A queue is a list of branches. A branch is a list of elements in
|
||||
# sequence, each one connecting to another element. An element in a
|
||||
|
||||
Reference in New Issue
Block a user