mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 02:23:34 +00:00
- Use active object as mirror plane when other objects are selected,
falling back to in-place X-axis flip when only one object is selected - Show Mirror Geometry button for any active IFC element, not just flippable types Generated with the assistance of an AI coding tool.
This commit is contained in:
@@ -691,11 +691,19 @@ class TrueMirrorElements(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return context.selected_objects
|
||||
|
||||
def _execute(self, context):
|
||||
for obj in context.selected_objects:
|
||||
self.mirror_obj(context, obj)
|
||||
active_obj = context.active_object
|
||||
mirror_ref = None
|
||||
if active_obj:
|
||||
objs_to_mirror = [obj for obj in context.selected_objects if obj != active_obj]
|
||||
if objs_to_mirror:
|
||||
mirror_ref = active_obj
|
||||
if mirror_ref is None:
|
||||
objs_to_mirror = context.selected_objects
|
||||
for obj in objs_to_mirror:
|
||||
self.mirror_obj(context, obj, mirror_ref)
|
||||
return {"FINISHED"}
|
||||
|
||||
def mirror_obj(self, context: bpy.types.Context, obj: bpy.types.Object):
|
||||
def mirror_obj(self, context: bpy.types.Context, obj: bpy.types.Object, mirror_ref: bpy.types.Object = None):
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
return
|
||||
@@ -714,11 +722,17 @@ class TrueMirrorElements(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
context.view_layer.update()
|
||||
|
||||
mirrored_bb_data = tool.Blender.get_object_bounding_box(obj)
|
||||
|
||||
x_correction_factor = mirrored_bb_data["min_x"] - bb_data["min_x"]
|
||||
x_correction_vec = (obj.matrix_world @ Vector((x_correction_factor, 0, 0, 0))).xyz
|
||||
obj.location -= x_correction_vec
|
||||
if mirror_ref:
|
||||
# Reflect object origin about the mirror reference's YZ plane
|
||||
origin_in_mirror = mirror_ref.matrix_world.inverted() @ obj.matrix_world.translation
|
||||
origin_in_mirror.x *= -1
|
||||
obj.matrix_world.translation = mirror_ref.matrix_world @ origin_in_mirror
|
||||
else:
|
||||
# Fall back: nudge in place to compensate for bounding box shift after inversion
|
||||
mirrored_bb_data = tool.Blender.get_object_bounding_box(obj)
|
||||
x_correction_factor = mirrored_bb_data["min_x"] - bb_data["min_x"]
|
||||
x_correction_vec = (obj.matrix_world @ Vector((x_correction_factor, 0, 0, 0))).xyz
|
||||
obj.location -= x_correction_vec
|
||||
|
||||
if element.is_a("IfcElement") and element.FillsVoids:
|
||||
tool.Model.update_simple_openings(element)
|
||||
|
||||
@@ -950,6 +950,9 @@ class EditObjectUI:
|
||||
if AuthoringData.data["is_flippable_element"]:
|
||||
cls.draw_flip(ui_context, row)
|
||||
|
||||
if AuthoringData.data["active_class"] is not None:
|
||||
cls.draw_mirror_geometry(ui_context, row)
|
||||
|
||||
if PortData.data["total_ports"] > 0:
|
||||
row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row
|
||||
row.operator(
|
||||
@@ -1094,6 +1097,9 @@ class EditObjectUI:
|
||||
def draw_flip(cls, ui_context, layout) -> None:
|
||||
row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else layout
|
||||
add_layout_hotkey_operator(row, "Flip", "S_F", bpy.ops.bim.flip_object.__doc__, ui_context)
|
||||
|
||||
@classmethod
|
||||
def draw_mirror_geometry(cls, ui_context, layout) -> None:
|
||||
row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else layout
|
||||
add_layout_hotkey_operator(row, "Mirror Geometry", "C_F", bpy.ops.bim.mirror_geometry.__doc__, ui_context)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user