This commit is contained in:
Andrej730
2024-03-13 15:21:26 +05:00
parent 9596117953
commit 28b54c869a
3 changed files with 42 additions and 33 deletions
+8 -6
View File
@@ -29,14 +29,14 @@ import blenderbim.bim.handler
import blenderbim.tool as tool import blenderbim.tool as tool
from pathlib import Path from pathlib import Path
from blenderbim.tool.brick import BrickStore from blenderbim.tool.brick import BrickStore
from typing import Set, Union from typing import Set, Union, Optional
IFC_CONNECTED_TYPE = Union[bpy.types.Material, bpy.types.Object] IFC_CONNECTED_TYPE = Union[bpy.types.Material, bpy.types.Object]
class IfcStore: class IfcStore:
path = "" path: str = ""
file: ifcopenshell.file = None file: ifcopenshell.file = None
schema: ifcopenshell.ifcopenshell_wrapper.schema_definition = None schema: ifcopenshell.ifcopenshell_wrapper.schema_definition = None
cache: ifcopenshell.ifcopenshell_wrapper.HdfSerializer = None cache: ifcopenshell.ifcopenshell_wrapper.HdfSerializer = None
@@ -44,11 +44,11 @@ class IfcStore:
id_map: dict[int, IFC_CONNECTED_TYPE] = {} id_map: dict[int, IFC_CONNECTED_TYPE] = {}
guid_map: dict[str, IFC_CONNECTED_TYPE] = {} guid_map: dict[str, IFC_CONNECTED_TYPE] = {}
edited_objs: Set[bpy.types.Object] = set() edited_objs: Set[bpy.types.Object] = set()
pset_template_path = "" pset_template_path: str = ""
pset_template_file: ifcopenshell.file = None pset_template_file: ifcopenshell.file = None
classification_path = "" classification_path: str = ""
classification_file: ifcopenshell.file = None classification_file: ifcopenshell.file = None
library_path = "" library_path: str = ""
library_file: ifcopenshell.file = None library_file: ifcopenshell.file = None
current_transaction = "" current_transaction = ""
last_transaction = "" last_transaction = ""
@@ -280,7 +280,9 @@ class IfcStore:
del IfcStore.guid_map[data["guid"]] del IfcStore.guid_map[data["guid"]]
@staticmethod @staticmethod
def unlink_element(element: ifcopenshell.entity_instance = None, obj: IFC_CONNECTED_TYPE = None) -> None: def unlink_element(
element: Optional[ifcopenshell.entity_instance] = None, obj: Optional[IFC_CONNECTED_TYPE] = None
) -> None:
if element is None: if element is None:
try: try:
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
+22 -18
View File
@@ -20,45 +20,47 @@ import os
import bpy import bpy
import numpy as np import numpy as np
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.util.element
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.bim.handler import blenderbim.bim.handler
import blenderbim.tool as tool import blenderbim.tool as tool
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore, IFC_CONNECTED_TYPE
from typing import Optional, Union, Any
class Ifc(blenderbim.core.tool.Ifc): class Ifc(blenderbim.core.tool.Ifc):
@classmethod @classmethod
def run(cls, command, **kwargs): def run(cls, command: str, **kwargs) -> Any:
return ifcopenshell.api.run(command, IfcStore.get_file(), **kwargs) return ifcopenshell.api.run(command, IfcStore.get_file(), **kwargs)
@classmethod @classmethod
def set(cls, ifc): def set(cls, ifc: ifcopenshell.file) -> None:
IfcStore.file = ifc IfcStore.file = ifc
@classmethod @classmethod
def get(cls): def get(cls) -> ifcopenshell.file:
return IfcStore.get_file() return IfcStore.get_file()
@classmethod @classmethod
def get_path(cls): def get_path(cls) -> str:
return IfcStore.path return IfcStore.path
@classmethod @classmethod
def get_schema(cls): def get_schema(cls) -> str:
if IfcStore.get_file(): if IfcStore.get_file():
return IfcStore.get_file().schema return IfcStore.get_file().schema
@classmethod @classmethod
def has_changed_shading(cls, obj): def has_changed_shading(cls, obj: bpy.types.Material) -> bool:
checksum = obj.BIMMaterialProperties.shading_checksum checksum = obj.BIMMaterialProperties.shading_checksum
return checksum != repr(np.array(obj.diffuse_color).tobytes()) return checksum != repr(np.array(obj.diffuse_color).tobytes())
@classmethod @classmethod
def is_edited(cls, obj): def is_edited(cls, obj: bpy.types.Object) -> bool:
return list(obj.scale) != [1.0, 1.0, 1.0] or obj in IfcStore.edited_objs return list(obj.scale) != [1.0, 1.0, 1.0] or obj in IfcStore.edited_objs
@classmethod @classmethod
def is_moved(cls, obj): def is_moved(cls, obj: bpy.types.Object) -> bool:
element = cls.get_entity(obj) element = cls.get_entity(obj)
if not element or element.is_a("IfcTypeProduct") or element.is_a("IfcProject"): if not element or element.is_a("IfcTypeProduct") or element.is_a("IfcProject"):
return False return False
@@ -77,7 +79,7 @@ class Ifc(blenderbim.core.tool.Ifc):
return IfcStore.get_schema() return IfcStore.get_schema()
@classmethod @classmethod
def get_entity(cls, obj): def get_entity(cls, obj: bpy.types.Object) -> ifcopenshell.entity_instance:
ifc = IfcStore.get_file() ifc = IfcStore.get_file()
props = getattr(obj, "BIMObjectProperties", None) props = getattr(obj, "BIMObjectProperties", None)
if ifc and props and props.ifc_definition_id: if ifc and props and props.ifc_definition_id:
@@ -87,7 +89,7 @@ class Ifc(blenderbim.core.tool.Ifc):
pass pass
@classmethod @classmethod
def get_entity_by_id(cls, entity_id): def get_entity_by_id(cls, entity_id) -> Union[ifcopenshell.entity_instance, None]:
"""useful to check whether entity_id is still exists in IFC""" """useful to check whether entity_id is still exists in IFC"""
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
try: try:
@@ -96,11 +98,11 @@ class Ifc(blenderbim.core.tool.Ifc):
return None return None
@classmethod @classmethod
def get_object(cls, element): def get_object(cls, element: ifcopenshell.entity_instance) -> IFC_CONNECTED_TYPE:
return IfcStore.get_element(element.id()) return IfcStore.get_element(element.id())
@classmethod @classmethod
def rebuild_element_maps(cls): def rebuild_element_maps(cls) -> None:
"""Rebuilds the id_map and guid_map """Rebuilds the id_map and guid_map
When any Blender object is stored outside a Blender PointerProperty, When any Blender object is stored outside a Blender PointerProperty,
@@ -153,15 +155,15 @@ class Ifc(blenderbim.core.tool.Ifc):
blenderbim.bim.handler.subscribe_to(obj, "diffuse_color", blenderbim.bim.handler.color_callback) blenderbim.bim.handler.subscribe_to(obj, "diffuse_color", blenderbim.bim.handler.color_callback)
@classmethod @classmethod
def link(cls, element, obj): def link(cls, element: ifcopenshell.entity_instance, obj: IFC_CONNECTED_TYPE) -> None:
IfcStore.link_element(element, obj) IfcStore.link_element(element, obj)
@classmethod @classmethod
def edit(cls, obj): def edit(cls, obj: bpy.types.Object) -> None:
IfcStore.edited_objs.add(obj) IfcStore.edited_objs.add(obj)
@classmethod @classmethod
def finish_edit(cls, obj): def finish_edit(cls, obj: bpy.types.Object) -> None:
try: try:
IfcStore.edited_objs.remove(obj) IfcStore.edited_objs.remove(obj)
except: except:
@@ -186,11 +188,13 @@ class Ifc(blenderbim.core.tool.Ifc):
return os.path.relpath(uri, ifc_path).replace("\\", "/") return os.path.relpath(uri, ifc_path).replace("\\", "/")
@classmethod @classmethod
def unlink(cls, element=None, obj=None): def unlink(
cls, element: Optional[ifcopenshell.entity_instance] = None, obj: Optional[IFC_CONNECTED_TYPE] = None
) -> None:
IfcStore.unlink_element(element, obj) IfcStore.unlink_element(element, obj)
@classmethod @classmethod
def get_all_element_occurrences(cls, element): def get_all_element_occurrences(cls, element: ifcopenshell.entity_instance) -> list[ifcopenshell.entity_instance]:
if element.is_a("IfcElementType"): if element.is_a("IfcElementType"):
element_type = element element_type = element
occurrences = ifcopenshell.util.element.get_types(element_type) occurrences = ifcopenshell.util.element.get_types(element_type)
@@ -23,13 +23,14 @@ import numpy
import importlib import importlib
import ifcopenshell import ifcopenshell
import ifcopenshell.api import ifcopenshell.api
from typing import Callable, Any
pre_listeners = {} pre_listeners = {}
post_listeners = {} post_listeners = {}
def run(usecase_path, ifc_file=None, should_run_listeners=True, **settings): def run(usecase_path: str, ifc_file: ifcopenshell.file = None, should_run_listeners=True, **settings) -> Any:
if should_run_listeners: if should_run_listeners:
for listener in pre_listeners.get(usecase_path, {}).values(): for listener in pre_listeners.get(usecase_path, {}).values():
listener(usecase_path, ifc_file, settings) listener(usecase_path, ifc_file, settings)
@@ -74,42 +75,44 @@ def run(usecase_path, ifc_file=None, should_run_listeners=True, **settings):
return result return result
def add_pre_listener(usecase_path, name, callback): def add_pre_listener(usecase_path: str, name: str, callback: Callable[[str, ifcopenshell.file, dict], None]) -> None:
"""Add a pre listener """Add a pre listener
:param usecase_path: string, ifcopenshell api use case path :param usecase_path: string, ifcopenshell api use case path
:param name: string, name of listener :param name: string, name of listener
:param callback: callback function :param callback: callback function with 3 arguments: `usecase_path`, `ifc_file`, `settings`
""" """
pre_listeners.setdefault(usecase_path, {})[name] = callback pre_listeners.setdefault(usecase_path, {})[name] = callback
def add_post_listener(usecase_path, name, callback): def add_post_listener(usecase_path: str, name: str, callback: Callable[[str, ifcopenshell.file, dict], None]) -> None:
"""Add a post listener """Add a post listener
:param usecase_path: string, ifcopenshell api use case path :param usecase_path: string, ifcopenshell api use case path
:param name: string, name of listener :param name: string, name of listener
:param callback: callback function :param callback: callback function with 3 arguments: `usecase_path`, `ifc_file`, `settings`
""" """
post_listeners.setdefault(usecase_path, {})[name] = callback post_listeners.setdefault(usecase_path, {})[name] = callback
def remove_pre_listener(usecase_path, name, callback): def remove_pre_listener(usecase_path: str, name: str, callback: Callable[[str, ifcopenshell.file, dict], None]) -> None:
"""Remove a pre listener """Remove a pre listener
:param usecase_path: string, ifcopenshell api use case path :param usecase_path: string, ifcopenshell api use case path
:param name: string, name of listener :param name: string, name of listener
:param callback: callback function :param callback: callback function with 3 arguments: `usecase_path`, `ifc_file`, `settings`
""" """
pre_listeners.get(usecase_path, {}).pop(name, None) pre_listeners.get(usecase_path, {}).pop(name, None)
def remove_post_listener(usecase_path, name, callback): def remove_post_listener(
usecase_path: str, name: str, callback: Callable[[str, ifcopenshell.file, dict], None]
) -> None:
"""Remove a post listener """Remove a post listener
:param usecase_path: string, ifcopenshell api use case path :param usecase_path: string, ifcopenshell api use case path
:param name: string, name of listener :param name: string, name of listener
:param callback: callback function :param callback: callback function with 3 arguments: `usecase_path`, `ifc_file`, `settings`
""" """
post_listeners.get(usecase_path, {}).pop(name, None) post_listeners.get(usecase_path, {}).pop(name, None)