Use relevant tool.Geometry functions for querying openings relations

This commit is contained in:
Gorgious56
2025-01-03 12:22:08 +01:00
parent 25af639dae
commit e933ff08f8
5 changed files with 65 additions and 67 deletions
+55 -53
View File
@@ -357,7 +357,7 @@ class FilledOpeningGenerator:
return shape_builder.get_representation(context, [extrusion])
def has_visible_openings(self, element):
for opening in [r.RelatedOpeningElement for r in element.HasOpenings]:
for opening in [r.RelatedOpeningElement for r in tool.Geometry.get_openings(element)]:
if tool.Ifc.get_object(opening):
return True
return False
@@ -496,7 +496,7 @@ class AddPotentialOpening(Operator, AddObjectHelper):
if new_matrix:
obj.matrix_world = new_matrix
tool.Model.clear_scene_openings()
tool.Model.purge_scene_openings()
new = props.openings.add()
new.obj = obj
@@ -523,7 +523,7 @@ class AddPotentialHalfSpaceSolid(Operator, AddObjectHelper):
obj = object_data_add(context, mesh, operator=self)
obj.name = "HalfSpaceSolid"
tool.Model.clear_scene_openings()
tool.Model.purge_scene_openings()
new = props.openings.add()
new.obj = obj
@@ -574,7 +574,7 @@ class AddBoolean(Operator, tool.Ifc.Operator):
)
tool.Model.mark_manual_booleans(element1, booleans)
tool.Model.clear_scene_openings()
tool.Model.purge_scene_openings()
bonsai.core.geometry.switch_representation(
tool.Ifc,
@@ -628,7 +628,7 @@ class ShowBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
booleans.extend(self.get_booleans(item))
props = bpy.context.scene.BIMModelProperties
tool.Model.clear_scene_openings()
tool.Model.purge_scene_openings()
existing_booleans = {
boolean_obj.data.BIMMeshProperties.ifc_boolean_id: boolean_obj
@@ -763,7 +763,7 @@ class HideBooleans(Operator, tool.Ifc.Operator):
objects_to_remove.add(obj)
tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True)
tool.Model.clear_scene_openings()
tool.Model.purge_scene_openings()
if set_active_obj and set_selected_objs is not None:
tool.Blender.set_objects_selection(context, set_active_obj, set_selected_objs)
@@ -831,38 +831,40 @@ class ShowOpenings(Operator, tool.Ifc.Operator):
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
props = bpy.context.scene.BIMModelProperties
objs = list(context.selected_objects)
self.update_with_aggregates(objs)
for obj in objs:
# If several parts of an aggregation are selected, the aggregate openings may be queried more than once
objects_element_map = set()
while objs:
obj = objs.pop(0)
element = tool.Ifc.get_entity(obj)
if not element or not getattr(element, "HasOpenings", None):
continue
if tool.Ifc.is_moved(obj):
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
openings = tool.Model.load_openings(
[
r.RelatedOpeningElement
for r in element.HasOpenings
if not tool.Ifc.get_object(r.RelatedOpeningElement)
],
)
for opening in openings:
new = props.openings.add()
new.obj = opening
opening.display_type = "WIRE"
if element and getattr(element, "Decomposes", None):
# Select aggregate recursively
if element.Decomposes and (aggregate := element.Decomposes[0].RelatingObject):
aggregate_obj = tool.Ifc.get_object(aggregate)
objs.append(aggregate_obj)
objects_element_map.add((obj, element))
for obj, element in objects_element_map:
self.show_object_openings(obj, element)
DecorationsHandler.install(bpy.context)
bpy.ops.bim.update_openings_focus()
return {"FINISHED"}
def update_with_aggregates(self, objs):
for obj in objs:
element = tool.Ifc.get_entity(obj)
if element and getattr(element, "Decomposes", None):
if element.Decomposes and (aggregate := element.Decomposes[0].RelatingObject):
aggregate_obj = tool.Ifc.get_object(aggregate)
objs.append(aggregate_obj)
def show_object_openings(self, obj, element):
openings_elements = [rel.RelatedOpeningElement for rel in tool.Geometry.get_openings(element)]
if not openings_elements:
return
if tool.Ifc.is_moved(obj):
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
openings_elements_to_load = [o for o in openings_elements if not tool.Ifc.get_object(o)]
openings_objects = tool.Model.load_openings(openings_elements_to_load)
for opening in openings_objects:
self.on_new_opening_obj(opening)
def on_new_opening_obj(self, opening_obj):
new = bpy.context.scene.BIMModelProperties.openings.add()
new.obj = opening_obj
opening_obj.display_type = "WIRE"
class UpdateOpeningsFocus(Operator, tool.Ifc.Operator):
@@ -908,24 +910,25 @@ def hide_openings(context, objects):
objects_to_remove = set()
for opening_prop in context.scene.BIMModelProperties.openings:
opening_obj = opening_prop.obj
if opening_obj:
opening_element = tool.Ifc.get_entity(opening_obj)
if opening_element:
if not opening_element.is_a("IfcOpeningElement"):
# This opening has been assigned to another ifc class. Remove it from the openings pool. See #3854
opening_prop.obj = None
continue
building_element = opening_element.VoidsElements[0].RelatingBuildingElement
if building_element:
building_obj = tool.Ifc.get_object(building_element)
if building_obj in objects:
tool.Ifc.unlink(element=opening_element)
objects_to_remove.add(opening_obj)
if opening_obj in objects:
objects_to_remove.add(opening_obj)
if not opening_obj:
continue
opening_element = tool.Ifc.get_entity(opening_obj)
if opening_element:
if not opening_element.is_a("IfcOpeningElement"):
# This opening has been assigned to another ifc class. Remove it from the openings pool. See #3854
opening_prop.obj = None
continue
building_element = opening_element.VoidsElements[0].RelatingBuildingElement
if building_element:
building_obj = tool.Ifc.get_object(building_element)
if building_obj in objects:
tool.Ifc.unlink(element=opening_element)
objects_to_remove.add(opening_obj)
if opening_obj in objects:
objects_to_remove.add(opening_obj)
tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True)
tool.Model.clear_scene_openings()
tool.Model.purge_scene_openings()
bpy.ops.bim.update_openings_focus()
@@ -962,7 +965,7 @@ class EditOpenings(Operator, tool.Ifc.Operator):
building_objs, opening_elements = self.get_buildings_and_openings(context)
self.edit_openings(building_objs, opening_elements)
tool.Model.clear_scene_openings()
tool.Model.purge_scene_openings()
tool.Model.reload_body_representation(building_objs)
bpy.ops.bim.update_openings_focus()
return {"FINISHED"}
@@ -979,7 +982,7 @@ class EditOpenings(Operator, tool.Ifc.Operator):
continue
opening_element = tool.Ifc.get_entity(opening_obj)
if opening_element is None:
objects_to_remove.add(opening_element)
objects_to_remove.add(opening_obj)
continue
opening_elements.add(opening_element)
building_element = opening_element.VoidsElements[0].RelatingBuildingElement
@@ -995,9 +998,8 @@ class EditOpenings(Operator, tool.Ifc.Operator):
building_obj = tool.Ifc.get_object(building_element)
if building_obj:
building_objs.add(building_obj)
elif hasattr(element, "HasOpenings"):
building_element = element
for relation in building_element.HasOpenings:
else:
for relation in tool.Geometry.get_openings(element):
opening_element = relation.RelatedOpeningElement
if tool.Ifc.get_object(opening_element):
opening_elements.add(opening_element)
@@ -157,7 +157,7 @@ class AddOpening(bpy.types.Operator, tool.Ifc.Operator):
tool.Ifc.unlink(element=element2)
bpy.data.objects.remove(obj2)
tool.Model.clear_scene_openings()
tool.Model.purge_scene_openings()
context.view_layer.objects.active = obj1
return {"FINISHED"}
+1 -1
View File
@@ -560,7 +560,7 @@ class Model:
def import_curve(cls, curve, obj=None, position=None): pass
def import_rectangle(cls, obj, position, profile): pass
def load_openings(cls, openings): pass
def clear_scene_openings(cls): pass
def purge_scene_openings(cls): pass
def get_usage_type(cls, element): pass
def get_material_layer_parameters(cls, element): pass
def get_manual_booleans(cls, element): pass
+2 -2
View File
@@ -1526,8 +1526,8 @@ class Geometry(bonsai.core.tool.Geometry):
Use `.RelatedOpeningElement` to get the opening element.
"""
for element in getattr(element, "HasOpenings", ()):
yield element
for element_rel in getattr(element, "HasOpenings", ()):
yield element_rel
if aggregate := ifcopenshell.util.element.get_aggregate(element):
yield from cls.get_openings(aggregate)
+6 -10
View File
@@ -494,16 +494,12 @@ class Model(bonsai.core.tool.Model):
return ifc_importer.added_data.values()
@classmethod
def clear_scene_openings(cls) -> None:
"""Clear removed scene openings."""
props = bpy.context.scene.BIMModelProperties
has_deleted_opening = True
while has_deleted_opening:
has_deleted_opening = False
for i, opening in enumerate(list(props.openings)):
if not opening.obj:
props.openings.remove(i)
has_deleted_opening = True
def purge_scene_openings(cls) -> None:
"""Purge removed scene openings."""
openings = bpy.context.scene.BIMModelProperties.openings
for i in range(len(openings) - 1, -1, -1):
if not openings[i].obj:
openings.remove(i)
@classmethod
def get_material_layer_parameters(cls, element: ifcopenshell.entity_instance) -> dict[str, Any]: