This commit is contained in:
Andrej730
2025-06-20 14:27:31 +05:00
parent 5ec77b1b1c
commit 90ab846a18
17 changed files with 278 additions and 99 deletions
+3 -2
View File
@@ -29,6 +29,7 @@ import numpy.typing as npt
import multiprocessing import multiprocessing
import ifcopenshell import ifcopenshell
import ifcopenshell.geom import ifcopenshell.geom
import ifcopenshell.ifcopenshell_wrapper as W
import ifcopenshell.util.unit import ifcopenshell.util.unit
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcopenshell.util.geolocation import ifcopenshell.util.geolocation
@@ -1032,9 +1033,9 @@ class IfcImporter:
def create_curve( def create_curve(
self, self,
element: ifcopenshell.entity_instance, element: ifcopenshell.entity_instance,
shape: Union[ifcopenshell.geom.ShapeElementType, ifcopenshell.geom.ShapeType], shape: Union[W.Triangulation, W.TriangulationElement],
) -> bpy.types.Curve: ) -> bpy.types.Curve:
if isinstance(shape, ifcopenshell.geom.ShapeElementType): if isinstance(shape, W.TriangulationElement):
geometry = shape.geometry geometry = shape.geometry
else: else:
geometry = shape geometry = shape
@@ -41,7 +41,7 @@ class SearchBSDDClassifications(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
total = core.search_bsdd_class(tool.Bsdd, context.scene.BIMBSDDProperties.keyword) total = core.search_bsdd_class(tool.Bsdd, tool.Bsdd.get_bsdd_props().keyword)
self.report({"INFO"}, f"{total} bSDD classes found.") self.report({"INFO"}, f"{total} bSDD classes found.")
return {"FINISHED"} return {"FINISHED"}
@@ -71,7 +71,7 @@ class SearchBSDDProperties(bpy.types.Operator):
def execute(self, context): def execute(self, context):
props = tool.Bsdd.get_bsdd_props() props = tool.Bsdd.get_bsdd_props()
core.search_bsdd_properties(tool.Bsdd, context.scene.BIMBSDDProperties.keyword, self.obj, self.obj_type) core.search_bsdd_properties(tool.Bsdd, tool.Bsdd.get_bsdd_props().keyword, self.obj, self.obj_type)
self.report({"INFO"}, f"{len(props.properties)} bSDD properties found.") self.report({"INFO"}, f"{len(props.properties)} bSDD properties found.")
return {"FINISHED"} return {"FINISHED"}
+50 -6
View File
@@ -31,7 +31,7 @@ from bpy.props import (
FloatVectorProperty, FloatVectorProperty,
CollectionProperty, CollectionProperty,
) )
from typing import Union from typing import Union, TYPE_CHECKING, Literal
def get_active_dictionary(self, context): def get_active_dictionary(self, context):
@@ -54,27 +54,41 @@ def update_active_class_index(self: "BIMBSDDProperties", context: bpy.types.Cont
class BSDDDictionary(PropertyGroup): class BSDDDictionary(PropertyGroup):
name: StringProperty(name="Name")
uri: StringProperty(name="URI") uri: StringProperty(name="URI")
default_language_code: StringProperty(name="Language") default_language_code: StringProperty(name="Language")
organization_name_owner: StringProperty(name="Organization") organization_name_owner: StringProperty(name="Organization")
status: StringProperty(name="Status") status: StringProperty(name="Status")
version: StringProperty(name="Version") version: StringProperty(name="Version")
is_active: BoolProperty( is_active: BoolProperty(
name="Is Active", description="Enable to search with this dictionary", default=False, update=update_is_active name="Is Active",
description="Enable to search with this dictionary",
default=False,
update=update_is_active,
) )
if TYPE_CHECKING:
uri: str
default_language_code: str
organization_name_owner: str
status: str
version: str
is_active: bool
class BSDDClassification(PropertyGroup): class BSDDClassification(PropertyGroup):
name: StringProperty(name="Name")
reference_code: StringProperty(name="Reference Code") reference_code: StringProperty(name="Reference Code")
uri: StringProperty(name="URI") uri: StringProperty(name="URI")
dictionary_name: StringProperty(name="Dictionary Name") dictionary_name: StringProperty(name="Dictionary Name")
dictionary_namespace_uri: StringProperty(name="Dictionary Namespace URI") dictionary_namespace_uri: StringProperty(name="Dictionary Namespace URI")
if TYPE_CHECKING:
reference_code: str
uri: str
dictionary_name: str
dictionary_namespace_uri: str
class BSDDProperty(PropertyGroup): class BSDDProperty(PropertyGroup):
name: StringProperty(name="Name")
code: StringProperty(name="Code") code: StringProperty(name="Code")
uri: StringProperty(name="URI") uri: StringProperty(name="URI")
pset: StringProperty(name="Pset") pset: StringProperty(name="Pset")
@@ -82,11 +96,19 @@ class BSDDProperty(PropertyGroup):
name="Is Selected", description="Select to add or edit this property", default=False, update=update_is_selected name="Is Selected", description="Select to add or edit this property", default=False, update=update_is_selected
) )
if TYPE_CHECKING:
code: str
uri: str
pset: str
is_selected: bool
class BSDDPset(PropertyGroup): class BSDDPset(PropertyGroup):
name: StringProperty(name="Name")
properties: CollectionProperty(name="Properties", type=Attribute) properties: CollectionProperty(name="Properties", type=Attribute)
if TYPE_CHECKING:
properties: bpy.types.bpy_prop_collection_idprop[Attribute]
class BIMBSDDProperties(PropertyGroup): class BIMBSDDProperties(PropertyGroup):
active_dictionary: StringProperty(name="Active Dictionary") active_dictionary: StringProperty(name="Active Dictionary")
@@ -131,6 +153,28 @@ class BIMBSDDProperties(PropertyGroup):
) )
classification_psets: CollectionProperty(name="Classification Psets", type=BSDDPset) classification_psets: CollectionProperty(name="Classification Psets", type=BSDDPset)
if TYPE_CHECKING:
active_dictionary: str
active_dictionary: str
active_uri: str
dictionaries: bpy.types.bpy_prop_collection_idprop[BSDDDictionary]
active_dictionary_index: int
classifications: bpy.types.bpy_prop_collection_idprop[BSDDClassification]
active_classification_index: int
property_filter_mode: Literal["CLASS", "KEYWORD"]
classes: bpy.types.bpy_prop_collection_idprop[BSDDClassification]
active_class_index: int
properties: bpy.types.bpy_prop_collection_idprop[BSDDProperty]
active_property_index: int
selected_properties: bpy.types.bpy_prop_collection_idprop[Attribute]
keyword: str
should_filter_ifc_class: bool
use_only_ifc_properties: bool
load_preview_dictionaries: bool
load_inactive_dictionaries: bool
load_test_dictionaries: bool
classification_psets: bpy.types.bpy_prop_collection_idprop[BSDDPset]
@property @property
def active_class(self) -> Union[BSDDClassification, None]: def active_class(self) -> Union[BSDDClassification, None]:
return tool.Blender.get_active_uilist_element(self.classes, self.active_class_index) return tool.Blender.get_active_uilist_element(self.classes, self.active_class_index)
+48 -6
View File
@@ -16,9 +16,15 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>. # along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy
import bonsai.tool as tool import bonsai.tool as tool
from bonsai.bim.module.bsdd.data import BSDDData from bonsai.bim.module.bsdd.data import BSDDData
from bpy.types import Panel, UIList from bpy.types import Panel, UIList
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from bonsai.bim.module.bsdd.prop import BIMBSDDProperties, BSDDDictionary, BSDDClassification, BSDDProperty
class BIM_PT_bsdd(Panel): class BIM_PT_bsdd(Panel):
@@ -33,7 +39,8 @@ class BIM_PT_bsdd(Panel):
def draw(self, context): def draw(self, context):
if not BSDDData.is_loaded: if not BSDDData.is_loaded:
BSDDData.load() BSDDData.load()
props = context.scene.BIMBSDDProperties props = tool.Bsdd.get_bsdd_props()
assert self.layout
layout = self.layout layout = self.layout
if len(props.dictionaries): if len(props.dictionaries):
row = self.layout.row() row = self.layout.row()
@@ -70,9 +77,17 @@ class BIM_PT_bsdd(Panel):
class BIM_UL_bsdd_dictionaries(UIList): class BIM_UL_bsdd_dictionaries(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname): def draw_item(
self,
context,
layout: bpy.types.UILayout,
data: BIMBSDDProperties,
item: BSDDDictionary,
icon,
active_data,
active_propname,
) -> None:
if item: if item:
props = context.scene.BIMBSDDProperties
row = layout.row(align=True) row = layout.row(align=True)
if item.status != "Active": if item.status != "Active":
row.label( row.label(
@@ -86,7 +101,16 @@ class BIM_UL_bsdd_dictionaries(UIList):
class BIM_UL_bsdd_classifications(UIList): class BIM_UL_bsdd_classifications(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname): def draw_item(
self,
context,
layout: bpy.types.UILayout,
data: BIMBSDDProperties,
item: BSDDClassification,
icon,
active_data,
active_propname,
) -> None:
if item: if item:
row = layout.row(align=True) row = layout.row(align=True)
row.label(text=item.reference_code) row.label(text=item.reference_code)
@@ -95,7 +119,16 @@ class BIM_UL_bsdd_classifications(UIList):
class BIM_UL_bsdd_classes(UIList): class BIM_UL_bsdd_classes(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname): def draw_item(
self,
context,
layout: bpy.types.UILayout,
data: BIMBSDDProperties,
item: BSDDClassification,
icon,
active_data,
active_propname,
) -> None:
if item: if item:
row = layout.row(align=True) row = layout.row(align=True)
row.label(text=item.name) row.label(text=item.name)
@@ -103,7 +136,16 @@ class BIM_UL_bsdd_classes(UIList):
class BIM_UL_bsdd_properties(UIList): class BIM_UL_bsdd_properties(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname): def draw_item(
self,
context,
layout: bpy.types.UILayout,
data: BIMBSDDProperties,
item: BSDDProperty,
icon,
active_data,
active_propname,
) -> None:
if item: if item:
row = layout.row(align=True) row = layout.row(align=True)
name = item.name name = item.name
@@ -83,7 +83,7 @@ class ReferencesData:
def active_classification_library(cls): def active_classification_library(cls):
if not IfcStore.classification_file or not IfcStore.classification_file.by_type("IfcClassification"): if not IfcStore.classification_file or not IfcStore.classification_file.by_type("IfcClassification"):
return False return False
props = bpy.context.scene.BIMClassificationProperties props = tool.Classification.get_classification_props()
name = IfcStore.classification_file.by_id(int(props.available_classifications)).Name name = IfcStore.classification_file.by_id(int(props.available_classifications)).Name
if name in [e.Name for e in tool.Ifc.get().by_type("IfcClassification")]: if name in [e.Name for e in tool.Ifc.get().by_type("IfcClassification")]:
return name return name
@@ -47,7 +47,7 @@ class AddClassification(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMClassificationProperties props = tool.Classification.get_classification_props()
ifcopenshell.api.classification.add_classification( ifcopenshell.api.classification.add_classification(
tool.Ifc.get(), tool.Ifc.get(),
classification=IfcStore.classification_file.by_id(int(props.available_classifications)), classification=IfcStore.classification_file.by_id(int(props.available_classifications)),
@@ -60,7 +60,7 @@ class AddManualClassification(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMClassificationProperties props = tool.Classification.get_classification_props()
attributes = bonsai.bim.helper.export_attributes(props.classification_attributes) attributes = bonsai.bim.helper.export_attributes(props.classification_attributes)
classification = ifcopenshell.api.classification.add_classification(tool.Ifc.get(), classification="Unnamed") classification = ifcopenshell.api.classification.add_classification(tool.Ifc.get(), classification="Unnamed")
ifcopenshell.api.classification.edit_classification( ifcopenshell.api.classification.edit_classification(
@@ -84,7 +84,7 @@ class AddManualClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
objects = [context.active_object.name] objects = [context.active_object.name]
else: else:
objects = [self.obj] objects = [self.obj]
props = context.scene.BIMClassificationReferenceProperties props = tool.Classification.get_classification_reference_props()
attributes = bonsai.bim.helper.export_attributes(props.reference_attributes) attributes = bonsai.bim.helper.export_attributes(props.reference_attributes)
products = [ products = [
tool.Ifc.get().by_id(ifc_definition_id) tool.Ifc.get().by_id(ifc_definition_id)
@@ -110,7 +110,7 @@ class AddClassificationFromBSDD(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def _execute(self, context):
cprops = context.scene.BIMClassificationProperties cprops = tool.Classification.get_classification_props()
bprops = tool.Bsdd.get_bsdd_props() bprops = tool.Bsdd.get_bsdd_props()
if cprops.classification_source == "BSDD": if cprops.classification_source == "BSDD":
dictionaries = [d.uri for d in bprops.dictionaries if d.is_active] dictionaries = [d.uri for d in bprops.dictionaries if d.is_active]
@@ -142,7 +142,7 @@ class EnableAddingManualClassification(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
props = context.scene.BIMClassificationProperties props = tool.Classification.get_classification_props()
props.is_adding = True props.is_adding = True
props.active_classification_id = 0 props.active_classification_id = 0
props.classification_attributes.clear() props.classification_attributes.clear()
@@ -156,7 +156,7 @@ class DisableAddingManualClassification(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
props = context.scene.BIMClassificationProperties props = tool.Classification.get_classification_props()
props.is_adding = False props.is_adding = False
return {"FINISHED"} return {"FINISHED"}
@@ -167,7 +167,7 @@ class EnableAddingManualClassificationReference(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
props = context.scene.BIMClassificationReferenceProperties props = tool.Classification.get_classification_reference_props()
props.is_adding = True props.is_adding = True
props.reference_attributes.clear() props.reference_attributes.clear()
bonsai.bim.helper.import_attributes2("IfcClassificationReference", props.reference_attributes) bonsai.bim.helper.import_attributes2("IfcClassificationReference", props.reference_attributes)
@@ -180,7 +180,7 @@ class DisableAddingManualClassificationReference(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
props = context.scene.BIMClassificationReferenceProperties props = tool.Classification.get_classification_reference_props()
props.is_adding = False props.is_adding = False
return {"FINISHED"} return {"FINISHED"}
@@ -203,7 +203,7 @@ class EnableEditingClassification(bpy.types.Operator):
new.string_value = "" if new.is_null else json.dumps(data[name]) new.string_value = "" if new.is_null else json.dumps(data[name])
return True return True
props = context.scene.BIMClassificationProperties props = tool.Classification.get_classification_props()
props.classification_attributes.clear() props.classification_attributes.clear()
bonsai.bim.helper.import_attributes2( bonsai.bim.helper.import_attributes2(
tool.Ifc.get().by_id(self.classification), props.classification_attributes, callback tool.Ifc.get().by_id(self.classification), props.classification_attributes, callback
@@ -218,7 +218,8 @@ class DisableEditingClassification(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
context.scene.BIMClassificationProperties.active_classification_id = 0 props = tool.Classification.get_classification_props()
props.active_classification_id = 0
return {"FINISHED"} return {"FINISHED"}
@@ -246,7 +247,7 @@ class EditClassification(bpy.types.Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMClassificationProperties props = tool.Classification.get_classification_props()
def callback(attributes, prop): def callback(attributes, prop):
if prop.name == "ReferenceTokens": if prop.name == "ReferenceTokens":
@@ -271,7 +272,7 @@ class EnableEditingClassificationReference(bpy.types.Operator):
obj: bpy.props.StringProperty() obj: bpy.props.StringProperty()
def execute(self, context): def execute(self, context):
props = context.scene.BIMClassificationReferenceProperties props = tool.Classification.get_classification_reference_props()
props.reference_attributes.clear() props.reference_attributes.clear()
bonsai.bim.helper.import_attributes2(tool.Ifc.get().by_id(self.reference), props.reference_attributes) bonsai.bim.helper.import_attributes2(tool.Ifc.get().by_id(self.reference), props.reference_attributes)
props.active_reference_id = self.reference props.active_reference_id = self.reference
@@ -285,7 +286,7 @@ class DisableEditingClassificationReference(bpy.types.Operator):
obj: bpy.props.StringProperty() obj: bpy.props.StringProperty()
def execute(self, context): def execute(self, context):
context.scene.BIMClassificationReferenceProperties.active_reference_id = 0 tool.Classification.get_classification_reference_props().active_reference_id = 0
return {"FINISHED"} return {"FINISHED"}
@@ -337,7 +338,7 @@ class EditClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
obj: bpy.props.StringProperty() obj: bpy.props.StringProperty()
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMClassificationReferenceProperties props = tool.Classification.get_classification_reference_props()
attributes = bonsai.bim.helper.export_attributes(props.reference_attributes) attributes = bonsai.bim.helper.export_attributes(props.reference_attributes)
ifc_file = tool.Ifc.get() ifc_file = tool.Ifc.get()
ifcopenshell.api.classification.edit_reference( ifcopenshell.api.classification.edit_reference(
@@ -364,7 +365,7 @@ class AddClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
objects = [context.active_object.name] objects = [context.active_object.name]
else: else:
objects = [self.obj] objects = [self.obj]
props = context.scene.BIMClassificationProperties props = tool.Classification.get_classification_props()
classification = None classification = None
classification_name = IfcStore.classification_file.by_id(int(props.available_classifications)).Name classification_name = IfcStore.classification_file.by_id(int(props.available_classifications)).Name
for element in tool.Ifc.get().by_type("IfcClassification"): for element in tool.Ifc.get().by_type("IfcClassification"):
@@ -405,8 +406,7 @@ class AddClassificationReferenceFromBSDD(bpy.types.Operator, tool.Ifc.Operator):
objects = [context.active_object.name] objects = [context.active_object.name]
else: else:
objects = [self.obj] objects = [self.obj]
props = context.scene.BIMClassificationProperties bprops = tool.Bsdd.get_bsdd_props()
bprops = context.scene.BIMBSDDProperties
use_only_ifc_properties: bool = bprops.use_only_ifc_properties use_only_ifc_properties: bool = bprops.use_only_ifc_properties
bsdd_classification = bprops.classifications[bprops.active_classification_index] bsdd_classification = bprops.classifications[bprops.active_classification_index]
@@ -487,7 +487,7 @@ class ChangeClassificationLevel(bpy.types.Operator):
parent_id: bpy.props.IntProperty() parent_id: bpy.props.IntProperty()
def execute(self, context): def execute(self, context):
props = context.scene.BIMClassificationProperties props = tool.Classification.get_classification_props()
props.available_library_references.clear() props.available_library_references.clear()
for reference in IfcStore.classification_file.by_id(self.parent_id).HasReferences: for reference in IfcStore.classification_file.by_id(self.parent_id).HasReferences:
new = props.available_library_references.add() new = props.available_library_references.add()
@@ -509,6 +509,6 @@ class DisableEditingClassificationReferences(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context): def execute(self, context):
props = context.scene.BIMClassificationProperties props = tool.Classification.get_classification_props()
props.available_library_references.clear() props.available_library_references.clear()
return {"FINISHED"} return {"FINISHED"}
@@ -17,6 +17,7 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>. # along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy import bpy
import bonsai.tool as tool
from bonsai.bim.prop import Attribute from bonsai.bim.prop import Attribute
from bonsai.bim.module.classification.data import ClassificationsData, ClassificationReferencesData from bonsai.bim.module.classification.data import ClassificationsData, ClassificationReferencesData
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
@@ -30,9 +31,12 @@ from bpy.props import (
FloatVectorProperty, FloatVectorProperty,
CollectionProperty, CollectionProperty,
) )
from typing import TYPE_CHECKING
def get_available_classifications(self, context): def get_available_classifications(
self: "BIMClassificationProperties", context: bpy.types.Context
) -> tool.Blender.BLENDER_ENUM_ITEMS:
if not ClassificationsData.is_loaded: if not ClassificationsData.is_loaded:
ClassificationsData.load() ClassificationsData.load()
return ClassificationsData.data["available_classifications"] return ClassificationsData.data["available_classifications"]
@@ -44,19 +48,26 @@ def get_classifications(self, context):
return ClassificationReferencesData.data["classifications"] return ClassificationReferencesData.data["classifications"]
def get_classification_source(self, context): def get_classification_source(
self: "BIMClassificationProperties", context: bpy.types.Context
) -> tool.Blender.BLENDER_ENUM_ITEMS:
if not ClassificationsData.is_loaded: if not ClassificationsData.is_loaded:
ClassificationsData.load() ClassificationsData.load()
return ClassificationsData.data["classification_source"] return ClassificationsData.data["classification_source"]
class ClassificationReference(PropertyGroup): class ClassificationReference(PropertyGroup):
name: StringProperty(name="Name")
identification: StringProperty(name="Identification") identification: StringProperty(name="Identification")
ifc_definition_id: IntProperty(name="IFC Definition ID") ifc_definition_id: IntProperty(name="IFC Definition ID")
has_references: BoolProperty(name="Has References") has_references: BoolProperty(name="Has References")
referenced_source: IntProperty(name="IFC Definition ID") referenced_source: IntProperty(name="IFC Definition ID")
if TYPE_CHECKING:
identification: str
ifc_definition_id: int
has_references: bool
referenced_source: int
class BIMClassificationProperties(PropertyGroup): class BIMClassificationProperties(PropertyGroup):
is_adding: BoolProperty(name="Is Adding", default=False) is_adding: BoolProperty(name="Is Adding", default=False)
@@ -68,9 +79,25 @@ class BIMClassificationProperties(PropertyGroup):
active_library_referenced_source: IntProperty(name="Active Library Referenced Source") active_library_referenced_source: IntProperty(name="Active Library Referenced Source")
active_library_reference_index: IntProperty(name="Active Library Reference Index") active_library_reference_index: IntProperty(name="Active Library Reference Index")
if TYPE_CHECKING:
is_adding: bool
classification_source: str
available_classifications: str
classification_attributes: bpy.types.bpy_prop_collection_idprop[Attribute]
active_classification_id: int
available_library_references: bpy.types.bpy_prop_collection_idprop[ClassificationReference]
active_library_referenced_source: int
active_library_reference_index: int
class BIMClassificationReferenceProperties(PropertyGroup): class BIMClassificationReferenceProperties(PropertyGroup):
is_adding: BoolProperty(name="Is Adding", default=False) is_adding: BoolProperty(name="Is Adding", default=False)
classifications: EnumProperty(items=get_classifications, name="Classifications") classifications: EnumProperty(items=get_classifications, name="Classifications")
reference_attributes: CollectionProperty(name="Reference Attributes", type=Attribute) reference_attributes: CollectionProperty(name="Reference Attributes", type=Attribute)
active_reference_id: IntProperty(name="Active Reference Id") active_reference_id: IntProperty(name="Active Reference Id")
if TYPE_CHECKING:
is_adding: bool
classifications: str
reference_attributes: bpy.types.bpy_prop_collection_idprop
active_reference_id: int
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>. # along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy import bpy
import bonsai.bim.helper import bonsai.bim.helper
import bonsai.tool as tool import bonsai.tool as tool
@@ -27,6 +28,10 @@ from bonsai.bim.module.classification.data import (
MaterialClassificationsData, MaterialClassificationsData,
CostClassificationsData, CostClassificationsData,
) )
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from bonsai.bim.module.classification.prop import BIMClassificationProperties, ClassificationReference
class BIM_PT_classifications(Panel): class BIM_PT_classifications(Panel):
@@ -46,7 +51,8 @@ class BIM_PT_classifications(Panel):
if not ClassificationsData.is_loaded: if not ClassificationsData.is_loaded:
ClassificationsData.load() ClassificationsData.load()
self.props = context.scene.BIMClassificationProperties self.props = tool.Classification.get_classification_props()
assert self.layout
row = self.layout.row(align=True) row = self.layout.row(align=True)
row.label(text="Source", icon="OUTLINER") row.label(text="Source", icon="OUTLINER")
@@ -110,9 +116,9 @@ class ReferenceUI:
def draw_ui(self, context): def draw_ui(self, context):
obj = context.active_object obj = context.active_object
self.sprops = context.scene.BIMClassificationProperties self.sprops = tool.Classification.get_classification_props()
self.bprops = context.scene.BIMBSDDProperties self.bprops = tool.Bsdd.get_bsdd_props()
self.props = context.scene.BIMClassificationReferenceProperties self.props = tool.Classification.get_classification_reference_props()
self.file = tool.Ifc.get() self.file = tool.Ifc.get()
self.draw_add_ui(context) self.draw_add_ui(context)
@@ -315,7 +321,16 @@ class BIM_PT_cost_classifications(Panel, ReferenceUI):
class BIM_UL_classifications(UIList): class BIM_UL_classifications(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname): def draw_item(
self,
context,
layout: bpy.types.UILayout,
data: BIMClassificationProperties,
item: ClassificationReference,
icon,
active_data,
active_propname,
):
if item: if item:
if item.has_references: if item.has_references:
op = layout.operator("bim.change_classification_level", text="", icon="DISCLOSURE_TRI_RIGHT") op = layout.operator("bim.change_classification_level", text="", icon="DISCLOSURE_TRI_RIGHT")
+1 -1
View File
@@ -255,7 +255,7 @@ class BIM_PT_object_psets(Panel):
ObjectPsetsData.load() ObjectPsetsData.load()
props = context.active_object.PsetProperties props = context.active_object.PsetProperties
self.bprops = context.scene.BIMBSDDProperties self.bprops = tool.Bsdd.get_bsdd_props()
row = self.layout.row(align=True) row = self.layout.row(align=True)
prop_with_search(row, props, "pset_name", text="") prop_with_search(row, props, "pset_name", text="")
if props.pset_name != "BBIM_BSDD" and not props.pset_name.startswith(tool.Bsdd.identifier_url): if props.pset_name != "BBIM_BSDD" and not props.pset_name.startswith(tool.Bsdd.identifier_url):
+4 -4
View File
@@ -26,20 +26,20 @@ if TYPE_CHECKING:
import bonsai.tool as tool import bonsai.tool as tool
def import_bsdd_classes(bsdd: tool.Bsdd, obj, obj_type) -> int: def import_bsdd_classes(bsdd: type[tool.Bsdd], obj, obj_type) -> int:
return bsdd.import_classes(obj, obj_type) return bsdd.import_classes(obj, obj_type)
def search_bsdd_properties(bsdd: tool.Bsdd, keyword: str, obj, obj_type) -> int: def search_bsdd_properties(bsdd: type[tool.Bsdd], keyword: str, obj, obj_type) -> int:
return bsdd.import_properties(obj, obj_type, keyword) return bsdd.import_properties(obj, obj_type, keyword)
def load_bsdd(bsdd: tool.Bsdd) -> None: def load_bsdd(bsdd: type[tool.Bsdd]) -> None:
bsdd.clear_dictionaries() bsdd.clear_dictionaries()
bsdd.create_dictionaries(bsdd.get_dictionaries()) bsdd.create_dictionaries(bsdd.get_dictionaries())
def search_bsdd_class(bsdd: tool.Bsdd, keyword: str) -> int: def search_bsdd_class(bsdd: type[tool.Bsdd], keyword: str) -> int:
bsdd.clear_classes() bsdd.clear_classes()
related_entities = bsdd.get_related_ifc_entities() related_entities = bsdd.get_related_ifc_entities()
return bsdd.search_class(keyword, related_entities) return bsdd.search_class(keyword, related_entities)
+30 -16
View File
@@ -32,7 +32,11 @@ if TYPE_CHECKING:
def unjoin_walls( def unjoin_walls(
ifc: tool.Ifc, blender: tool.Blender, geometry: tool.Geometry, joiner: DumbWallJoiner, model: tool.Model ifc: type[tool.Ifc],
blender: type[tool.Blender],
geometry: type[tool.Geometry],
joiner: DumbWallJoiner,
model: type[tool.Model],
) -> None: ) -> None:
"""Unjoin selected walls.""" """Unjoin selected walls."""
for obj in blender.get_selected_objects(): for obj in blender.get_selected_objects():
@@ -45,11 +49,11 @@ def unjoin_walls(
def extend_walls( def extend_walls(
ifc: tool.Ifc, ifc: type[tool.Ifc],
blender: tool.Blender, blender: type[tool.Blender],
geometry: tool.Geometry, geometry: type[tool.Geometry],
joiner: DumbWallJoiner, joiner: DumbWallJoiner,
model: tool.Model, model: type[tool.Model],
target: Vector, target: Vector,
connection: Optional[str] = None, connection: Optional[str] = None,
) -> None: ) -> None:
@@ -62,11 +66,11 @@ def extend_walls(
def join_walls_LV( def join_walls_LV(
ifc: tool.Ifc, ifc: type[tool.Ifc],
blender: tool.Blender, blender: type[tool.Blender],
geometry: tool.Geometry, geometry: type[tool.Geometry],
joiner: DumbWallJoiner, joiner: DumbWallJoiner,
model: tool.Model, model: type[tool.Model],
join_type: Literal["L", "V"] = "L", join_type: Literal["L", "V"] = "L",
) -> None: ) -> None:
selected_objs = [ selected_objs = [
@@ -86,7 +90,7 @@ def join_walls_LV(
joiner.connect(another_selected_object, active_obj) joiner.connect(another_selected_object, active_obj)
def offset_walls(ifc: tool.Ifc, blender: tool.Blender, model: tool.Model, offset_type: OffsetType): def offset_walls(ifc: type[tool.Ifc], blender: type[tool.Blender], model: type[tool.Model], offset_type: OffsetType):
objs = [ objs = [
obj obj
for obj in blender.get_selected_objects() for obj in blender.get_selected_objects()
@@ -98,7 +102,11 @@ def offset_walls(ifc: tool.Ifc, blender: tool.Blender, model: tool.Model, offset
def align_walls( def align_walls(
ifc: tool.Ifc, blender: tool.Blender, model: tool.Model, aligner: DumbWallAligner, align_type: AlignType ifc: type[tool.Ifc],
blender: type[tool.Blender],
model: type[tool.Model],
aligner: DumbWallAligner,
align_type: AlignType,
): ):
reference_obj = blender.get_active_object(is_selected=True) reference_obj = blender.get_active_object(is_selected=True)
if not (e := ifc.get_entity(reference_obj) or not model.get_usage_type(e) == "LAYER2"): if not (e := ifc.get_entity(reference_obj) or not model.get_usage_type(e) == "LAYER2"):
@@ -122,7 +130,9 @@ def align_walls(
aligner.align_last_layer(obj) aligner.align_last_layer(obj)
def align_objects(blender: tool.Blender, model: tool.Model, align_type: Literal["CENTER", "POSITIVE", "NEGATIVE"]): def align_objects(
blender: type[tool.Blender], model: type[tool.Model], align_type: Literal["CENTER", "POSITIVE", "NEGATIVE"]
):
reference_obj = blender.get_active_object(is_selected=True) reference_obj = blender.get_active_object(is_selected=True)
objs = [o for o in blender.get_selected_objects() if o != reference_obj] objs = [o for o in blender.get_selected_objects() if o != reference_obj]
if not reference_obj or not objs: if not reference_obj or not objs:
@@ -131,9 +141,9 @@ def align_objects(blender: tool.Blender, model: tool.Model, align_type: Literal[
def extend_wall_to_slab( def extend_wall_to_slab(
ifc: tool.Ifc, ifc: type[tool.Ifc],
geometry: tool.Geometry, geometry: type[tool.Geometry],
model: tool.Model, model: type[tool.Model],
slab_obj: bpy.types.Object, slab_obj: bpy.types.Object,
wall_objs: list[bpy.types.Object], wall_objs: list[bpy.types.Object],
) -> None: ) -> None:
@@ -150,7 +160,11 @@ def extend_wall_to_slab(
def join_walls_TZ( def join_walls_TZ(
ifc: tool.Ifc, blender: tool.Blender, geometry: tool.Geometry, joiner: DumbWallJoiner, model: tool.Model ifc: type[tool.Ifc],
blender: type[tool.Blender],
geometry: type[tool.Geometry],
joiner: DumbWallJoiner,
model: type[tool.Model],
) -> None: ) -> None:
selected_objs = [ selected_objs = [
o o
+38 -15
View File
@@ -1,3 +1,22 @@
# Bonsai - OpenBIM Blender Add-on
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
#
# This file is part of Bonsai.
#
# Bonsai is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Bonsai is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bonsai.core.tool import bonsai.core.tool
import bonsai.tool as tool import bonsai.tool as tool
import bpy import bpy
@@ -8,6 +27,9 @@ import ifcopenshell.util.element
import ifcopenshell.util.classification import ifcopenshell.util.classification
from typing import Any, Union, Optional, TYPE_CHECKING from typing import Any, Union, Optional, TYPE_CHECKING
if TYPE_CHECKING:
from bonsai.bim.module.bsdd.prop import BIMBSDDProperties
class Bsdd(bonsai.core.tool.Bsdd): class Bsdd(bonsai.core.tool.Bsdd):
identifier_url = "https://identifier.buildingsmart.org" identifier_url = "https://identifier.buildingsmart.org"
@@ -16,28 +38,29 @@ class Bsdd(bonsai.core.tool.Bsdd):
bsdd_properties: dict[str, dict] = {} bsdd_properties: dict[str, dict] = {}
@classmethod @classmethod
def get_bsdd_props(cls): def get_bsdd_props(cls) -> BIMBSDDProperties:
return bpy.context.scene.BIMBSDDProperties assert (scene := bpy.context.scene)
return scene.BIMBSDDProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod @classmethod
def clear_class_psets(cls) -> None: def clear_class_psets(cls) -> None:
bpy.context.scene.BIMBSDDProperties.classification_psets.clear() cls.get_bsdd_props().classification_psets.clear()
@classmethod @classmethod
def clear_classes(cls) -> None: def clear_classes(cls) -> None:
bpy.context.scene.BIMBSDDProperties.classifications.clear() cls.get_bsdd_props().classifications.clear()
@classmethod @classmethod
def clear_properties(cls) -> None: def clear_properties(cls) -> None:
bpy.context.scene.BIMBSDDProperties.properties.clear() cls.get_bsdd_props().properties.clear()
@classmethod @classmethod
def clear_dictionaries(cls) -> None: def clear_dictionaries(cls) -> None:
bpy.context.scene.BIMBSDDProperties.dictionaries.clear() cls.get_bsdd_props().dictionaries.clear()
@classmethod @classmethod
def create_class_psets(cls, pset_dict: dict[str, dict[str, Any]]) -> None: def create_class_psets(cls, pset_dict: dict[str, dict[str, Any]]) -> None:
props = bpy.context.scene.BIMBSDDProperties props = cls.get_bsdd_props()
data_type_map = { data_type_map = {
"String": "string", "String": "string",
"Real": "float", "Real": "float",
@@ -60,7 +83,7 @@ class Bsdd(bonsai.core.tool.Bsdd):
@classmethod @classmethod
def create_dictionaries(cls, dictionaries: list[bsdd.DictionaryContractV1]) -> None: def create_dictionaries(cls, dictionaries: list[bsdd.DictionaryContractV1]) -> None:
props = bpy.context.scene.BIMBSDDProperties props = cls.get_bsdd_props()
for dictionary in sorted(dictionaries, key=lambda d: d["name"]): for dictionary in sorted(dictionaries, key=lambda d: d["name"]):
new = props.dictionaries.add() new = props.dictionaries.add()
new.name = dictionary["name"] new.name = dictionary["name"]
@@ -72,7 +95,7 @@ class Bsdd(bonsai.core.tool.Bsdd):
@classmethod @classmethod
def get_active_class_data(cls) -> Union[bsdd.ClassContractV1, dict]: def get_active_class_data(cls) -> Union[bsdd.ClassContractV1, dict]:
prop = bpy.context.scene.BIMBSDDProperties prop = cls.get_bsdd_props()
bsdd_classification = prop.classifications[prop.active_classification_index] bsdd_classification = prop.classifications[prop.active_classification_index]
if not bsdd_classification: if not bsdd_classification:
return {} return {}
@@ -80,18 +103,18 @@ class Bsdd(bonsai.core.tool.Bsdd):
@classmethod @classmethod
def get_active_dictionary_uri(cls) -> str: def get_active_dictionary_uri(cls) -> str:
return bpy.context.scene.BIMBSDDProperties.active_uri return cls.get_bsdd_props().active_uri
@classmethod @classmethod
def get_dictionary(cls, uri: str) -> bsdd.DictionaryContractV1: def get_dictionary(cls, uri: str) -> bsdd.DictionaryContractV1:
props = bpy.context.scene.BIMBSDDProperties props = cls.get_bsdd_props()
response = cls.client.get_dictionary(dictionary_uri=uri, include_test_dictionaries=props.load_test_dictionaries) response = cls.client.get_dictionary(dictionary_uri=uri, include_test_dictionaries=props.load_test_dictionaries)
if dicts := response.get("dictionaries"): if dicts := response.get("dictionaries"):
return dicts[0] return dicts[0]
@classmethod @classmethod
def get_dictionaries(cls) -> list[bsdd.DictionaryContractV1]: def get_dictionaries(cls) -> list[bsdd.DictionaryContractV1]:
props = bpy.context.scene.BIMBSDDProperties props = cls.get_bsdd_props()
response = cls.client.get_dictionary(include_test_dictionaries=props.load_test_dictionaries) response = cls.client.get_dictionary(include_test_dictionaries=props.load_test_dictionaries)
dicts = response.get("dictionaries") or [] dicts = response.get("dictionaries") or []
statuses = ["Active"] statuses = ["Active"]
@@ -165,7 +188,7 @@ class Bsdd(bonsai.core.tool.Bsdd):
limit: int = 100, limit: int = 100,
should_paginate: bool = True, should_paginate: bool = True,
): ):
cprops = bpy.context.scene.BIMClassificationProperties cprops = tool.Classification.get_classification_props()
bprops = cls.get_bsdd_props() bprops = cls.get_bsdd_props()
dictionary_uris = ( dictionary_uris = (
[d.uri for d in bprops.dictionaries if d.is_active] [d.uri for d in bprops.dictionaries if d.is_active]
@@ -202,13 +225,13 @@ class Bsdd(bonsai.core.tool.Bsdd):
@classmethod @classmethod
def set_active_bsdd(cls, name: str, uri: str) -> None: def set_active_bsdd(cls, name: str, uri: str) -> None:
props = bpy.context.scene.BIMBSDDProperties props = cls.get_bsdd_props()
props.active_dictionary = name props.active_dictionary = name
props.active_uri = uri props.active_uri = uri
@classmethod @classmethod
def should_filter_ifc_class(cls) -> bool: def should_filter_ifc_class(cls) -> bool:
return bpy.context.scene.BIMBSDDProperties.should_filter_ifc_class return cls.get_bsdd_props().should_filter_ifc_class
@classmethod @classmethod
def get_bsdd_class(cls, uri: str) -> dict: def get_bsdd_class(cls, uri: str) -> dict:
+14 -1
View File
@@ -22,10 +22,23 @@ import ifcopenshell.api
import ifcopenshell.util.classification import ifcopenshell.util.classification
import bonsai.core.tool import bonsai.core.tool
import bonsai.tool as tool import bonsai.tool as tool
from typing import Union, assert_never from typing import Union, assert_never, TYPE_CHECKING
if TYPE_CHECKING:
from bonsai.bim.module.classification.prop import BIMClassificationReferenceProperties, BIMClassificationProperties
class Classification(bonsai.core.tool.Classification): class Classification(bonsai.core.tool.Classification):
@classmethod
def get_classification_props(cls) -> BIMClassificationProperties:
assert (scene := bpy.context.scene)
return scene.BIMClassificationProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod
def get_classification_reference_props(cls) -> BIMClassificationReferenceProperties:
assert (scene := bpy.context.scene)
return scene.BIMClassificationReferenceProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod @classmethod
def get_location(cls, classification: ifcopenshell.entity_instance) -> Union[str, None]: def get_location(cls, classification: ifcopenshell.entity_instance) -> Union[str, None]:
schema = classification.file.schema schema = classification.file.schema
+6 -6
View File
@@ -46,8 +46,8 @@ class TestAddClassificationReferenceFromBSDD(NewFile):
bpy.ops.bim.load_bsdd_domains() bpy.ops.bim.load_bsdd_domains()
uri = "https://identifier.buildingsmart.org/uri/molio/cciconstruction/1.0" uri = "https://identifier.buildingsmart.org/uri/molio/cciconstruction/1.0"
bpy.ops.bim.set_active_bsdd_domain(name="CCI Construction", uri=uri) bpy.ops.bim.set_active_bsdd_domain(name="CCI Construction", uri=uri)
props = context.scene.BIMBSDDProperties props = tool.Bsdd.get_bsdd_props()
bpy.context.scene.BIMClassificationProperties.classification_source = "BSDD" tool.Classification.get_classification_props().classification_source = "BSDD"
props.should_filter_ifc_class = True props.should_filter_ifc_class = True
props.keyword = "Room" props.keyword = "Room"
bpy.ops.bim.search_bsdd_classifications() bpy.ops.bim.search_bsdd_classifications()
@@ -70,8 +70,8 @@ class TestAddClassificationReferenceFromBSDD(NewFile):
bpy.ops.bim.load_bsdd_domains() bpy.ops.bim.load_bsdd_domains()
uri = "https://identifier.buildingsmart.org/uri/molio/cciconstruction/1.0" uri = "https://identifier.buildingsmart.org/uri/molio/cciconstruction/1.0"
bpy.ops.bim.set_active_bsdd_domain(name="CCI Construction", uri=uri) bpy.ops.bim.set_active_bsdd_domain(name="CCI Construction", uri=uri)
props = context.scene.BIMBSDDProperties props = tool.Bsdd.get_bsdd_props()
bpy.context.scene.BIMClassificationProperties.classification_source = "BSDD" tool.Classification.get_classification_props().classification_source = "BSDD"
props.should_filter_ifc_class = True props.should_filter_ifc_class = True
props.keyword = "Room" props.keyword = "Room"
bpy.ops.bim.search_bsdd_classifications() bpy.ops.bim.search_bsdd_classifications()
@@ -103,12 +103,12 @@ class TestAddClassificationReferenceFromBSDD(NewFile):
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
assert element assert element
props = context.scene.BIMBSDDProperties props = tool.Bsdd.get_bsdd_props()
props.load_preview_domains = True props.load_preview_domains = True
bpy.ops.bim.load_bsdd_domains() bpy.ops.bim.load_bsdd_domains()
uri = "https://identifier.buildingsmart.org/uri/ifcairport/ifcairport/0.9" uri = "https://identifier.buildingsmart.org/uri/ifcairport/ifcairport/0.9"
bpy.ops.bim.set_active_bsdd_domain(name="IFC Airport", uri=uri) bpy.ops.bim.set_active_bsdd_domain(name="IFC Airport", uri=uri)
bpy.context.scene.BIMClassificationProperties.classification_source = "BSDD" tool.Classification.get_classification_props().classification_source = "BSDD"
props.should_filter_ifc_class = False # Important due to class mismatch. props.should_filter_ifc_class = False # Important due to class mismatch.
props.keyword = "check-in conveyor" props.keyword = "check-in conveyor"
bpy.ops.bim.search_bsdd_classifications() bpy.ops.bim.search_bsdd_classifications()
+1 -1
View File
@@ -540,7 +540,7 @@ class TestSetupActiveBsddClassification(NewFile):
filepath = "test/files/temp/test.ifc" filepath = "test/files/temp/test.ifc"
ifc_file.write(filepath) ifc_file.write(filepath)
bpy.ops.bim.load_project(filepath=filepath) bpy.ops.bim.load_project(filepath=filepath)
props = bpy.context.scene.BIMBSDDProperties props = tool.Bsdd.get_bsdd_props()
assert props.active_domain == name assert props.active_domain == name
assert props.active_uri == base_uri assert props.active_uri == base_uri
@@ -351,19 +351,18 @@ def log_internal_cpp_errors(f: ifcopenshell.file, filename: str, logger: Logger)
logger.error(m) logger.error(m)
entity_attribute_map: dict[tuple[str, str], tuple[entity_type, tuple[attribute]]] = {} entity_attribute_map: dict[tuple[str, str], tuple[entity_type, tuple[attribute, ...]]] = {}
def get_entity_attributes(schema: schema_definition, entity: str) -> tuple[entity_type, tuple[attribute]]: def get_entity_attributes(schema: schema_definition, entity: str) -> tuple[entity_type, tuple[attribute, ...]]:
cache_key = schema.name(), entity cache_key = schema.name(), entity
from_cache = entity_attribute_map.get(cache_key) from_cache = entity_attribute_map.get(cache_key)
if from_cache: if from_cache:
return from_cache return from_cache
entity_attrs = ( ent = schema.declaration_by_name(entity).as_entity()
ent := schema.declaration_by_name(entity), assert ent
ent.all_attributes(), entity_attrs = (ent, ent.all_attributes())
)
entity_attribute_map[cache_key] = entity_attrs entity_attribute_map[cache_key] = entity_attrs
return entity_attrs return entity_attrs
+6 -5
View File
@@ -17,12 +17,14 @@
# along with IfcPatch. If not, see <http://www.gnu.org/licenses/>. # along with IfcPatch. If not, see <http://www.gnu.org/licenses/>.
import ifcopenshell import ifcopenshell
import ifcopenshell.guid
import ifcopenshell.util.element import ifcopenshell.util.element
import ifcpatch
import logging
from typing import Union
class Patcher: class Patcher(ifcpatch.BasePatcher):
def __init__(self, file, logger): def __init__(self, file: ifcopenshell.file, logger: Union[logging.Logger, None] = None):
"""Merge identical styles together """Merge identical styles together
Some software may create an obscene number of styles instead of reusing Some software may create an obscene number of styles instead of reusing
@@ -35,8 +37,7 @@ class Patcher:
ifcpatch.execute({"file": model, "recipe": "MergeStyles", "arguments": []}) ifcpatch.execute({"file": model, "recipe": "MergeStyles", "arguments": []})
""" """
self.file = file super().__init__(file, logger)
self.logger = logger
def patch(self): def patch(self):
for ifc_class in ("IfcColourRgb", "IfcSurfaceStyleShading", "IfcPresentationStyle"): for ifc_class in ("IfcColourRgb", "IfcSurfaceStyleShading", "IfcPresentationStyle"):