This commit is contained in:
Andrej730
2025-04-28 13:27:30 +05:00
parent f9a0081b33
commit 10f84537de
6 changed files with 38 additions and 29 deletions
+11 -12
View File
@@ -38,7 +38,7 @@ import ifcopenshell.util.shape
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore, IFC_CONNECTED_TYPE
from bonsai.tool.loader import OBJECT_DATA_TYPE
from typing import Dict, Union, Optional, Any, Literal
from typing import Dict, Union, Optional, Any, Literal, Iterable
from ifcopenshell.util.shape import MatrixType
@@ -319,16 +319,15 @@ class IfcImporter:
tool.Loader.settings.gross_context_settings = tool.Loader.create_settings(is_gross=True)
def process_element_filter(self) -> None:
elements: list[ifcopenshell.entity_instance]
if self.ifc_import_settings.has_filter:
self.elements = self.ifc_import_settings.elements
if isinstance(self.elements, set):
self.elements = list(self.elements)
elements = list(self.ifc_import_settings.elements)
# TODO: enable filtering for annotations
else:
if self.file.schema in ("IFC2X3", "IFC4"):
self.elements = self.file.by_type("IfcElement") + self.file.by_type("IfcProxy")
elements = self.file.by_type("IfcElement") + self.file.by_type("IfcProxy")
else:
self.elements = self.file.by_type("IfcElement")
elements = self.file.by_type("IfcElement")
drawing_groups = [g for g in self.file.by_type("IfcGroup") if g.ObjectType == "DRAWING"]
drawing_annotations = set()
@@ -338,16 +337,16 @@ class IfcImporter:
self.annotations = set([a for a in self.file.by_type("IfcAnnotation")])
self.annotations -= drawing_annotations
self.elements = [e for e in self.elements if not e.is_a("IfcFeatureElement") or e.is_a("IfcSurfaceFeature")]
elements = [e for e in elements if not e.is_a("IfcFeatureElement") or e.is_a("IfcSurfaceFeature")]
if self.ifc_import_settings.element_limit_mode == "UNLIMITED":
self.elements = set(self.elements)
self.elements = set(elements)
else:
offset = self.ifc_import_settings.element_offset
offset_limit = offset + self.ifc_import_settings.element_limit
self.elements = set(self.elements[offset:offset_limit])
self.elements = set(elements[offset:offset_limit])
if self.ifc_import_settings.has_filter or self.ifc_import_settings.element_limit_mode != "UNLIMITED":
self.element_types = set([ifcopenshell.util.element.get_type(e) for e in self.elements])
self.element_types = {t for e in self.elements if (t := ifcopenshell.util.element.get_type(e))}
else:
self.element_types = set(self.file.by_type("IfcTypeProduct"))
@@ -1168,13 +1167,13 @@ class IfcImportSettings:
self.element_limit_mode = "UNLIMITED"
self.element_offset = 0
self.element_limit = 30000
self.has_filter = None
self.has_filter = False
self.should_filter_spatial_elements = True
self.should_setup_viewport_camera = True
self.contexts: list[ifcopenshell.entity_instance] = []
self.context_settings: list[ifcopenshell.geom.main.settings] = []
self.gross_context_settings: list[ifcopenshell.geom.main.settings] = []
self.elements: set[ifcopenshell.entity_instance] = set()
self.elements: Iterable[ifcopenshell.entity_instance] = set()
self.load_indexed_maps = False
@staticmethod
@@ -1736,13 +1736,14 @@ class OverrideJoin(bpy.types.Operator, tool.Ifc.Operator):
)
def join_blender_obj(self) -> None:
ifc_file = tool.Ifc.get()
for obj in bpy.context.selected_objects:
if obj == self.target:
continue
# TODO Properly handle element types, grid axes, and representation items
element = tool.Ifc.get_entity(obj)
if element:
ifcopenshell.api.run("root.remove_product", tool.Ifc.get(), product=element)
ifcopenshell.api.root.remove_product(ifc_file, product=element)
bpy.ops.object.join()
@@ -162,6 +162,11 @@ class RepresentationItemObject(PropertyGroup):
obj: PointerProperty(type=bpy.types.Object)
ifc_definition_id: IntProperty()
if TYPE_CHECKING:
name: str
obj: Union[bpy.types.Object, None]
ifc_definition_id: int
class ShapeAspect(PropertyGroup):
name: StringProperty(
@@ -1103,8 +1103,8 @@ class LoadProjectElements(bpy.types.Operator):
bonsai.bim.handler.refresh_ui_data()
return {"FINISHED"}
def get_decomposition_elements(self):
containers = set()
def get_decomposition_elements(self) -> set[ifcopenshell.entity_instance]:
containers: set[ifcopenshell.entity_instance] = set()
for filter_category in self.props.filter_categories:
if not filter_category.is_selected:
continue
@@ -1116,15 +1116,15 @@ class LoadProjectElements(bpy.types.Operator):
container = None
elif self.file.schema != "IFC2X3" and container.is_a("IfcContext"):
container = None
elements = set()
elements: set[ifcopenshell.entity_instance] = set()
for container in containers:
for rel in container.ContainsElements:
elements.update(rel.RelatedElements)
self.append_decomposed_elements(elements)
return elements
def append_decomposed_elements(self, elements):
decomposed_elements = set()
def append_decomposed_elements(self, elements: set[ifcopenshell.entity_instance]) -> None:
decomposed_elements: set[ifcopenshell.entity_instance] = set()
for element in elements:
if element.IsDecomposedBy:
for subelement in element.IsDecomposedBy[0].RelatedObjects:
@@ -1133,26 +1133,26 @@ class LoadProjectElements(bpy.types.Operator):
self.append_decomposed_elements(decomposed_elements)
elements.update(decomposed_elements)
def get_ifc_class_elements(self):
elements = set()
def get_ifc_class_elements(self) -> set[ifcopenshell.entity_instance]:
elements: set[ifcopenshell.entity_instance] = set()
for filter_category in self.props.filter_categories:
if not filter_category.is_selected:
continue
elements.update(self.file.by_type(filter_category.name, include_subtypes=False))
return elements
def get_ifc_type_elements(self):
elements = set()
def get_ifc_type_elements(self) -> set[ifcopenshell.entity_instance]:
elements: set[ifcopenshell.entity_instance] = set()
for filter_category in self.props.filter_categories:
if not filter_category.is_selected:
continue
elements.update(ifcopenshell.util.element.get_types(self.file.by_id(filter_category.ifc_definition_id)))
return elements
def get_whitelist_elements(self):
def get_whitelist_elements(self) -> set[ifcopenshell.entity_instance]:
return set(ifcopenshell.util.selector.filter_elements(self.file, self.props.filter_query))
def get_blacklist_elements(self):
def get_blacklist_elements(self) -> set[ifcopenshell.entity_instance]:
return set(self.file.by_type("IfcElement")) - set(
ifcopenshell.util.selector.filter_elements(self.file, self.props.filter_query)
)
+8 -4
View File
@@ -67,6 +67,7 @@ from typing import (
Generator,
cast,
TypeGuard,
Any,
)
from typing_extensions import TypeIs
@@ -1861,6 +1862,7 @@ class Geometry(bonsai.core.tool.Geometry):
tool.Blender.set_active_object(props.representation_obj)
cls.sync_item_positions()
representation = cls.get_active_representation(props.representation_obj)
assert representation
ifcopenshell.api.geometry.validate_type(tool.Ifc.get(), representation)
props.is_changing_mode = True
if props.mode != "OBJECT":
@@ -1873,6 +1875,7 @@ class Geometry(bonsai.core.tool.Geometry):
def edit_meshlike_item(cls, obj: bpy.types.Object) -> None:
item = tool.Geometry.get_active_representation(obj)
assert item
assert isinstance(obj.data, (bpy.types.Curve, bpy.types.Mesh))
mprops = tool.Geometry.get_mesh_props(obj.data)
if mprops.mesh_checksum == cls.get_mesh_checksum(obj.data):
return
@@ -1898,7 +1901,7 @@ class Geometry(bonsai.core.tool.Geometry):
ifcopenshell.util.element.replace_attribute(inverse, item, new_item)
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), item)
tool.Ifc.link(new_item, obj.data)
cls.reload_representation(props.representation_obj)
cls.reload_representation(rep_obj)
@classmethod
def split_by_loose_parts(cls, obj: bpy.types.Object) -> List[bpy.types.Mesh]:
@@ -2130,7 +2133,6 @@ class Geometry(bonsai.core.tool.Geometry):
tool.Root.reload_grid_decorator()
return old_to_new, new_active_obj or active_object
@classmethod
def duplicate_ifc_item(cls, obj: bpy.types.Object) -> None:
props = tool.Geometry.get_geometry_props()
@@ -2148,11 +2150,13 @@ class Geometry(bonsai.core.tool.Geometry):
for collection in obj.users_collection:
collection.objects.link(new_obj)
representation = tool.Geometry.get_active_representation(props.representation_obj)
assert (rep_obj := props.representation_obj)
representation = tool.Geometry.get_active_representation(rep_obj)
assert representation
representation = ifcopenshell.util.representation.resolve_representation(representation)
representation.Items = list(representation.Items) + [new_item]
tool.Geometry.reload_representation(props.representation_obj)
tool.Geometry.reload_representation(rep_obj)
obj.select_set(False)
tool.Root.reload_item_decorator()
@@ -47,7 +47,7 @@ def validate_type(
combination, or False otherwise.
"""
def is_operand(item):
def is_operand(item: ifcopenshell.entity_instance) -> bool:
return (
item.is_a("IfcBooleanResult")
or item.is_a("IfcCsgPrimitive3D")