mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 22:50:21 +00:00
Use relevant tool.Geometry functions for querying openings relations
This commit is contained in:
@@ -357,7 +357,7 @@ class FilledOpeningGenerator:
|
|||||||
return shape_builder.get_representation(context, [extrusion])
|
return shape_builder.get_representation(context, [extrusion])
|
||||||
|
|
||||||
def has_visible_openings(self, element):
|
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):
|
if tool.Ifc.get_object(opening):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@@ -496,7 +496,7 @@ class AddPotentialOpening(Operator, AddObjectHelper):
|
|||||||
if new_matrix:
|
if new_matrix:
|
||||||
obj.matrix_world = new_matrix
|
obj.matrix_world = new_matrix
|
||||||
|
|
||||||
tool.Model.clear_scene_openings()
|
tool.Model.purge_scene_openings()
|
||||||
|
|
||||||
new = props.openings.add()
|
new = props.openings.add()
|
||||||
new.obj = obj
|
new.obj = obj
|
||||||
@@ -523,7 +523,7 @@ class AddPotentialHalfSpaceSolid(Operator, AddObjectHelper):
|
|||||||
obj = object_data_add(context, mesh, operator=self)
|
obj = object_data_add(context, mesh, operator=self)
|
||||||
obj.name = "HalfSpaceSolid"
|
obj.name = "HalfSpaceSolid"
|
||||||
|
|
||||||
tool.Model.clear_scene_openings()
|
tool.Model.purge_scene_openings()
|
||||||
|
|
||||||
new = props.openings.add()
|
new = props.openings.add()
|
||||||
new.obj = obj
|
new.obj = obj
|
||||||
@@ -574,7 +574,7 @@ class AddBoolean(Operator, tool.Ifc.Operator):
|
|||||||
)
|
)
|
||||||
|
|
||||||
tool.Model.mark_manual_booleans(element1, booleans)
|
tool.Model.mark_manual_booleans(element1, booleans)
|
||||||
tool.Model.clear_scene_openings()
|
tool.Model.purge_scene_openings()
|
||||||
|
|
||||||
bonsai.core.geometry.switch_representation(
|
bonsai.core.geometry.switch_representation(
|
||||||
tool.Ifc,
|
tool.Ifc,
|
||||||
@@ -628,7 +628,7 @@ class ShowBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
|
|||||||
booleans.extend(self.get_booleans(item))
|
booleans.extend(self.get_booleans(item))
|
||||||
|
|
||||||
props = bpy.context.scene.BIMModelProperties
|
props = bpy.context.scene.BIMModelProperties
|
||||||
tool.Model.clear_scene_openings()
|
tool.Model.purge_scene_openings()
|
||||||
|
|
||||||
existing_booleans = {
|
existing_booleans = {
|
||||||
boolean_obj.data.BIMMeshProperties.ifc_boolean_id: boolean_obj
|
boolean_obj.data.BIMMeshProperties.ifc_boolean_id: boolean_obj
|
||||||
@@ -763,7 +763,7 @@ class HideBooleans(Operator, tool.Ifc.Operator):
|
|||||||
objects_to_remove.add(obj)
|
objects_to_remove.add(obj)
|
||||||
|
|
||||||
tool.Blender.remove_data_blocks(objects_to_remove, remove_unused_data=True)
|
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:
|
if set_active_obj and set_selected_objs is not None:
|
||||||
tool.Blender.set_objects_selection(context, set_active_obj, set_selected_objs)
|
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"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = bpy.context.scene.BIMModelProperties
|
|
||||||
objs = list(context.selected_objects)
|
objs = list(context.selected_objects)
|
||||||
self.update_with_aggregates(objs)
|
# If several parts of an aggregation are selected, the aggregate openings may be queried more than once
|
||||||
|
objects_element_map = set()
|
||||||
for obj in objs:
|
while objs:
|
||||||
|
obj = objs.pop(0)
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
if not element or not getattr(element, "HasOpenings", None):
|
if element and getattr(element, "Decomposes", None):
|
||||||
continue
|
# Select aggregate recursively
|
||||||
if tool.Ifc.is_moved(obj):
|
if element.Decomposes and (aggregate := element.Decomposes[0].RelatingObject):
|
||||||
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
|
aggregate_obj = tool.Ifc.get_object(aggregate)
|
||||||
openings = tool.Model.load_openings(
|
objs.append(aggregate_obj)
|
||||||
[
|
objects_element_map.add((obj, element))
|
||||||
r.RelatedOpeningElement
|
|
||||||
for r in element.HasOpenings
|
for obj, element in objects_element_map:
|
||||||
if not tool.Ifc.get_object(r.RelatedOpeningElement)
|
self.show_object_openings(obj, element)
|
||||||
],
|
|
||||||
)
|
|
||||||
for opening in openings:
|
|
||||||
new = props.openings.add()
|
|
||||||
new.obj = opening
|
|
||||||
opening.display_type = "WIRE"
|
|
||||||
DecorationsHandler.install(bpy.context)
|
DecorationsHandler.install(bpy.context)
|
||||||
bpy.ops.bim.update_openings_focus()
|
bpy.ops.bim.update_openings_focus()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
def update_with_aggregates(self, objs):
|
def show_object_openings(self, obj, element):
|
||||||
for obj in objs:
|
openings_elements = [rel.RelatedOpeningElement for rel in tool.Geometry.get_openings(element)]
|
||||||
element = tool.Ifc.get_entity(obj)
|
if not openings_elements:
|
||||||
if element and getattr(element, "Decomposes", None):
|
return
|
||||||
if element.Decomposes and (aggregate := element.Decomposes[0].RelatingObject):
|
if tool.Ifc.is_moved(obj):
|
||||||
aggregate_obj = tool.Ifc.get_object(aggregate)
|
bonsai.core.geometry.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
|
||||||
objs.append(aggregate_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):
|
class UpdateOpeningsFocus(Operator, tool.Ifc.Operator):
|
||||||
@@ -908,24 +910,25 @@ def hide_openings(context, objects):
|
|||||||
objects_to_remove = set()
|
objects_to_remove = set()
|
||||||
for opening_prop in context.scene.BIMModelProperties.openings:
|
for opening_prop in context.scene.BIMModelProperties.openings:
|
||||||
opening_obj = opening_prop.obj
|
opening_obj = opening_prop.obj
|
||||||
if opening_obj:
|
if not opening_obj:
|
||||||
opening_element = tool.Ifc.get_entity(opening_obj)
|
continue
|
||||||
if opening_element:
|
opening_element = tool.Ifc.get_entity(opening_obj)
|
||||||
if not opening_element.is_a("IfcOpeningElement"):
|
if opening_element:
|
||||||
# This opening has been assigned to another ifc class. Remove it from the openings pool. See #3854
|
if not opening_element.is_a("IfcOpeningElement"):
|
||||||
opening_prop.obj = None
|
# This opening has been assigned to another ifc class. Remove it from the openings pool. See #3854
|
||||||
continue
|
opening_prop.obj = None
|
||||||
building_element = opening_element.VoidsElements[0].RelatingBuildingElement
|
continue
|
||||||
if building_element:
|
building_element = opening_element.VoidsElements[0].RelatingBuildingElement
|
||||||
building_obj = tool.Ifc.get_object(building_element)
|
if building_element:
|
||||||
if building_obj in objects:
|
building_obj = tool.Ifc.get_object(building_element)
|
||||||
tool.Ifc.unlink(element=opening_element)
|
if building_obj in objects:
|
||||||
objects_to_remove.add(opening_obj)
|
tool.Ifc.unlink(element=opening_element)
|
||||||
if opening_obj in objects:
|
objects_to_remove.add(opening_obj)
|
||||||
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.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()
|
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)
|
building_objs, opening_elements = self.get_buildings_and_openings(context)
|
||||||
self.edit_openings(building_objs, opening_elements)
|
self.edit_openings(building_objs, opening_elements)
|
||||||
|
|
||||||
tool.Model.clear_scene_openings()
|
tool.Model.purge_scene_openings()
|
||||||
tool.Model.reload_body_representation(building_objs)
|
tool.Model.reload_body_representation(building_objs)
|
||||||
bpy.ops.bim.update_openings_focus()
|
bpy.ops.bim.update_openings_focus()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
@@ -979,7 +982,7 @@ class EditOpenings(Operator, tool.Ifc.Operator):
|
|||||||
continue
|
continue
|
||||||
opening_element = tool.Ifc.get_entity(opening_obj)
|
opening_element = tool.Ifc.get_entity(opening_obj)
|
||||||
if opening_element is None:
|
if opening_element is None:
|
||||||
objects_to_remove.add(opening_element)
|
objects_to_remove.add(opening_obj)
|
||||||
continue
|
continue
|
||||||
opening_elements.add(opening_element)
|
opening_elements.add(opening_element)
|
||||||
building_element = opening_element.VoidsElements[0].RelatingBuildingElement
|
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)
|
building_obj = tool.Ifc.get_object(building_element)
|
||||||
if building_obj:
|
if building_obj:
|
||||||
building_objs.add(building_obj)
|
building_objs.add(building_obj)
|
||||||
elif hasattr(element, "HasOpenings"):
|
else:
|
||||||
building_element = element
|
for relation in tool.Geometry.get_openings(element):
|
||||||
for relation in building_element.HasOpenings:
|
|
||||||
opening_element = relation.RelatedOpeningElement
|
opening_element = relation.RelatedOpeningElement
|
||||||
if tool.Ifc.get_object(opening_element):
|
if tool.Ifc.get_object(opening_element):
|
||||||
opening_elements.add(opening_element)
|
opening_elements.add(opening_element)
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ class AddOpening(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
tool.Ifc.unlink(element=element2)
|
tool.Ifc.unlink(element=element2)
|
||||||
bpy.data.objects.remove(obj2)
|
bpy.data.objects.remove(obj2)
|
||||||
|
|
||||||
tool.Model.clear_scene_openings()
|
tool.Model.purge_scene_openings()
|
||||||
context.view_layer.objects.active = obj1
|
context.view_layer.objects.active = obj1
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|||||||
@@ -560,7 +560,7 @@ class Model:
|
|||||||
def import_curve(cls, curve, obj=None, position=None): pass
|
def import_curve(cls, curve, obj=None, position=None): pass
|
||||||
def import_rectangle(cls, obj, position, profile): pass
|
def import_rectangle(cls, obj, position, profile): pass
|
||||||
def load_openings(cls, openings): 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_usage_type(cls, element): pass
|
||||||
def get_material_layer_parameters(cls, element): pass
|
def get_material_layer_parameters(cls, element): pass
|
||||||
def get_manual_booleans(cls, element): pass
|
def get_manual_booleans(cls, element): pass
|
||||||
|
|||||||
@@ -1526,8 +1526,8 @@ class Geometry(bonsai.core.tool.Geometry):
|
|||||||
|
|
||||||
Use `.RelatedOpeningElement` to get the opening element.
|
Use `.RelatedOpeningElement` to get the opening element.
|
||||||
"""
|
"""
|
||||||
for element in getattr(element, "HasOpenings", ()):
|
for element_rel in getattr(element, "HasOpenings", ()):
|
||||||
yield element
|
yield element_rel
|
||||||
|
|
||||||
if aggregate := ifcopenshell.util.element.get_aggregate(element):
|
if aggregate := ifcopenshell.util.element.get_aggregate(element):
|
||||||
yield from cls.get_openings(aggregate)
|
yield from cls.get_openings(aggregate)
|
||||||
|
|||||||
@@ -494,16 +494,12 @@ class Model(bonsai.core.tool.Model):
|
|||||||
return ifc_importer.added_data.values()
|
return ifc_importer.added_data.values()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def clear_scene_openings(cls) -> None:
|
def purge_scene_openings(cls) -> None:
|
||||||
"""Clear removed scene openings."""
|
"""Purge removed scene openings."""
|
||||||
props = bpy.context.scene.BIMModelProperties
|
openings = bpy.context.scene.BIMModelProperties.openings
|
||||||
has_deleted_opening = True
|
for i in range(len(openings) - 1, -1, -1):
|
||||||
while has_deleted_opening:
|
if not openings[i].obj:
|
||||||
has_deleted_opening = False
|
openings.remove(i)
|
||||||
for i, opening in enumerate(list(props.openings)):
|
|
||||||
if not opening.obj:
|
|
||||||
props.openings.remove(i)
|
|
||||||
has_deleted_opening = True
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_material_layer_parameters(cls, element: ifcopenshell.entity_instance) -> dict[str, Any]:
|
def get_material_layer_parameters(cls, element: ifcopenshell.entity_instance) -> dict[str, Any]:
|
||||||
|
|||||||
Reference in New Issue
Block a user