diff --git a/src/bonsai/bonsai/bim/module/bcf/bcfstore.py b/src/bonsai/bonsai/bim/module/bcf/bcfstore.py
index b80e724be3..13be3faf1d 100644
--- a/src/bonsai/bonsai/bim/module/bcf/bcfstore.py
+++ b/src/bonsai/bonsai/bim/module/bcf/bcfstore.py
@@ -21,6 +21,7 @@ import bpy
import bcf
import bcf.bcfxml
import bcf.v2.bcfxml
+import bonsai.tool as tool
from typing import Union
@@ -30,7 +31,8 @@ class BcfStore:
@classmethod
def get_bcfxml(cls) -> Union[bcf.bcfxml.BcfXml, None]:
if not cls.bcfxml:
- bcf_filepath = bpy.context.scene.BCFProperties.bcf_file
+ props = tool.Bcf.get_bcf_props()
+ bcf_filepath = props.bcf_file
if not os.path.isabs(bcf_filepath):
bcf_filepath = os.path.abspath(os.path.join(bpy.path.abspath("//"), bcf_filepath))
if bcf_filepath:
@@ -46,7 +48,7 @@ class BcfStore:
@classmethod
def set(cls, bcfxml: Union[bcf.bcfxml.BcfXml, None], filepath: str) -> None:
cls.bcfxml = bcfxml
- props = bpy.context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
props.bcf_file = filepath
# Set bcf_version prop on load.
diff --git a/src/bonsai/bonsai/bim/module/bcf/operator.py b/src/bonsai/bonsai/bim/module/bcf/operator.py
index 0295d2cdde..bfcc40b8a9 100644
--- a/src/bonsai/bonsai/bim/module/bcf/operator.py
+++ b/src/bonsai/bonsai/bim/module/bcf/operator.py
@@ -55,7 +55,7 @@ class NewBcfProject(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
bcf_v2 = props.bcf_version == "2"
bcf_class = bcf.v2.bcfxml.BcfXml if bcf_v2 else bcf.v3.bcfxml.BcfXml
bcfxml = bcf_class.create_new("New Project")
@@ -103,7 +103,8 @@ class LoadBcfProject(bpy.types.Operator):
assert bcfxml.project
if bcfxml.project.name is None:
bcfxml.project.name = nameless
- context.scene.BCFProperties.name = bcfxml.project.name
+ props = tool.Bcf.get_bcf_props()
+ props.name = bcfxml.project.name
bpy.ops.bim.load_bcf_topics()
self.report({"INFO"}, f"BCF Project '{Path(self.filepath).name}' is loaded.")
return {"FINISHED"}
@@ -131,7 +132,7 @@ class LoadBcfTopics(bpy.types.Operator):
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
props.topics.clear()
# workaround, one non standard topic would break reading entire bcf
# ignored these topics ATM
@@ -163,7 +164,8 @@ class LoadBcfTopic(bpy.types.Operator):
assert bcfxml
topic = bcfxml.topics[self.topic_guid]
bcfxml.get_header(self.topic_guid)
- new = context.scene.BCFProperties.topics[self.topic_index]
+ props = tool.Bcf.get_bcf_props()
+ new = props.topics[self.topic_index]
data_map = {
"name": topic.guid,
"title": topic.topic.title,
@@ -244,7 +246,8 @@ class LoadBcfComments(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- blender_topic = context.scene.BCFProperties.topics.get(self.topic_guid)
+ props = tool.Bcf.get_bcf_props()
+ blender_topic = props.topics.get(self.topic_guid)
blender_topic.comments.clear()
for comment in bcfxml.topics[self.topic_guid].comments:
new = blender_topic.comments.add()
@@ -274,7 +277,9 @@ class EditBcfProjectName(bpy.types.Operator):
# Bonsai creates default project on load.
assert bcfxml.project
- bcfxml.project.name = context.scene.BCFProperties.name
+
+ props = tool.Bcf.get_bcf_props()
+ bcfxml.project.name = props.name
return {"FINISHED"}
@@ -284,7 +289,7 @@ class EditBcfTopicName(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
@@ -300,7 +305,7 @@ class EditBcfTopic(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
@@ -371,13 +376,15 @@ class AddBcfTopic(bpy.types.Operator):
@classmethod
def poll(cls, context):
- return context.scene.BCFProperties.author
+ props = tool.Bcf.get_bcf_props()
+ return props.author
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- bcfxml.add_topic("New Topic", "", context.scene.BCFProperties.author)
+ props = tool.Bcf.get_bcf_props()
+ bcfxml.add_topic("New Topic", "", props.author)
bpy.ops.bim.load_bcf_topics()
return {"FINISHED"}
@@ -389,7 +396,7 @@ class AddBcfBimSnippet(bpy.types.Operator):
@classmethod
def poll(cls, context):
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
props_are_filled = all(
(getattr(props, attr) for attr in ("bim_snippet_reference", "bim_snippet_schema", "bim_snippet_type"))
)
@@ -403,7 +410,7 @@ class AddBcfBimSnippet(bpy.types.Operator):
assert bcfxml
bcf_v2 = (bcfxml.version.version_id or "").startswith("2")
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
is_external = "://" in props.bim_snippet_reference
@@ -435,7 +442,7 @@ class AddBcfRelatedTopic(bpy.types.Operator):
assert bcfxml
bcf_v2 = (bcfxml.version.version_id or "").startswith("2")
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
related_topics = tool.Bcf.get_topic_related_topics(topic)
@@ -462,14 +469,15 @@ class AddBcfHeaderFile(bpy.types.Operator):
@classmethod
def poll(cls, context):
- return context.scene.BCFProperties.file_reference
+ props = tool.Bcf.get_bcf_props()
+ return props.file_reference
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
bcf_v2 = (bcfxml.version.version_id or "").startswith("2")
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
@@ -519,9 +527,10 @@ class ViewBcfTopic(bpy.types.Operator):
topic_guid: bpy.props.StringProperty()
def execute(self, context):
- for index, topic in enumerate(context.scene.BCFProperties.topics):
+ props = tool.Bcf.get_bcf_props()
+ for index, topic in enumerate(props.topics):
if topic.name.lower() == self.topic_guid.lower():
- context.scene.BCFProperties.active_topic_index = index
+ props.active_topic_index = index
break
return {"FINISHED"}
@@ -546,7 +555,7 @@ class AddBcfViewpoint(bpy.types.Operator):
blender_camera = context.scene.camera
assert blender_camera
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
@@ -675,7 +684,7 @@ class RemoveBcfViewpoint(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
if not bcfxml:
return False
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
topic = props.active_topic
if not topic:
return False
@@ -690,7 +699,7 @@ class RemoveBcfViewpoint(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
del topic.viewpoints[blender_topic.viewpoints]
@@ -715,7 +724,7 @@ class RemoveBcfFile(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
header_files = tool.Bcf.get_topic_header_files(topic)
@@ -733,13 +742,14 @@ class RemoveBcfTopic(bpy.types.Operator):
@classmethod
def poll(cls, context):
- return context.scene.BCFProperties.topics
+ props = tool.Bcf.get_bcf_props()
+ return props.topics
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
del bcfxml.topics[props.active_topic.name]
bpy.ops.bim.load_bcf_topics()
return {"FINISHED"}
@@ -752,13 +762,14 @@ class AddBcfReferenceLink(bpy.types.Operator):
@classmethod
def poll(cls, context):
- return context.scene.BCFProperties.reference_link
+ props = tool.Bcf.get_bcf_props()
+ return bool(props.reference_link)
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
reference_links = tool.Bcf.get_topic_reference_links(topic)
@@ -776,14 +787,15 @@ class AddBcfDocumentReference(bpy.types.Operator):
@classmethod
def poll(cls, context):
- return context.scene.BCFProperties.document_reference
+ props = tool.Bcf.get_bcf_props()
+ return bool(props.document_reference)
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
bcf_v2 = (bcfxml.version.version_id or "").startswith("2")
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
@@ -855,13 +867,14 @@ class AddBcfLabel(bpy.types.Operator):
@classmethod
def poll(cls, context):
- return context.scene.BCFProperties.label
+ props = tool.Bcf.get_bcf_props()
+ return bool(props.label)
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
new = blender_topic.labels.add()
@@ -883,7 +896,7 @@ class EditBcfReferenceLinks(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
reference_links = [r.name for r in blender_topic.reference_links]
@@ -900,7 +913,7 @@ class EditBcfLabels(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
labels = [l.name for l in blender_topic.labels]
@@ -918,7 +931,7 @@ class RemoveBcfReferenceLink(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
reference_links = tool.Bcf.get_topic_reference_links(topic)
@@ -938,7 +951,7 @@ class RemoveBcfLabel(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
labels = tool.Bcf.get_topic_labels(topic)
@@ -957,7 +970,7 @@ class RemoveBcfBimSnippet(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
tool.Bcf.set_topic_bim_snippet(topic, None)
@@ -978,7 +991,7 @@ class RemoveBcfDocumentReference(bpy.types.Operator):
assert bcfxml
bcf_v2 = (bcfxml.version.version_id or "").startswith("2")
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
@@ -1043,7 +1056,7 @@ class RemoveBcfRelatedTopic(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
related_topics = tool.Bcf.get_topic_related_topics(topic)
@@ -1063,7 +1076,7 @@ class RemoveBcfComment(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
comments = topic.comments
@@ -1084,7 +1097,7 @@ class EditBcfComment(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
blender_comment = blender_topic.comments.get(self.comment_guid)
topic = bcfxml.topics[blender_topic.name]
@@ -1092,7 +1105,7 @@ class EditBcfComment(bpy.types.Operator):
if comment.guid == self.comment_guid:
comment.comment = blender_comment.comment
comment.modified_date = XmlDateTime.now()
- comment.modified_author = context.scene.BCFProperties.author
+ comment.modified_author = props.author
bpy.ops.bim.load_bcf_comments(topic_guid=topic.guid)
return {"FINISHED"}
@@ -1105,7 +1118,7 @@ class AddBcfComment(bpy.types.Operator):
@classmethod
def poll(cls, context):
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
if not props.comment:
cls.poll_message_set("No comment to add.")
return False
@@ -1128,7 +1141,7 @@ class AddBcfComment(bpy.types.Operator):
assert bcfxml
bcf_v2 = (bcfxml.version.version_id or "").startswith("2")
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
comments = topic.comments
@@ -1136,7 +1149,7 @@ class AddBcfComment(bpy.types.Operator):
if bcf_v2:
comment = bcf.v2.model.Comment(
date=XmlDateTime.now(),
- author=context.scene.BCFProperties.author,
+ author=props.author,
comment=props.comment,
guid=str(uuid.uuid4()),
)
@@ -1149,7 +1162,7 @@ class AddBcfComment(bpy.types.Operator):
else:
comment = bcf.v3.model.Comment(
date=XmlDateTime.now(),
- author=context.scene.BCFProperties.author,
+ author=props.author,
comment=props.comment,
guid=str(uuid.uuid4()),
)
@@ -1179,7 +1192,7 @@ class ActivateBcfViewpoint(bpy.types.Operator):
@classmethod
def poll(cls, context):
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
if blender_topic is None:
cls.poll_message_set("No topic is active.")
@@ -1197,7 +1210,7 @@ class ActivateBcfViewpoint(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
if self.viewpoint_guid:
@@ -1517,7 +1530,8 @@ class OpenBcfReferenceLink(bpy.types.Operator):
index: bpy.props.IntProperty()
def execute(self, context):
- webbrowser.open(context.scene.BCFProperties.topic_links[self.index].name)
+ props = tool.Bcf.get_bcf_props()
+ webbrowser.open(props.topic_links[self.index].name)
return {"FINISHED"}
@@ -1530,7 +1544,8 @@ class SelectBcfHeaderFile(bpy.types.Operator):
def execute(self, context):
if self.filepath:
- context.scene.BCFProperties.file_reference = self.filepath
+ props = tool.Bcf.get_bcf_props()
+ props.file_reference = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
@@ -1546,7 +1561,8 @@ class SelectBcfBimSnippetReference(bpy.types.Operator):
def execute(self, context):
if self.filepath:
- context.scene.BCFProperties.bim_snippet_reference = self.filepath
+ props = tool.Bcf.get_bcf_props()
+ props.bim_snippet_reference = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
@@ -1562,7 +1578,8 @@ class SelectBcfDocumentReference(bpy.types.Operator):
def execute(self, context):
if self.filepath:
- context.scene.BCFProperties.document_reference = self.filepath
+ props = tool.Bcf.get_bcf_props()
+ props.document_reference = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
@@ -1585,7 +1602,8 @@ class LoadBcfHeaderIfcFile(bpy.types.Operator):
assert bcfxml
bcf_path = tool.Bcf.get_path()
- topic = bcfxml.topics[context.scene.BCFProperties.active_topic.name]
+ props = tool.Bcf.get_bcf_props()
+ topic = bcfxml.topics[props.active_topic.name]
entity = tool.Bcf.get_topic_header_files(topic)[self.index]
ifc_path = bcf.agnostic.topic.extract_file(topic, entity)
bpy.ops.bim.load_project(filepath=ifc_path)
@@ -1605,7 +1623,8 @@ class ExtractBcfFile(bpy.types.Operator):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
- topic = bcfxml.topics[context.scene.BCFProperties.active_topic.name]
+ props = tool.Bcf.get_bcf_props()
+ topic = bcfxml.topics[props.active_topic.name]
if self.entity_type == "HEADER_FILE":
entity = tool.Bcf.get_topic_header_files(topic)[self.index]
diff --git a/src/bonsai/bonsai/bim/module/bcf/prop.py b/src/bonsai/bonsai/bim/module/bcf/prop.py
index ef681ace10..17a15597a7 100644
--- a/src/bonsai/bonsai/bim/module/bcf/prop.py
+++ b/src/bonsai/bonsai/bim/module/bcf/prop.py
@@ -17,6 +17,7 @@
# along with Bonsai. If not, see .
import bpy
+import bonsai.tool as tool
from . import bcfstore
from bonsai.bim.prop import StrProperty
from bpy.types import PropertyGroup
@@ -34,6 +35,7 @@ from functools import partial
from typing import Literal
from typing_extensions import assert_never
from bcf.agnostic.extensions import get_extensions_attributes
+from typing import TYPE_CHECKING, Union
bcfviewpoints_enum = None
@@ -95,7 +97,7 @@ def getBcfViewpoints(self, context, force_update=False):
global bcfviewpoints_enum
if bcfviewpoints_enum is None or force_update: # Retrieving Viewpoints is slow. Make sure we only do when needed
bcfviewpoints_enum = []
- props = context.scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
topic = props.active_topic
@@ -110,6 +112,12 @@ class BcfBimSnippet(PropertyGroup):
type: StringProperty(name="Type")
is_external: BoolProperty(name="Is External")
+ if TYPE_CHECKING:
+ schema: str
+ reference: str
+ type: str
+ is_external: bool
+
class BcfDocumentReference(PropertyGroup):
reference: StringProperty(name="Reference")
@@ -117,6 +125,12 @@ class BcfDocumentReference(PropertyGroup):
guid: StringProperty(name="GUID")
is_external: BoolProperty(name="Is External")
+ if TYPE_CHECKING:
+ reference: str
+ description: str
+ guid: str
+ is_external: bool
+
class BcfComment(PropertyGroup):
name: StringProperty(name="GUID")
@@ -128,6 +142,16 @@ class BcfComment(PropertyGroup):
modified_author: StringProperty(name="Modified Author")
is_editable: BoolProperty(name="Is Editable", default=False, update=updateBcfCommentIsEditable)
+ if TYPE_CHECKING:
+ name: str
+ date: str
+ author: str
+ comment: str
+ viewpoint: str
+ modified_date: str
+ modified_author: str
+ is_editable: bool
+
def get_extensions_items(
self: "BCFProperties", context: bpy.types.Context, edit_text: str, extensions_attr: str
@@ -183,6 +207,30 @@ class BcfTopic(PropertyGroup):
comments: CollectionProperty(name="Comments", type=BcfComment)
is_editable: BoolProperty(name="Edit Topic Attributes", default=False, update=updateBcfTopicIsEditable)
+ if TYPE_CHECKING:
+ name: str
+ title: str
+ type: str
+ status: str
+ priority: str
+ stage: str
+ creation_date: str
+ creation_author: str
+ modified_date: str
+ modified_author: str
+ assigned_to: str
+ due_date: str
+ description: str
+ viewpoints: str
+ files: bpy.types.bpy_prop_collection_idprop[StrProperty]
+ reference_links: bpy.types.bpy_prop_collection_idprop[BcfReferenceLink]
+ labels: bpy.types.bpy_prop_collection_idprop[BcfLabel]
+ bim_snippet: BcfBimSnippet
+ document_references: bpy.types.bpy_prop_collection_idprop[BcfDocumentReference]
+ related_topics: bpy.types.bpy_prop_collection_idprop[StrProperty]
+ comments: bpy.types.bpy_prop_collection_idprop[BcfComment]
+ is_editable: bool
+
def get_related_topics(self: "BCFProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
global RELATED_TOPICS_ENUM_ITEMS
@@ -235,7 +283,30 @@ class BCFProperties(PropertyGroup):
comment: StringProperty(default="", name="Comment")
has_related_viewpoint: BoolProperty(name="Has Related Viewpoint", default=False)
- def clear_input_fields(self):
+ if TYPE_CHECKING:
+ bcf_file: str
+ bcf_version: str
+ comment_text_width: int
+ name: str
+ author: str
+ topics: bpy.types.bpy_prop_collection_idprop[BcfTopic]
+ active_topic_index: int
+ file_reference: str
+ file_ifc_project: str
+ file_ifc_spatial_structure_element: str
+ reference_link: str
+ label: str
+ bim_snippet_reference: str
+ bim_snippet_type: str
+ bim_snippet_schema: str
+ document_reference: str
+ document_reference_description: str
+ document_description: str
+ related_topic: str
+ comment: str
+ has_related_viewpoint: bool
+
+ def clear_input_fields(self) -> None:
self.file_reference = ""
self.file_ifc_project = ""
self.file_ifc_spatial_structure_element = ""
@@ -250,7 +321,7 @@ class BCFProperties(PropertyGroup):
self.has_related_viewpoint = False
@property
- def active_topic(self):
+ def active_topic(self) -> Union[BcfTopic, None]:
if len(self.topics) == 0:
return None
if self.active_topic_index < 0:
@@ -259,5 +330,5 @@ class BCFProperties(PropertyGroup):
self.active_topic_index = len(self.topics) - 1
return self.topics[self.active_topic_index]
- def refresh_topic(self, context):
+ def refresh_topic(self, context: bpy.types.Context) -> None:
refreshBcfTopic(self, context)
diff --git a/src/bonsai/bonsai/bim/module/bcf/ui.py b/src/bonsai/bonsai/bim/module/bcf/ui.py
index 5efa118a8c..83c80557f8 100644
--- a/src/bonsai/bonsai/bim/module/bcf/ui.py
+++ b/src/bonsai/bonsai/bim/module/bcf/ui.py
@@ -37,8 +37,7 @@ class BIM_PT_bcf(Panel):
layout.use_property_split = True
layout.use_property_decorate = False
- scene = context.scene
- props = scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
if not bcfstore.BcfStore.get_bcfxml():
row = layout.row(align=True)
@@ -63,18 +62,17 @@ class BIM_PT_bcf(Panel):
row = layout.row()
row.prop(props, "author")
- props = context.scene.BCFProperties
row = layout.row()
row.template_list("BIM_UL_topics", "", props, "topics", props, "active_topic_index")
col = row.column(align=True)
col.operator("bim.add_bcf_topic", icon="ADD", text="")
col.operator("bim.remove_bcf_topic", icon="REMOVE", text="")
- if props.active_topic_index < len(props.topics):
- topic = props.active_topic
+
+ topic = props.active_topic
+ if topic is not None:
is_editable = topic.is_editable
col.prop(topic, "is_editable", icon="CHECKMARK" if topic.is_editable else "GREASEPENCIL", icon_only=True)
- topic = props.active_topic
row = layout.row()
row.enabled = is_editable
row.prop(topic, "description", text="")
@@ -131,8 +129,7 @@ class BIM_PT_bcf_metadata(Panel):
layout.use_property_split = True
layout.use_property_decorate = False
- scene = context.scene
- props = scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
bcfxml = bcfstore.BcfStore.get_bcfxml()
if not bcfxml or props.active_topic_index >= len(props.topics):
@@ -296,8 +293,7 @@ class BIM_PT_bcf_comments(Panel):
layout.use_property_split = True
layout.use_property_decorate = False
- scene = context.scene
- props = scene.BCFProperties
+ props = tool.Bcf.get_bcf_props()
if props.active_topic_index >= len(props.topics):
layout.label(text="No BCF project is loaded")
diff --git a/src/bonsai/bonsai/bim/module/classification/data.py b/src/bonsai/bonsai/bim/module/classification/data.py
index 1dff8c3875..e4c5e30ca8 100644
--- a/src/bonsai/bonsai/bim/module/classification/data.py
+++ b/src/bonsai/bonsai/bim/module/classification/data.py
@@ -118,7 +118,7 @@ class MaterialClassificationsData(ReferencesData):
def references(cls):
results = []
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
if props.materials and props.active_material_index < len(props.materials):
material = props.materials[props.active_material_index]
if material.ifc_definition_id:
diff --git a/src/bonsai/bonsai/bim/module/classification/ui.py b/src/bonsai/bonsai/bim/module/classification/ui.py
index fcef0ad4bd..87257fbaaa 100644
--- a/src/bonsai/bonsai/bim/module/classification/ui.py
+++ b/src/bonsai/bonsai/bim/module/classification/ui.py
@@ -312,7 +312,7 @@ class BIM_PT_material_classifications(Panel, ReferenceUI):
def poll(cls, context):
if not tool.Ifc.get():
return False
- props = context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
if props.is_editing and (material := props.active_material) and material.ifc_definition_id:
return True
return False
diff --git a/src/bonsai/bonsai/bim/module/debug/operator.py b/src/bonsai/bonsai/bim/module/debug/operator.py
index 0058c70a3a..33100956ef 100644
--- a/src/bonsai/bonsai/bim/module/debug/operator.py
+++ b/src/bonsai/bonsai/bim/module/debug/operator.py
@@ -689,13 +689,15 @@ class PurgeUnusedObjects(bpy.types.Operator, tool.Ifc.Operator):
scene = context.scene
if object_type == "PROFILE":
- if scene.BIMProfileProperties.is_editing:
+ props = tool.Profile.get_profile_props()
+ if props.is_editing:
bpy.ops.bim.load_profiles()
elif object_type == "STYLE":
if scene.BIMStylesProperties.is_editing:
bpy.ops.bim.load_styles()
elif object_type == "MATERIAL":
- if scene.BIMMaterialProperties.is_editing:
+ props = tool.Material.get_material_props()
+ if props.is_editing:
bpy.ops.bim.load_materials()
@@ -737,13 +739,15 @@ class MergeIdenticalObjects(bpy.types.Operator, tool.Ifc.Operator):
scene = context.scene
if object_type == "PROFILE":
- if scene.BIMProfileProperties.is_editing:
+ props = tool.Profile.get_profile_props()
+ if props.is_editing:
bpy.ops.bim.load_profiles()
elif object_type == "STYLE":
if scene.BIMStylesProperties.is_editing:
bpy.ops.bim.load_styles()
elif object_type == "MATERIAL":
- if scene.BIMMaterialProperties.is_editing:
+ props = tool.Material.get_material_props()
+ if props.is_editing:
bpy.ops.bim.load_materials()
diff --git a/src/bonsai/bonsai/bim/module/geometry/operator.py b/src/bonsai/bonsai/bim/module/geometry/operator.py
index 5451c611f4..de59b7a61c 100644
--- a/src/bonsai/bonsai/bim/module/geometry/operator.py
+++ b/src/bonsai/bonsai/bim/module/geometry/operator.py
@@ -2136,7 +2136,8 @@ class OverrideModeSetObject(bpy.types.Operator, tool.Ifc.Operator):
continue
if tool.Profile.is_editing_profile():
- profile_id = context.scene.BIMProfileProperties.active_profile_id
+ props = tool.Profile.get_profile_props()
+ profile_id = props.active_profile_id
if profile_id:
profile = tool.Ifc.get().by_id(profile_id)
if tool.Ifc.get_object(profile): # We are editing an arbitrary profile
@@ -2148,7 +2149,7 @@ class OverrideModeSetObject(bpy.types.Operator, tool.Ifc.Operator):
elif tool.Model.get_usage_type(element) == "PROFILE":
bpy.ops.bim.edit_extrusion_axis()
# if in the process of editing arbitrary profile
- elif context.scene.BIMProfileProperties.active_arbitrary_profile_id:
+ elif props.active_arbitrary_profile_id:
bpy.ops.bim.edit_arbitrary_profile()
else:
bpy.ops.bim.edit_extrusion_profile()
diff --git a/src/bonsai/bonsai/bim/module/library/data.py b/src/bonsai/bonsai/bim/module/library/data.py
index 145dfbc83a..87ad7c23ae 100644
--- a/src/bonsai/bonsai/bim/module/library/data.py
+++ b/src/bonsai/bonsai/bim/module/library/data.py
@@ -47,7 +47,8 @@ class LibrariesData:
@classmethod
def library_attributes(cls):
- library_id = bpy.context.scene.BIMLibraryProperties.active_library_id
+ props = tool.Library.get_library_props()
+ library_id = props.active_library_id
if not library_id:
return []
results = []
@@ -63,7 +64,7 @@ class LibrariesData:
@classmethod
def reference_attributes(cls):
- props = bpy.context.scene.BIMLibraryProperties
+ props = tool.Library.get_library_props()
try:
reference_id = props.references[props.active_reference_index].ifc_definition_id
except:
diff --git a/src/bonsai/bonsai/bim/module/library/prop.py b/src/bonsai/bonsai/bim/module/library/prop.py
index b7ddb74ed6..896bf0da2e 100644
--- a/src/bonsai/bonsai/bim/module/library/prop.py
+++ b/src/bonsai/bonsai/bim/module/library/prop.py
@@ -30,6 +30,7 @@ from bpy.props import (
FloatVectorProperty,
CollectionProperty,
)
+from typing import TYPE_CHECKING, Literal
def update_active_reference_index(self, context):
@@ -40,6 +41,10 @@ class LibraryReference(PropertyGroup):
name: StringProperty(name="Name")
ifc_definition_id: IntProperty(name="IFC Definition ID")
+ if TYPE_CHECKING:
+ name: str
+ ifc_definition_id: int
+
class BIMLibraryProperties(PropertyGroup):
editing_mode: EnumProperty(
@@ -58,3 +63,12 @@ class BIMLibraryProperties(PropertyGroup):
active_reference_id: IntProperty(name="Active Reference Id")
references: CollectionProperty(type=LibraryReference, name="References")
active_reference_index: IntProperty(name="Active Reference Index", update=update_active_reference_index)
+
+ if TYPE_CHECKING:
+ editing_mode: Literal["NONE", "LIBRARY", "REFERENCES", "REFERENCE"]
+ library_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
+ active_library_id: int
+ reference_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
+ active_reference_id: int
+ references: bpy.types.bpy_prop_collection_idprop[LibraryReference]
+ active_reference_index: int
diff --git a/src/bonsai/bonsai/bim/module/library/ui.py b/src/bonsai/bonsai/bim/module/library/ui.py
index 79797b9f54..1c9f389a7e 100644
--- a/src/bonsai/bonsai/bim/module/library/ui.py
+++ b/src/bonsai/bonsai/bim/module/library/ui.py
@@ -16,10 +16,16 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see .
+from __future__ import annotations
+import bpy
import bonsai.bim.helper
import bonsai.tool as tool
from bpy.types import Panel, UIList
from bonsai.bim.module.library.data import LibrariesData, LibraryReferencesData
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from bonsai.bim.module.library.prop import BIMLibraryProperties, LibraryReference
class BIM_PT_libraries(Panel):
@@ -38,7 +44,7 @@ class BIM_PT_libraries(Panel):
def draw(self, context):
if not LibrariesData.is_loaded:
LibrariesData.load()
- self.props = context.scene.BIMLibraryProperties
+ self.props = tool.Library.get_library_props()
if self.props.editing_mode == "LIBRARY":
self.draw_editable_library_ui()
@@ -110,7 +116,7 @@ class BIM_PT_library_references(Panel):
def draw(self, context):
if not LibraryReferencesData.is_loaded:
LibraryReferencesData.load()
- self.props = context.scene.BIMLibraryProperties
+ self.props = tool.Library.get_library_props()
if self.props.editing_mode == "REFERENCES":
self.layout.template_list(
@@ -129,7 +135,9 @@ class BIM_PT_library_references(Panel):
class BIM_UL_library_references(UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
+ def draw_item(
+ self, context, layout: bpy.types.UILayout, data, item: LibraryReference, icon, active_data, active_propname
+ ):
if item:
row = layout.row(align=True)
row.label(text=item.name)
@@ -140,7 +148,9 @@ class BIM_UL_library_references(UIList):
class BIM_UL_object_library_references(UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
+ def draw_item(
+ self, context, layout: bpy.types.UILayout, data, item: LibraryReference, icon, active_data, active_propname
+ ):
if item:
row = layout.row(align=True)
row.label(text=item.name)
diff --git a/src/bonsai/bonsai/bim/module/material/data.py b/src/bonsai/bonsai/bim/module/material/data.py
index 95e68468c6..50a03603df 100644
--- a/src/bonsai/bonsai/bim/module/material/data.py
+++ b/src/bonsai/bonsai/bim/module/material/data.py
@@ -48,7 +48,8 @@ class MaterialsData:
@classmethod
def total_materials(cls):
- return len(tool.Ifc.get().by_type(bpy.context.scene.BIMMaterialProperties.material_type))
+ props = tool.Material.get_material_props()
+ return len(tool.Ifc.get().by_type(props.material_type))
@classmethod
def material_types(cls):
@@ -101,7 +102,7 @@ class MaterialsData:
@classmethod
def material_styles_data(cls) -> dict[int, list[dict[str, Any]]]:
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
material_styles_data: dict[int, list[dict[str, Any]]] = {}
for material_item in props.materials:
diff --git a/src/bonsai/bonsai/bim/module/material/operator.py b/src/bonsai/bonsai/bim/module/material/operator.py
index c6b92145b5..820ac5359e 100644
--- a/src/bonsai/bonsai/bim/module/material/operator.py
+++ b/src/bonsai/bonsai/bim/module/material/operator.py
@@ -19,6 +19,7 @@
import bpy
import json
import ifcopenshell.api
+import ifcopenshell.api.material
import ifcopenshell.util.element
import ifcopenshell.util.attribute
import ifcopenshell.util.representation
@@ -40,7 +41,8 @@ class LoadMaterials(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- core.load_materials(tool.Material, context.scene.BIMMaterialProperties.material_type)
+ props = tool.Material.get_material_props()
+ core.load_materials(tool.Material, props.material_type)
return {"FINISHED"}
@@ -327,12 +329,13 @@ class AddProfile(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
self.file = IfcStore.get_file()
+ props = tool.Material.get_material_props()
ifcopenshell.api.run(
"material.add_profile",
self.file,
profile_set=self.file.by_id(self.profile_set),
material=self.file.by_id(int(obj.BIMObjectMaterialProperties.material)),
- profile=self.file.by_id(int(context.scene.BIMMaterialProperties.profiles)),
+ profile=self.file.by_id(int(props.profiles)),
)
@@ -662,7 +665,7 @@ class EnableEditingMaterialSetItem(bpy.types.Operator):
def execute(self, context):
self.file = IfcStore.get_file()
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
- self.mprops = context.scene.BIMMaterialProperties
+ self.mprops = tool.Material.get_material_props()
self.props = obj.BIMObjectMaterialProperties
self.props.active_material_set_item_id = self.material_set_item
@@ -706,7 +709,7 @@ class EditMaterialSetItem(bpy.types.Operator, tool.Ifc.Operator):
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
self.file = IfcStore.get_file()
props = obj.BIMObjectMaterialProperties
- mprops = context.scene.BIMMaterialProperties
+ mprops = tool.Material.get_material_props()
element = tool.Ifc.get_entity(obj)
material = ifcopenshell.util.element.get_material(element, should_skip_usage=True)
@@ -763,7 +766,7 @@ class ExpandMaterialCategory(bpy.types.Operator):
return self.execute(context)
def execute(self, context):
- props = context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
for index, category in (
(i, c)
for i, c in enumerate(props.materials)
@@ -792,7 +795,7 @@ class ContractMaterialCategory(bpy.types.Operator):
return self.execute(context)
def execute(self, context):
- props = context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
for index, category in (
(i, c)
for i, c in enumerate(props.materials)
@@ -812,7 +815,7 @@ class EnableEditingMaterialStyle(bpy.types.Operator):
material: bpy.props.IntProperty()
def execute(self, context):
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
props.active_material_id = self.material
props.editing_material_type = "STYLE"
@@ -843,7 +846,7 @@ class EditMaterialStyle(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
ifc_file = tool.Ifc.get()
material = ifc_file.by_id(props.active_material_id)
style = ifc_file.by_id(int(props.styles))
@@ -867,7 +870,7 @@ class UnassignMaterialStyle(bpy.types.Operator, tool.Ifc.Operator):
context: bpy.props.IntProperty()
def _execute(self, context):
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
material = tool.Ifc.get().by_id(props.materials[props.active_material_index].ifc_definition_id)
style = tool.Ifc.get().by_id(self.style)
context = tool.Ifc.get().by_id(self.context)
@@ -888,7 +891,7 @@ class SelectMaterialInMaterialsUI(bpy.types.Operator):
material_id: int
def execute(self, context):
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
ifc_file = tool.Ifc.get()
material_id = self.material_id
material = ifc_file.by_id(material_id)
diff --git a/src/bonsai/bonsai/bim/module/material/prop.py b/src/bonsai/bonsai/bim/module/material/prop.py
index aa680abe9b..f21a34a702 100644
--- a/src/bonsai/bonsai/bim/module/material/prop.py
+++ b/src/bonsai/bonsai/bim/module/material/prop.py
@@ -121,7 +121,7 @@ def set_material_name(self: "Material", new_category_name: str) -> None:
material.Category = new_category_name
# Reload UI elements if necessary.
- props: "BIMMaterialProperties" = self.id_data.BIMMaterialProperties
+ props = tool.Material.get_material_props()
new_category_name_already_in_use = bool(
next((m for m in props.materials if m.is_category and m.name == new_category_name), None)
)
diff --git a/src/bonsai/bonsai/bim/module/material/ui.py b/src/bonsai/bonsai/bim/module/material/ui.py
index c4c9eda9c4..eef2adb670 100644
--- a/src/bonsai/bonsai/bim/module/material/ui.py
+++ b/src/bonsai/bonsai/bim/module/material/ui.py
@@ -29,7 +29,7 @@ from bonsai.bim.module.drawing.helper import format_distance
from typing import TYPE_CHECKING
if TYPE_CHECKING:
- from bonsai.bim.module.material.prop import Material
+ from bonsai.bim.module.material.prop import Material, BIMMaterialProperties
class BIM_PT_materials(Panel):
@@ -49,7 +49,7 @@ class BIM_PT_materials(Panel):
if not MaterialsData.is_loaded:
MaterialsData.load()
- self.props = context.scene.BIMMaterialProperties
+ self.props = tool.Material.get_material_props()
material = tool.Material.get_active_material_item()
material_id = material.ifc_definition_id if material else None
@@ -156,7 +156,7 @@ class BIM_PT_object_material(Panel):
self.file = IfcStore.get_file()
self.oprops = context.active_object.BIMObjectProperties
self.props = context.active_object.BIMObjectMaterialProperties
- self.mprops = context.scene.BIMMaterialProperties
+ self.mprops = tool.Material.get_material_props()
if not ObjectMaterialData.data["materials"]:
row = self.layout.row(align=True)
@@ -401,10 +401,16 @@ class BIM_PT_object_material(Panel):
class BIM_UL_materials(UIList):
def draw_item(
- self, context, layout: bpy.types.UILayout, data, item: Material, icon, active_data, active_propname
+ self,
+ context,
+ layout: bpy.types.UILayout,
+ data: BIMMaterialProperties,
+ item: Material,
+ icon,
+ active_data,
+ active_propname,
) -> None:
- mprops = context.scene.BIMMaterialProperties
- material_type = mprops.material_type
+ material_type = data.material_type
if item:
row = layout.row(align=True)
diff --git a/src/bonsai/bonsai/bim/module/profile/data.py b/src/bonsai/bonsai/bim/module/profile/data.py
index 9f89cf01ed..88bd85197c 100644
--- a/src/bonsai/bonsai/bim/module/profile/data.py
+++ b/src/bonsai/bonsai/bim/module/profile/data.py
@@ -51,7 +51,7 @@ class ProfileData:
@classmethod
def active_profile_users(cls):
- profiles_props = bpy.context.scene.BIMProfileProperties
+ profiles_props = tool.Profile.get_profile_props()
if profiles_props.active_profile_index >= len(profiles_props.profiles):
return 0
profile_prop = profiles_props.profiles[profiles_props.active_profile_index]
@@ -83,7 +83,7 @@ class ProfileData:
@classmethod
def is_arbitrary_profile(cls):
- props = bpy.context.scene.BIMProfileProperties
+ props = tool.Profile.get_profile_props()
if props.active_profile_id:
profile = tool.Ifc.get().by_id(props.active_profile_id)
if profile.is_a("IfcArbitraryClosedProfileDef"):
diff --git a/src/bonsai/bonsai/bim/module/profile/operator.py b/src/bonsai/bonsai/bim/module/profile/operator.py
index a2e5ca5626..b0d5073429 100644
--- a/src/bonsai/bonsai/bim/module/profile/operator.py
+++ b/src/bonsai/bonsai/bim/module/profile/operator.py
@@ -35,7 +35,7 @@ class LoadProfiles(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- props = context.scene.BIMProfileProperties
+ props = tool.Profile.get_profile_props()
props.profiles.clear()
filter_material_profiles = props.is_filtering_material_profiles
@@ -64,7 +64,8 @@ class DisableProfileEditingUI(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- context.scene.BIMProfileProperties.is_editing = False
+ props = tool.Profile.get_profile_props()
+ props.is_editing = False
return {"FINISHED"}
@@ -75,7 +76,7 @@ class RemoveProfileDef(bpy.types.Operator, tool.Ifc.Operator):
profile: bpy.props.IntProperty()
def _execute(self, context):
- props = context.scene.BIMProfileProperties
+ props = tool.Profile.get_profile_props()
current_index = props.active_profile_index
ifc_file = tool.Ifc.get()
@@ -113,7 +114,7 @@ class EnableEditingProfile(bpy.types.Operator):
profile: bpy.props.IntProperty()
def execute(self, context):
- props = context.scene.BIMProfileProperties
+ props = tool.Profile.get_profile_props()
props.profile_attributes.clear()
bonsai.bim.helper.import_attributes2(tool.Ifc.get().by_id(self.profile), props.profile_attributes)
props.active_profile_id = self.profile
@@ -126,7 +127,8 @@ class DisableEditingProfile(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- context.scene.BIMProfileProperties.active_profile_id = 0
+ props = tool.Profile.get_profile_props()
+ props.active_profile_id = 0
bpy.ops.bim.disable_editing_arbitrary_profile()
return {"FINISHED"}
@@ -137,7 +139,7 @@ class EditProfile(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
- props = context.scene.BIMProfileProperties
+ props = tool.Profile.get_profile_props()
attributes = bonsai.bim.helper.export_attributes(props.profile_attributes)
profile = tool.Ifc.get().by_id(props.active_profile_id)
ifcopenshell.api.run("profile.edit_profile", tool.Ifc.get(), profile=profile, attributes=attributes)
@@ -152,7 +154,7 @@ class AddProfileDef(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
- props = context.scene.BIMProfileProperties
+ props = tool.Profile.get_profile_props()
profile_class = props.profile_classes
if profile_class == "IfcArbitraryClosedProfileDef":
obj = props.object_to_profile
@@ -229,7 +231,7 @@ class EnableEditingArbitraryProfile(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
- props = context.scene.BIMProfileProperties
+ props = tool.Profile.get_profile_props()
active_profile = props.profiles[props.active_profile_index]
profile_id = active_profile.ifc_definition_id
props.active_arbitrary_profile_id = profile_id
@@ -253,7 +255,7 @@ def disable_editing_arbitrary_profile(context):
bpy.data.objects.remove(obj)
bpy.data.meshes.remove(profile_mesh)
- props = context.scene.BIMProfileProperties
+ props = tool.Profile.get_profile_props()
props.active_arbitrary_profile_id = 0
# need to update profile manager ui
# if this was called from decorator
@@ -276,7 +278,7 @@ class EditArbitraryProfile(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
- props = context.scene.BIMProfileProperties
+ props = tool.Profile.get_profile_props()
old_profile = tool.Ifc.get().by_id(props.active_arbitrary_profile_id)
obj = context.active_object
@@ -322,7 +324,7 @@ class SelectProfileInProfilesUI(bpy.types.Operator):
profile_id: bpy.props.IntProperty()
def execute(self, context):
- props = bpy.context.scene.BIMProfileProperties
+ props = tool.Profile.get_profile_props()
ifc_file = tool.Ifc.get()
profile = ifc_file.by_id(self.profile_id)
bpy.ops.bim.load_profiles()
diff --git a/src/bonsai/bonsai/bim/module/profile/prop.py b/src/bonsai/bonsai/bim/module/profile/prop.py
index 801e7e0204..9a2da938e6 100644
--- a/src/bonsai/bonsai/bim/module/profile/prop.py
+++ b/src/bonsai/bonsai/bim/module/profile/prop.py
@@ -35,7 +35,7 @@ from bpy.props import (
FloatVectorProperty,
CollectionProperty,
)
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Union
def get_profile_classes(self, context):
@@ -91,6 +91,17 @@ class BIMProfileProperties(PropertyGroup):
poll=lambda self, obj: obj.type == "MESH",
)
+ if TYPE_CHECKING:
+ is_editing: bool
+ profiles: bpy.types.bpy_prop_collection_idprop[Profile]
+ active_profile_index: int
+ active_profile_id: int
+ active_arbitrary_profile_id: int
+ profile_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
+ profile_classes: str
+ is_filtering_material_profiles: bool
+ object_to_profile: Union[bpy.types.Object, None]
+
def generate_thumbnail_for_active_profile():
from PIL import Image, ImageDraw
@@ -98,7 +109,7 @@ def generate_thumbnail_for_active_profile():
if bpy.app.background:
return
- props = bpy.context.scene.BIMProfileProperties
+ props = tool.Profile.get_profile_props()
ifc_file = tool.Ifc.get()
preview_collection = ProfileData.preview_collection
diff --git a/src/bonsai/bonsai/bim/module/profile/ui.py b/src/bonsai/bonsai/bim/module/profile/ui.py
index 9b8f65660a..fa5e9896b3 100644
--- a/src/bonsai/bonsai/bim/module/profile/ui.py
+++ b/src/bonsai/bonsai/bim/module/profile/ui.py
@@ -16,12 +16,17 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see .
+from __future__ import annotations
import bpy
import bonsai.bim.helper
import bonsai.tool as tool
from bpy.types import Panel, UIList
from bonsai.bim.module.profile.data import ProfileData
from bonsai.bim.module.profile.prop import generate_thumbnail_for_active_profile
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from bonsai.bim.module.profile.prop import BIMProfileProperties, Profile
class BIM_PT_profiles(Panel):
@@ -40,7 +45,7 @@ class BIM_PT_profiles(Panel):
def draw(self, context):
if not ProfileData.is_loaded:
ProfileData.load()
- self.props = context.scene.BIMProfileProperties
+ self.props = tool.Profile.get_profile_props()
active_profile = None
if self.props.is_editing and (active_profile := tool.Profile.get_active_profile_ui()):
@@ -129,8 +134,16 @@ class BIM_PT_profiles(Panel):
class BIM_UL_profiles(UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
- props = context.scene.BIMProfileProperties
+ def draw_item(
+ self,
+ context,
+ layout: bpy.types.UILayout,
+ data: BIMProfileProperties,
+ item: Profile,
+ icon,
+ active_data,
+ active_propname,
+ ):
if item:
row = layout.row(align=True)
row.prop(item, "name", text="", emboss=False)
diff --git a/src/bonsai/bonsai/bim/module/pset/data.py b/src/bonsai/bonsai/bim/module/pset/data.py
index ab89d67b31..88d830d976 100644
--- a/src/bonsai/bonsai/bim/module/pset/data.py
+++ b/src/bonsai/bonsai/bim/module/pset/data.py
@@ -175,7 +175,7 @@ class MaterialPsetsData(Data):
@classmethod
def load(cls):
ifc_definition_id = None
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
if props.materials and props.active_material_index < len(props.materials):
ifc_definition_id = props.materials[props.active_material_index].ifc_definition_id
@@ -188,7 +188,7 @@ class MaterialPsetsData(Data):
@classmethod
def pset_name(cls):
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
if props.materials and props.active_material_index < len(props.materials):
material = props.materials[props.active_material_index]
if material.ifc_definition_id:
diff --git a/src/bonsai/bonsai/bim/module/pset/prop.py b/src/bonsai/bonsai/bim/module/pset/prop.py
index 2014ff1bd6..86a3363557 100644
--- a/src/bonsai/bonsai/bim/module/pset/prop.py
+++ b/src/bonsai/bonsai/bim/module/pset/prop.py
@@ -173,7 +173,7 @@ def get_group_qto_names(self, context):
def get_profile_pset_names(self, context):
global psetnames
- pprops = context.scene.BIMProfileProperties
+ pprops = tool.Profile.get_profile_props()
ifc_class = IfcStore.get_file().by_id(pprops.profiles[pprops.active_profile_index].ifc_definition_id).is_a()
if ifc_class not in psetnames:
psets = bonsai.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True, schema=tool.Ifc.get_schema())
diff --git a/src/bonsai/bonsai/bim/module/pset/ui.py b/src/bonsai/bonsai/bim/module/pset/ui.py
index 8db5c36389..21f3c1b083 100644
--- a/src/bonsai/bonsai/bim/module/pset/ui.py
+++ b/src/bonsai/bonsai/bim/module/pset/ui.py
@@ -403,13 +403,13 @@ class BIM_PT_material_psets(Panel):
ifc_file = tool.Ifc.get()
if not ifc_file or ifc_file.schema == "IFC2X3":
return False # We don't support material psets in IFC2X3 because they suck
- props = context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
if props.is_editing and (material := props.active_material) and material.ifc_definition_id:
return True
return False
def draw(self, context):
- props = context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
if props.materials and props.active_material_index < len(props.materials):
ifc_definition_id = props.materials[props.active_material_index].ifc_definition_id
@@ -663,10 +663,10 @@ class BIM_PT_profile_psets(Panel):
@classmethod
def poll(cls, context):
- props = context.scene.BIMProfileProperties
+ props = tool.Profile.get_profile_props()
if not props.is_editing:
return False
- total_profiles = len(context.scene.BIMProfileProperties.profiles)
+ total_profiles = len(props.profiles)
if total_profiles > 0 and props.active_profile_index < total_profiles:
return True
return False
diff --git a/src/bonsai/bonsai/tool/bcf.py b/src/bonsai/bonsai/tool/bcf.py
index 4a4068034a..c427a22e90 100644
--- a/src/bonsai/bonsai/tool/bcf.py
+++ b/src/bonsai/bonsai/tool/bcf.py
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see .
+from __future__ import annotations
import bcf.v2.visinfo
import bonsai.core.tool
import bonsai.tool as tool
@@ -32,16 +33,24 @@ import bcf.agnostic.model
import bcf.agnostic.topic
import bcf.agnostic.visinfo
-from typing import Any, Union, TypeVar, TypeGuard, Optional
+from typing import Any, Union, TypeVar, TypeGuard, Optional, TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from bonsai.bim.module.bcf.prop import BCFProperties
T = TypeVar("T")
class Bcf(bonsai.core.tool.Bcf):
+ @classmethod
+ def get_bcf_props(cls) -> "BCFProperties":
+ return bpy.context.scene.BCFProperties
+
@classmethod
def get_path(cls) -> str:
- return bpy.context.scene.BCFProperties.bcf_file
+ props = cls.get_bcf_props()
+ return props.bcf_file
@classmethod
def is_list_of(cls, a: list[Any], t: type[T]) -> TypeGuard[list[T]]:
diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py
index 605bcbab90..ad62b1fabc 100644
--- a/src/bonsai/bonsai/tool/blender.py
+++ b/src/bonsai/bonsai/tool/blender.py
@@ -191,9 +191,8 @@ class Blender(bonsai.core.tool.Blender):
if obj_type == "Object":
return bpy.data.objects.get(obj).BIMObjectProperties.ifc_definition_id
elif obj_type == "Material":
- return context.scene.BIMMaterialProperties.materials[
- context.scene.BIMMaterialProperties.active_material_index
- ].ifc_definition_id
+ props = tool.Material.get_material_props()
+ return props.materials[props.active_material_index].ifc_definition_id
elif obj_type == "MaterialSetItem":
return bpy.data.objects.get(obj).BIMObjectMaterialProperties.active_material_set_item_id
elif obj_type == "Task":
@@ -208,9 +207,8 @@ class Blender(bonsai.core.tool.Blender):
context.scene.BIMResourceProperties.active_resource_index
].ifc_definition_id
elif obj_type == "Profile":
- return context.scene.BIMProfileProperties.profiles[
- context.scene.BIMProfileProperties.active_profile_index
- ].ifc_definition_id
+ props = tool.Profile.get_profile_props()
+ return props.profiles[props.active_profile_index].ifc_definition_id
elif obj_type == "WorkSchedule":
return context.scene.BIMWorkScheduleProperties.active_work_schedule_id
elif obj_type == "Group":
diff --git a/src/bonsai/bonsai/tool/library.py b/src/bonsai/bonsai/tool/library.py
index c28173482b..f968a21625 100644
--- a/src/bonsai/bonsai/tool/library.py
+++ b/src/bonsai/bonsai/tool/library.py
@@ -16,52 +16,62 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see .
+from __future__ import annotations
import ifcopenshell
import bpy
import bonsai.bim.helper
import bonsai.core.tool
import bonsai.tool as tool
-from typing import Literal, Any, Union
+from typing import Literal, Any, Union, TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from bonsai.bim.module.library.prop import BIMLibraryProperties
class Library(bonsai.core.tool.Library):
+ @classmethod
+ def get_library_props(cls) -> BIMLibraryProperties:
+ return bpy.context.scene.BIMLibraryProperties
+
@classmethod
def clear_editing_mode(cls) -> None:
- bpy.context.scene.BIMLibraryProperties.editing_mode = "NONE"
+ cls.get_library_props().editing_mode = "NONE"
@classmethod
def export_library_attributes(cls) -> dict[str, Any]:
- props = bpy.context.scene.BIMLibraryProperties
+ props = cls.get_library_props()
return bonsai.bim.helper.export_attributes(props.library_attributes)
@classmethod
def export_reference_attributes(cls) -> dict[str, Any]:
- props = bpy.context.scene.BIMLibraryProperties
+ props = cls.get_library_props()
return bonsai.bim.helper.export_attributes(props.reference_attributes)
@classmethod
def get_active_library(cls) -> ifcopenshell.entity_instance:
- return tool.Ifc.get().by_id(bpy.context.scene.BIMLibraryProperties.active_library_id)
+ props = cls.get_library_props()
+ return tool.Ifc.get().by_id(props.active_library_id)
@classmethod
def get_active_reference(cls) -> ifcopenshell.entity_instance:
- return tool.Ifc.get().by_id(bpy.context.scene.BIMLibraryProperties.active_reference_id)
+ props = cls.get_library_props()
+ return tool.Ifc.get().by_id(props.active_reference_id)
@classmethod
def import_library_attributes(cls, library: ifcopenshell.entity_instance) -> None:
- props = bpy.context.scene.BIMLibraryProperties
+ props = cls.get_library_props()
props.library_attributes.clear()
bonsai.bim.helper.import_attributes2(library, props.library_attributes)
@classmethod
def import_reference_attributes(cls, reference: ifcopenshell.entity_instance) -> None:
- props = bpy.context.scene.BIMLibraryProperties
+ props = cls.get_library_props()
props.reference_attributes.clear()
bonsai.bim.helper.import_attributes2(reference, props.reference_attributes)
@classmethod
def import_references(cls, library: ifcopenshell.entity_instance) -> None:
- props = bpy.context.scene.BIMLibraryProperties
+ props = cls.get_library_props()
props.references.clear()
if tool.Ifc.get_schema() == "IFC2X3":
references = library.LibraryReference
@@ -74,7 +84,7 @@ class Library(bonsai.core.tool.Library):
@classmethod
def set_active_library(cls, library: Union[ifcopenshell.entity_instance, None]) -> None:
- props = bpy.context.scene.BIMLibraryProperties
+ props = cls.get_library_props()
if library is None:
props.active_library_id = 0
else:
@@ -82,8 +92,10 @@ class Library(bonsai.core.tool.Library):
@classmethod
def set_active_reference(cls, reference: ifcopenshell.entity_instance) -> None:
- bpy.context.scene.BIMLibraryProperties.active_reference_id = reference.id()
+ props = cls.get_library_props()
+ props.active_reference_id = reference.id()
@classmethod
def set_editing_mode(cls, mode: Literal["LIBRARY", "REFERENCES", "REFERENCE"]) -> None:
- bpy.context.scene.BIMLibraryProperties.editing_mode = mode
+ props = cls.get_library_props()
+ props.editing_mode = mode
diff --git a/src/bonsai/bonsai/tool/material.py b/src/bonsai/bonsai/tool/material.py
index 5dad3cbf63..0d32bb1ebd 100644
--- a/src/bonsai/bonsai/tool/material.py
+++ b/src/bonsai/bonsai/tool/material.py
@@ -33,12 +33,18 @@ from typing_extensions import assert_never
if TYPE_CHECKING:
# Avoid circular imports.
from bonsai.bim.module.material.prop import Material as MaterialItem
+ from bonsai.bim.module.material.prop import BIMMaterialProperties
class Material(bonsai.core.tool.Material):
+ @classmethod
+ def get_material_props(cls) -> BIMMaterialProperties:
+ return bpy.context.scene.BIMMaterialProperties
+
@classmethod
def disable_editing_materials(cls) -> None:
- bpy.context.scene.BIMMaterialProperties.is_editing = False
+ props = tool.Material.get_material_props()
+ props.is_editing = False
@classmethod
def duplicate_material(cls, material: ifcopenshell.entity_instance) -> ifcopenshell.entity_instance:
@@ -55,11 +61,13 @@ class Material(bonsai.core.tool.Material):
@classmethod
def enable_editing_materials(cls) -> None:
- bpy.context.scene.BIMMaterialProperties.is_editing = True
+ props = tool.Material.get_material_props()
+ props.is_editing = True
@classmethod
def get_active_material_type(cls) -> str:
- return bpy.context.scene.BIMMaterialProperties.material_type
+ props = tool.Material.get_material_props()
+ return props.material_type
@classmethod
def get_elements_by_material(cls, material: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
@@ -68,7 +76,7 @@ class Material(bonsai.core.tool.Material):
@classmethod
def get_active_material_item(cls) -> Union[MaterialItem, None]:
"""Get active material props item if index is valid, otherwise, return None."""
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
if 0 <= props.active_material_index < len(props.materials):
return props.materials[props.active_material_index]
return None
@@ -80,7 +88,7 @@ class Material(bonsai.core.tool.Material):
@classmethod
def import_material_definitions(cls, material_type: str) -> None:
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
# Store active category name to reselect it later.
# Occurs when we expand/contract all categories.
@@ -140,7 +148,8 @@ class Material(bonsai.core.tool.Material):
@classmethod
def is_editing_materials(cls) -> bool:
- return bpy.context.scene.BIMMaterialProperties.is_editing
+ props = tool.Material.get_material_props()
+ return props.is_editing
@classmethod
def is_material_used_in_sets(cls, material: ifcopenshell.entity_instance) -> bool:
@@ -156,23 +165,24 @@ class Material(bonsai.core.tool.Material):
@classmethod
def load_material_attributes(cls, material: ifcopenshell.entity_instance) -> None:
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
props.material_attributes.clear()
bonsai.bim.helper.import_attributes2(material, props.material_attributes)
@classmethod
def enable_editing_material(cls, material: ifcopenshell.entity_instance) -> None:
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
props.active_material_id = material.id()
props.editing_material_type = "ATTRIBUTES"
@classmethod
def get_material_attributes(cls) -> dict[str, Any]:
- return bonsai.bim.helper.export_attributes(bpy.context.scene.BIMMaterialProperties.material_attributes)
+ props = tool.Material.get_material_props()
+ return bonsai.bim.helper.export_attributes(props.material_attributes)
@classmethod
def disable_editing_material(cls) -> None:
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
props.active_material_id = 0
props.editing_material_type = ""
diff --git a/src/bonsai/bonsai/tool/model.py b/src/bonsai/bonsai/tool/model.py
index c20f2762fd..6db9718d4d 100644
--- a/src/bonsai/bonsai/tool/model.py
+++ b/src/bonsai/bonsai/tool/model.py
@@ -26,6 +26,7 @@ import collections.abc
import numpy as np
import ifcopenshell
import ifcopenshell.api
+import ifcopenshell.api.grid
import ifcopenshell.api.pset
import ifcopenshell.geom
import ifcopenshell.util.element
@@ -1973,14 +1974,14 @@ class Model(bonsai.core.tool.Model):
extrusion.Position = position
@classmethod
- def get_existing_x_angle(cls, extrusion):
+ def get_existing_x_angle(cls, extrusion: ifcopenshell.entity_instance) -> float:
x, y, z = extrusion.ExtrudedDirection.DirectionRatios
x_angle = Vector((0, 1)).angle_signed(Vector((y, z)))
return x_angle
@classmethod
- def create_axis_curve(cls, obj: bpy.types.Object, grid_axis: ifcopenshell.entity_instance):
+ def create_axis_curve(cls, obj: bpy.types.Object, grid_axis: ifcopenshell.entity_instance) -> None:
m = tool.Surveyor.get_absolute_matrix(obj)
points = [m @ np.array(v.co.to_4d()) for v in obj.data.vertices[0:2]]
ifcopenshell.api.grid.create_axis_curve(
diff --git a/src/bonsai/bonsai/tool/profile.py b/src/bonsai/bonsai/tool/profile.py
index 9100383769..d230835b09 100644
--- a/src/bonsai/bonsai/tool/profile.py
+++ b/src/bonsai/bonsai/tool/profile.py
@@ -33,9 +33,14 @@ from typing import Union, TYPE_CHECKING
if TYPE_CHECKING:
import bonsai.bim.module.profile.prop
+ from bonsai.bim.module.profile.prop import BIMProfileProperties
class Profile(bonsai.core.tool.Profile):
+ @classmethod
+ def get_profile_props(cls) -> BIMProfileProperties:
+ return bpy.context.scene.BIMProfileProperties
+
@classmethod
def draw_image_for_ifc_profile(
cls, draw: PIL.ImageDraw.ImageDraw, profile: ifcopenshell.entity_instance, size: float
@@ -116,7 +121,7 @@ class Profile(bonsai.core.tool.Profile):
@classmethod
def get_active_profile_ui(cls) -> Union[bonsai.bim.module.profile.prop.Profile, None]:
- props = bpy.context.scene.BIMProfileProperties
+ props = cls.get_profile_props()
index = props.active_profile_index
if len(props.profiles) > index >= 0:
return props.profiles[index]
diff --git a/src/bonsai/test/tool/test_library.py b/src/bonsai/test/tool/test_library.py
index 7ce2308d69..12209824ea 100644
--- a/src/bonsai/test/tool/test_library.py
+++ b/src/bonsai/test/tool/test_library.py
@@ -31,7 +31,7 @@ class TestImplementsTool(NewFile):
class TestClearEditingMode(NewFile):
def test_run(self):
- props = bpy.context.scene.BIMLibraryProperties
+ props = tool.Library.get_library_props()
props.editing_mode = "LIBRARY"
subject.clear_editing_mode()
assert props.editing_mode == "NONE"
@@ -78,7 +78,7 @@ class TestImportLibraryAttributes(NewFile):
tool.Ifc.set(ifc := ifcopenshell.file())
library = ifc.createIfcLibraryInformation("Name", "Version", None, "VersionDate", "Location", "Description")
subject.import_library_attributes(library)
- props = bpy.context.scene.BIMLibraryProperties
+ props = tool.Library.get_library_props()
assert props.library_attributes.get("Name").string_value == "Name"
assert props.library_attributes.get("Version").string_value == "Version"
assert props.library_attributes.get("VersionDate").string_value == "VersionDate"
@@ -91,7 +91,7 @@ class TestImportReferenceAttributes(NewFile):
tool.Ifc.set(ifc := ifcopenshell.file())
reference = ifc.createIfcLibraryReference("Location", "Identification", "Name", "Description", "Language")
subject.import_reference_attributes(reference)
- props = bpy.context.scene.BIMLibraryProperties
+ props = tool.Library.get_library_props()
assert props.reference_attributes.get("Location").string_value == "Location"
assert props.reference_attributes.get("Identification").string_value == "Identification"
assert props.reference_attributes.get("Name").string_value == "Name"
@@ -105,7 +105,7 @@ class TestImportReferences(NewFile):
library = ifc.createIfcLibraryInformation()
reference = ifc.createIfcLibraryReference(Name="Reference", ReferencedLibrary=library)
subject.import_references(library)
- props = bpy.context.scene.BIMLibraryProperties
+ props = tool.Library.get_library_props()
assert props.references[0].ifc_definition_id == reference.id()
assert props.references[0].name == "Reference"
@@ -116,7 +116,8 @@ class TestSetActiveLibrary(NewFile):
tool.Ifc.set(ifc)
library = ifc.createIfcLibraryInformation()
subject.set_active_library(library)
- assert bpy.context.scene.BIMLibraryProperties.active_library_id == library.id()
+ props = tool.Library.get_library_props()
+ assert props.active_library_id == library.id()
class TestSetActiveReference(NewFile):
@@ -125,10 +126,12 @@ class TestSetActiveReference(NewFile):
tool.Ifc.set(ifc)
reference = ifc.createIfcLibraryReference()
subject.set_active_reference(reference)
- assert bpy.context.scene.BIMLibraryProperties.active_reference_id == reference.id()
+ props = tool.Library.get_library_props()
+ assert props.active_reference_id == reference.id()
class TestSetEditingMode(NewFile):
def test_run(self):
subject.set_editing_mode("LIBRARY")
- assert bpy.context.scene.BIMLibraryProperties.editing_mode == "LIBRARY"
+ props = tool.Library.get_library_props()
+ assert props.editing_mode == "LIBRARY"
diff --git a/src/bonsai/test/tool/test_material.py b/src/bonsai/test/tool/test_material.py
index 281c8918ac..c980135b5a 100644
--- a/src/bonsai/test/tool/test_material.py
+++ b/src/bonsai/test/tool/test_material.py
@@ -35,25 +35,28 @@ class TestImplementsTool(NewFile):
class TestDisableEditingMaterials(NewFile):
def test_run(self):
- bpy.context.scene.BIMMaterialProperties.is_editing = True
+ props = tool.Material.get_material_props()
+ props.is_editing = True
subject.disable_editing_materials()
- assert bpy.context.scene.BIMMaterialProperties.is_editing is False
+ assert props.is_editing is False
class TestEnableEditingMaterials(NewFile):
def test_run(self):
- bpy.context.scene.BIMMaterialProperties.is_editing = False
+ props = tool.Material.get_material_props()
+ props.is_editing = False
subject.enable_editing_materials()
- assert bpy.context.scene.BIMMaterialProperties.is_editing is True
+ assert props.is_editing is True
class TestGetActiveMaterialType(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
- bpy.context.scene.BIMMaterialProperties.material_type = "IfcMaterial"
+ props = tool.Material.get_material_props()
+ props.material_type = "IfcMaterial"
assert subject.get_active_material_type() == "IfcMaterial"
- bpy.context.scene.BIMMaterialProperties.material_type = "IfcMaterialLayerSet"
+ props.material_type = "IfcMaterialLayerSet"
assert subject.get_active_material_type() == "IfcMaterialLayerSet"
@@ -73,7 +76,7 @@ class TestImportMaterialDefinitions(NewFile):
tool.Ifc.set(ifc)
material = ifc.createIfcMaterial(Name="Name", Category="Category")
subject.import_material_definitions("IfcMaterial")
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
assert props.materials[0].ifc_definition_id == 0
assert props.materials[0].name == "Category"
assert props.materials[0].is_category is True
@@ -85,7 +88,7 @@ class TestImportMaterialDefinitions(NewFile):
tool.Ifc.set(ifc)
material = ifc.createIfcMaterial(Name="Name", Category="Category")
subject.import_material_definitions("IfcMaterial")
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
props.materials[0].is_expanded = True
subject.import_material_definitions("IfcMaterial")
assert len(props.materials) == 2
@@ -98,7 +101,7 @@ class TestImportMaterialDefinitions(NewFile):
tool.Ifc.set(ifc)
material = ifc.createIfcMaterialLayerSet(LayerSetName="Name")
subject.import_material_definitions("IfcMaterialLayerSet")
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
assert props.materials[0].ifc_definition_id == material.id()
assert props.materials[0].name == "Name"
assert props.materials[0].total_elements == 0
@@ -108,7 +111,7 @@ class TestImportMaterialDefinitions(NewFile):
tool.Ifc.set(ifc)
material = ifc.createIfcMaterialProfileSet(Name="Name")
subject.import_material_definitions("IfcMaterialProfileSet")
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
assert props.materials[0].ifc_definition_id == material.id()
assert props.materials[0].name == "Name"
assert props.materials[0].total_elements == 0
@@ -118,7 +121,7 @@ class TestImportMaterialDefinitions(NewFile):
tool.Ifc.set(ifc)
material = ifc.createIfcMaterialConstituentSet(Name="Name")
subject.import_material_definitions("IfcMaterialConstituentSet")
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
assert props.materials[0].ifc_definition_id == material.id()
assert props.materials[0].name == "Name"
assert props.materials[0].total_elements == 0
@@ -128,7 +131,7 @@ class TestImportMaterialDefinitions(NewFile):
tool.Ifc.set(ifc)
material = ifc.createIfcMaterialList()
subject.import_material_definitions("IfcMaterialList")
- props = bpy.context.scene.BIMMaterialProperties
+ props = tool.Material.get_material_props()
assert props.materials[0].ifc_definition_id == material.id()
assert props.materials[0].name == "Unnamed"
assert props.materials[0].total_elements == 0
@@ -136,9 +139,10 @@ class TestImportMaterialDefinitions(NewFile):
class TestIsEditingMaterials(NewFile):
def test_run(self):
- bpy.context.scene.BIMMaterialProperties.is_editing = False
+ props = tool.Material.get_material_props()
+ props.is_editing = False
assert subject.is_editing_materials() is False
- bpy.context.scene.BIMMaterialProperties.is_editing = True
+ props.is_editing = True
assert subject.is_editing_materials() is True
diff --git a/src/ifcopenshell-python/ifcopenshell/api/grid/create_axis_curve.py b/src/ifcopenshell-python/ifcopenshell/api/grid/create_axis_curve.py
index d65a96ee54..4e692008e3 100644
--- a/src/ifcopenshell-python/ifcopenshell/api/grid/create_axis_curve.py
+++ b/src/ifcopenshell-python/ifcopenshell/api/grid/create_axis_curve.py
@@ -22,13 +22,14 @@ import ifcopenshell.util.element
import ifcopenshell.util.unit
import ifcopenshell.util.placement
import numpy as np
+from ifcopenshell.util.shape_builder import VectorType, V, ifc_safe_vector_type
def create_axis_curve(
file: ifcopenshell.file,
*,
- p1: np.ndarray,
- p2: np.ndarray,
+ p1: VectorType,
+ p2: VectorType,
grid_axis: ifcopenshell.entity_instance,
is_si: bool = True,
) -> None:
@@ -60,7 +61,7 @@ def create_axis_curve(
model, p1=np.array((0., 0., 0.)), p2=np.array((0., 10., 0.)), grid_axis=axis_1)
"""
existing_curve = grid_axis.AxisCurve
-
+ p1, p2 = V(p1), V(p2)
if is_si:
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(file)
p1 /= unit_scale
@@ -70,8 +71,8 @@ def create_axis_curve(
grid_matrix_i = np.linalg.inv(ifcopenshell.util.placement.get_local_placement(grid.ObjectPlacement))
grid_axis.AxisCurve = file.createIfcPolyline(
(
- file.createIfcCartesianPoint((grid_matrix_i @ p1).tolist()),
- file.createIfcCartesianPoint((grid_matrix_i @ p2).tolist()),
+ file.createIfcCartesianPoint(ifc_safe_vector_type(grid_matrix_i @ p1)),
+ file.createIfcCartesianPoint(ifc_safe_vector_type(grid_matrix_i @ p2)),
)
)
diff --git a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py
index 9411307a66..2109bca618 100644
--- a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py
+++ b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py
@@ -264,7 +264,6 @@ class Usecase:
"IfcProductDefinitionShape": ["HasShapeAspects"],
"IfcRepresentationMap": ["HasShapeAspects"],
}
- print('appending type product!')
self.existing_contexts = self.file.by_type("IfcGeometricRepresentationContext")
element = self.add_element(self.settings["element"])
self.reuse_existing_contexts()