Fix #3357. Remove Shift-E for parametric objects (superseded by tab) and you can now extend to anything not just slabs.

This Shift-E still needs more polish as we figure out the best hotkeys
and what's most natural to users when they select different combinations
of objects, so expect the conditionals that govern when Shift-E does
things to still change in the future.
This commit is contained in:
Dion Moult
2025-03-12 18:41:18 +11:00
parent f5a1c4aae3
commit 226736eb41
3 changed files with 33 additions and 46 deletions
@@ -66,12 +66,13 @@ classes = (
product.SetActiveType,
workspace.Hotkey,
workspace.BIM_MT_add_representation_item,
wall.AddWallsFromSlab,
wall.AlignWall,
wall.ChangeExtrusionDepth,
wall.ChangeExtrusionXAngle,
wall.ChangeLayerLength,
wall.AddWallsFromSlab,
wall.DrawPolylineWall,
wall.ExtendWallsToUnderside,
wall.FlipWall,
wall.MergeWall,
wall.RecalculateWall,
+21 -1
View File
@@ -36,7 +36,7 @@ import bonsai.core.geometry
import bonsai.core.model as core
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
from math import pi, sin, cos, degrees, radians
from math import pi, sin, cos, degrees
from mathutils import Vector, Matrix
from bonsai.bim.module.model.opening import FilledOpeningGenerator
from bonsai.bim.module.model.decorator import PolylineDecorator, ProductDecorator
@@ -58,6 +58,26 @@ class UnjoinWalls(bpy.types.Operator, tool.Ifc.Operator):
core.unjoin_walls(tool.Ifc, tool.Blender, tool.Geometry, DumbWallJoiner(), tool.Model)
class ExtendWallsToUnderside(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.extend_walls_to_underside"
bl_label = "Extend Walls To Underside"
bl_description = "Extend and clip selected walls at the bottom faces of an object"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
slab = None
walls = []
if (obj := tool.Blender.get_active_object(is_selected=True)) and (element := tool.Ifc.get_entity(obj)):
slab = obj
for obj in tool.Blender.get_selected_objects(include_active=False):
if (element := tool.Ifc.get_entity(obj)) and tool.Model.get_usage_type(element) == "LAYER2":
walls.append(obj)
if slab and walls:
core.extend_wall_to_slab(tool.Ifc, tool.Geometry, tool.Model, slab, walls)
else:
self.report({"ERROR"}, "Please select at least one LAYER2 element and an active element")
class AlignWall(bpy.types.Operator):
bl_idname = "bim.align_wall"
bl_label = "Align Wall"
+10 -44
View File
@@ -675,13 +675,12 @@ class CreateObjectUI:
for _ in range(4):
row2.operator("bim.launch_type_manager", text="", emboss=False)
else:
op = box.operator(
box.operator(
"bim.load_type_thumbnails",
text="",
icon="FILE_REFRESH",
emboss=False,
)
op.ifc_class = ifc_class
row = box.row(align=True)
row.alignment = "CENTER"
@@ -848,7 +847,7 @@ class EditObjectUI:
elif AuthoringData.data["active_material_usage"] == "LAYER3":
if "LAYER2" in AuthoringData.data["selected_material_usages"]:
row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row
add_layout_hotkey_operator(cls.layout, "Extend Wall To Slab", "S_E", "", ui_context)
add_layout_hotkey_operator(cls.layout, "Extend To Underside", "S_E", "", ui_context)
if AuthoringData.data["relating_type_data"].get("usage") == "LAYER2":
row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row
add_layout_hotkey_operator(
@@ -907,6 +906,11 @@ class EditObjectUI:
row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row
add_layout_hotkey_operator(row, "Rotate 90", "S_R", bpy.ops.bim.rotate_90.__doc__, ui_context)
else:
if "LAYER2" in AuthoringData.data["selected_material_usages"]:
row = cls.layout.row(align=True) if ui_context != "TOOL_HEADER" else row
add_layout_hotkey_operator(cls.layout, "Extend To Undersideb", "S_E", "", ui_context)
if AuthoringData.data["is_flippable_element"]:
cls.draw_flip(ui_context, row)
@@ -1167,23 +1171,6 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
if not bpy.context.selected_objects or not (active_object := bpy.context.active_object):
return
# NOTE: placing it before the other operations because railing can also be SweptSolid
# and it might conflict with one of the conditions below
if (
tool.Model.is_parametric_railing_active()
and not tool.Model.get_railing_props(active_object).is_editing_path
):
bpy.ops.bim.enable_editing_railing_path()
return
elif tool.Model.is_parametric_roof_active() and not tool.Model.get_roof_props(active_object).is_editing_path:
# undo the unselection done above because roof has no usage type
bpy.ops.bim.enable_editing_roof_path()
return
elif tool.Model.is_parametric_window_active() or tool.Model.is_parametric_door_active():
return
selected_usages: dict[str, list[bpy.types.Object]] = {}
for obj in bpy.context.selected_objects:
element = tool.Ifc.get_entity(obj)
@@ -1194,11 +1181,6 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
if not usage:
representation = tool.Geometry.get_active_representation(obj)
representation = tool.Geometry.resolve_mapped_representation(representation)
if representation and representation.RepresentationType == "SweptSolid":
usage = "SWEPTSOLID"
else:
obj.select_set(False)
continue
selected_usages.setdefault(usage, []).append(obj)
if len(bpy.context.selected_objects) == 1:
@@ -1227,9 +1209,6 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
elif self.active_material_usage == "PROFILE":
# Extend PROFILE to cursor
bpy.ops.bim.extend_profile(join_type="T")
else:
# Edit SWEPTSOLID profile (assuming single profile for now)
bpy.ops.bim.enable_editing_extrusion_profile()
elif self.active_material_usage == "LAYER2" and selected_usages.get("PROFILE", []):
# Extend PROFILEs to LAYER2
@@ -1237,22 +1216,6 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
[o.select_set(False) for o in selected_usages.get("LAYER2", []) if o != bpy.context.active_object]
bpy.ops.bim.extend_profile(join_type="T")
elif self.active_material_usage == "LAYER3" and selected_usages.get("LAYER2", []):
# Extend LAYER2s to LAYER3
[o.select_set(False) for o in selected_usages.get("PROFILE", [])]
[o.select_set(False) for o in selected_usages.get("LAYER3", []) if o != bpy.context.active_object]
slab = None
walls = []
if (obj := tool.Blender.get_active_object(is_selected=True)) and (element := tool.Ifc.get_entity(obj)) and tool.Model.get_usage_type(element) == "LAYER3":
slab = obj
for obj in tool.Blender.get_selected_objects(include_active=False):
if (element := tool.Ifc.get_entity(obj)) and tool.Model.get_usage_type(element) == "LAYER2":
walls.append(obj)
if slab and walls:
core.extend_wall_to_slab(tool.Ifc, tool.Geometry, tool.Model, slab, walls)
else:
self.report({"ERROR"}, "Please select at least one LAYER2 element and an active LAYER3 element")
elif self.active_material_usage == "LAYER2":
# Extend LAYER2s to LAYER2
[o.select_set(False) for o in selected_usages.get("LAYER3", [])]
@@ -1268,6 +1231,9 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
[o.select_set(False) for o in selected_usages.get("LAYER2", [])]
bpy.ops.bim.extend_profile(join_type="T")
else:
bpy.ops.bim.extend_walls_to_underside()
def hotkey_S_F(self):
if not bpy.context.selected_objects:
return