Added tool.Blender.Modifier.has_mirrored_type and set_mirrored_type.

This commit is contained in:
Robin Quint
2025-08-08 14:54:18 +02:00
committed by Ryan Schultz
parent e96420335b
commit 21d1d014e3
4 changed files with 38 additions and 44 deletions
@@ -2719,24 +2719,22 @@ class OverrideModeSetObject(bpy.types.Operator, tool.Ifc.Operator):
# apply changes to mirrored object, if it exists # apply changes to mirrored object, if it exists
if props.representation_obj and (representation_elem := tool.Ifc.get_entity(props.representation_obj)): if props.representation_obj and (representation_elem := tool.Ifc.get_entity(props.representation_obj)):
type_elem = ifcopenshell.util.element.get_type(representation_elem) type_elem = ifcopenshell.util.element.get_type(representation_elem)
if type_elem and (mirrored_pset := ifcopenshell.util.element.get_pset(type_elem, "BBIM_InvertedSwingType", "Data")): if type_elem and (mirrored_type := tool.Blender.Modifier.has_mirrored_type(type_elem)):
mirrored_data = json.loads(mirrored_pset) # object has mirror, update it as well
if "inverted_swing_type" in mirrored_data and (inverted_type := tool.Ifc.get_entity_by_id(int(mirrored_data["inverted_swing_type"]))): for map_index, repr_map in enumerate(type_elem.RepresentationMaps):
# object has mirror, update it as well new_items = []
for map_index, repr_map in enumerate(type_elem.RepresentationMaps): for item in repr_map.MappedRepresentation.Items:
new_items = [] new_mirrored_repr = ifcopenshell.util.element.copy_deep(tool.Ifc.get(), item)
for item in repr_map.MappedRepresentation.Items: builder = ifcopenshell.util.shape_builder.ShapeBuilder(tool.Ifc.get())
new_mirrored_repr = ifcopenshell.util.element.copy_deep(tool.Ifc.get(), item) builder.mirror(new_mirrored_repr, (1, 0), create_copy=False)
builder = ifcopenshell.util.shape_builder.ShapeBuilder(tool.Ifc.get()) new_items.append(new_mirrored_repr)
builder.mirror(new_mirrored_repr, (1, 0), create_copy=False)
new_items.append(new_mirrored_repr)
old_items = inverted_type.RepresentationMaps[map_index].MappedRepresentation.Items
inverted_type.RepresentationMaps[map_index].MappedRepresentation.Items = new_items
for old_item in old_items:
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), old_item)
tool.Geometry.reload_representation(tool.Ifc.get_object(inverted_type)) old_items = mirrored_type.RepresentationMaps[map_index].MappedRepresentation.Items
mirrored_type.RepresentationMaps[map_index].MappedRepresentation.Items = new_items
for old_item in old_items:
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), old_item)
tool.Geometry.reload_representation(tool.Ifc.get_object(mirrored_type))
def enable_edit_mode(self, context): def enable_edit_mode(self, context):
+3 -5
View File
@@ -638,11 +638,9 @@ class FinishEditingDoor(_DoorEditMixin, bpy.types.Operator, tool.Ifc.Operator):
door_data_str = tool.Ifc.get().createIfcText(json.dumps(door_data, default=list)) door_data_str = tool.Ifc.get().createIfcText(json.dumps(door_data, default=list))
ifcopenshell.api.pset.edit_pset(tool.Ifc.get(), pset=pset, properties={"Data": door_data_str}) ifcopenshell.api.pset.edit_pset(tool.Ifc.get(), pset=pset, properties={"Data": door_data_str})
if inverted_pset := ifcopenshell.util.element.get_pset(element, "BBIM_InvertedSwingType", "Data"): if mirrored_type := tool.Blender.Modifier.has_mirrored_type(element):
inverted_data = json.loads(inverted_pset) # object has mirrored repr, update it as well
if "inverted_swing_type" in inverted_data and (inverted_type := tool.Ifc.get_entity_by_id(int(inverted_data["inverted_swing_type"]))): self.copy_door_params(door_data, element, mirrored_type)
# object has mirrored repr, update it as well
self.copy_door_params(door_data, element, inverted_type)
def copy_door_params(self, from_data, from_elem, to_elem): def copy_door_params(self, from_data, from_elem, to_elem):
if "RIGHT" in from_data["door_type"]: if "RIGHT" in from_data["door_type"]:
+5 -22
View File
@@ -691,10 +691,10 @@ class TrueMirrorElements(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context): def _execute(self, context):
for obj in context.selected_objects: for obj in context.selected_objects:
self.change_obj_swing_direction(obj) self.mirror_obj(obj)
return { "FINISHED" } return { "FINISHED" }
def change_obj_swing_direction(self, obj): def mirror_obj(self, obj):
element = tool.Ifc.get_entity(obj) element = tool.Ifc.get_entity(obj)
if not element: if not element:
return return
@@ -778,33 +778,16 @@ class TrueMirrorElements(bpy.types.Operator, tool.Ifc.Operator):
else: else:
self.invert_general_object(element) self.invert_general_object(element)
def get_inverted_type(self, type_element):
inverted_pset = ifcopenshell.util.element.get_pset(type_element, "BBIM_InvertedSwingType", "Data")
if not inverted_pset:
return None
data = json.loads(inverted_pset)
if "inverted_swing_type" in data:
return tool.Ifc.get_entity_by_id(int(data["inverted_swing_type"]))
return None
def set_inverted_type(self, type_element, inverted_type_element):
inverted_pset = tool.Pset.get_element_pset(type_element, "BBIM_InvertedSwingType")
if not inverted_pset:
inverted_pset = ifcopenshell.api.pset.add_pset(tool.Ifc.get(), type_element, "BBIM_InvertedSwingType")
ifcopenshell.api.pset.edit_pset(tool.Ifc.get(), inverted_pset, "BBIM_InvertedSwingType", { "Data": json.dumps({ "inverted_swing_type": inverted_type_element.id() }) })
def assign_inverted_type(self, element): def assign_inverted_type(self, element):
type_element = ifcopenshell.util.element.get_type(element) type_element = ifcopenshell.util.element.get_type(element)
inverted_type = self.get_inverted_type(type_element) inverted_type = tool.Blender.Modifier.has_mirrored_type(type_element)
if not inverted_type: if not inverted_type:
old_to_new, _ = tool.Geometry.duplicate_ifc_objects([ tool.Ifc.get_object(type_element) ]) old_to_new, _ = tool.Geometry.duplicate_ifc_objects([ tool.Ifc.get_object(type_element) ])
inverted_type = old_to_new[type_element][0] inverted_type = old_to_new[type_element][0]
self.invert_representation(inverted_type) self.invert_representation(inverted_type)
self.set_inverted_type(inverted_type, type_element) tool.Blender.Modifier.set_mirrored_type(inverted_type, type_element)
self.set_inverted_type(type_element, inverted_type) tool.Blender.Modifier.set_mirrored_type(type_element, inverted_type)
inverted_type.Name = f"{inverted_type.Name}.Mirror" inverted_type.Name = f"{inverted_type.Name}.Mirror"
bonsai.core.type.assign_type(tool.Ifc, tool.Type, element, inverted_type) bonsai.core.type.assign_type(tool.Ifc, tool.Type, element, inverted_type)
+15
View File
@@ -61,6 +61,7 @@ import numpy as np
import numpy.typing as npt import numpy.typing as npt
from gpu_extras.batch import batch_for_shader from gpu_extras.batch import batch_for_shader
from ifcopenshell import entity_instance from ifcopenshell import entity_instance
import ifcopenshell.api.pset
from mathutils import Matrix, Vector from mathutils import Matrix, Vector
import bonsai.bim import bonsai.bim
@@ -1618,6 +1619,20 @@ class Blender(bonsai.core.tool.Blender):
_any_selected_array_child_memo: tuple[frozenset[int], int, bool] | None = None _any_selected_array_child_memo: tuple[frozenset[int], int, bool] | None = None
@classmethod
def has_mirrored_type(cls, element: entity_instance, inherit: bool = True) -> entity_instance | None:
pset = ifcopenshell.util.element.get_pset(element, "BBIM_MirroredType", "Data", should_inherit=inherit)
if pset and (parsed := json.loads(pset)) and "mirrored_type" in parsed:
return tool.Ifc.get_entity_by_id(int(parsed["mirrored_type"]))
return None
@classmethod
def set_mirrored_type(cls, element: entity_instance, mirrored_type: entity_instance):
pset = tool.Pset.get_element_pset(element, "BBIM_MirroredType")
if not pset:
pset = ifcopenshell.api.pset.add_pset(tool.Ifc.get(), element, "BBIM_MirroredType")
ifcopenshell.api.pset.edit_pset(tool.Ifc.get(), pset, properties={"Data": json.dumps({"mirrored_type": mirrored_type.id()})})
@classmethod @classmethod
def is_slab(cls, element: entity_instance) -> bool: def is_slab(cls, element: entity_instance) -> bool:
"""A slab is host-eligible for the parametric add-opening gizmo if """A slab is host-eligible for the parametric add-opening gizmo if