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()