mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
Refactor and improve parametric gizmo system
- You can now input values using the keyboard once you clicked on a gizmo - Gizmos now support click > move > click in addition to drag and drop (yay carpal tunnel !) - Optimize snapping performance - Consolidate door and window type in model.py - You can now cycle through window and door types using the cycle gizmo - Pen, validate, cancel, lock, and cycle gizmos are now billboards and follow view direction - Draggable gizmos are now billboard 2D arrows instead of 3D cones
This commit is contained in:
@@ -207,7 +207,9 @@ classes = [
|
||||
ui.BIM_PT_decorators_overlay,
|
||||
ui.BIM_PT_snappping,
|
||||
# Gizmos
|
||||
gizmo.BIM_OT_gizmo_value_input,
|
||||
gizmo.GizmoArrow,
|
||||
gizmo.GizmoArrow2D,
|
||||
gizmo.GizmoCone,
|
||||
gizmo.GizmoLock,
|
||||
gizmo.GizmoArc,
|
||||
|
||||
+856
-267
File diff suppressed because it is too large
Load Diff
@@ -176,6 +176,7 @@ classes = (
|
||||
window.FinishEditingWindow,
|
||||
window.EnableEditingWindow,
|
||||
window.RemoveWindow,
|
||||
window.CycleWindowType,
|
||||
window.GizmoWindowEdition,
|
||||
door.BIM_OT_add_door,
|
||||
door.AddDoor,
|
||||
@@ -184,6 +185,7 @@ classes = (
|
||||
door.EnableEditingDoor,
|
||||
door.RemoveDoor,
|
||||
door.ToggleDoorSwing,
|
||||
door.CycleDoorType,
|
||||
door.GizmoDoorEdition,
|
||||
railing.BIM_OT_add_railing,
|
||||
railing.CopyRailingParameters,
|
||||
|
||||
@@ -41,6 +41,7 @@ from mathutils import Vector, Matrix
|
||||
import json
|
||||
import collections
|
||||
import collections.abc
|
||||
from typing import get_args
|
||||
|
||||
V_ = tool.Blender.V_
|
||||
|
||||
@@ -741,6 +742,38 @@ class ToggleDoorSwing(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CycleDoorType(bpy.types.Operator, tool.Ifc.Operator):
|
||||
"""Cycle through available door types. Shift+click to cycle in reverse."""
|
||||
|
||||
bl_idname = "bim.cycle_door_type"
|
||||
bl_label = "Cycle Door Type"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
reverse: bpy.props.BoolProperty(name="Reverse", default=False, options={"HIDDEN", "SKIP_SAVE"})
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.reverse = event.shift
|
||||
return self.execute(context)
|
||||
|
||||
def _execute(self, context):
|
||||
obj = tool.Blender.get_active_object()
|
||||
if not obj:
|
||||
return {"CANCELLED"}
|
||||
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element or not tool.Blender.Modifier.is_door(element):
|
||||
return {"CANCELLED"}
|
||||
|
||||
props = tool.Model.get_door_props(obj)
|
||||
door_types = get_args(tool.Model.DoorType)
|
||||
current_index = door_types.index(props.door_type) if props.door_type in door_types else 0
|
||||
direction = -1 if self.reverse else 1
|
||||
next_index = (current_index + direction) % len(door_types)
|
||||
props.door_type = door_types[next_index]
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class GizmoDoorEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
bl_idname = "OBJECT_GGT_bim_door_edition"
|
||||
bl_label = "Door Editing Gizmo"
|
||||
@@ -751,6 +784,7 @@ class GizmoDoorEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
enable_editing_operator = "bim.enable_editing_door"
|
||||
finish_editing_operator = "bim.finish_editing_door"
|
||||
cancel_editing_operator = "bim.cancel_editing_door"
|
||||
cycle_type_operator = "bim.cycle_door_type"
|
||||
|
||||
gizmo_props = [
|
||||
GizmoPropConfig("overall_height", (0, 0, 1)),
|
||||
@@ -833,11 +867,15 @@ class GizmoDoorEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
return translation @ rotation
|
||||
|
||||
def get_gizmo_matrix_transom_offset(self, props):
|
||||
translation = Matrix.Translation(V_(props.overall_width / 2, props.lining_offset, props.transom_offset))
|
||||
# Position at the bottom of the transom (transom extends upward from offset)
|
||||
translation = Matrix.Translation(
|
||||
V_(props.overall_width / 2, props.lining_offset, props.transom_offset)
|
||||
)
|
||||
rotation = self.get_axis_rotation_matrix((0, 0, 1))
|
||||
return translation @ rotation
|
||||
|
||||
def get_gizmo_matrix_transom_thickness(self, props):
|
||||
# Position at the top of the transom (offset + thickness)
|
||||
translation = Matrix.Translation(
|
||||
V_(props.overall_width / 2, props.lining_offset, props.transom_offset + props.transom_thickness)
|
||||
)
|
||||
@@ -904,7 +942,7 @@ class GizmoDoorEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
mw = obj.matrix_world
|
||||
self.update_property_gizmos(mw, props)
|
||||
self.update_swing_gizmos(mw, props)
|
||||
self.update_editing_gizmos(mw, props)
|
||||
self.update_editing_gizmos(context, mw, props)
|
||||
|
||||
def update_swing_gizmos(self, mw, props):
|
||||
"""Update swing gizmo position and color based on editing state."""
|
||||
|
||||
@@ -671,19 +671,6 @@ def window_type_prop_update(self, context):
|
||||
update_window(self, context)
|
||||
|
||||
|
||||
WindowType = Literal[
|
||||
"SINGLE_PANEL",
|
||||
"DOUBLE_PANEL_HORIZONTAL",
|
||||
"DOUBLE_PANEL_VERTICAL",
|
||||
"TRIPLE_PANEL_BOTTOM",
|
||||
"TRIPLE_PANEL_TOP",
|
||||
"TRIPLE_PANEL_LEFT",
|
||||
"TRIPLE_PANEL_RIGHT",
|
||||
"TRIPLE_PANEL_HORIZONTAL",
|
||||
"TRIPLE_PANEL_VERTICAL",
|
||||
]
|
||||
|
||||
|
||||
# default prop values are in mm and converted later
|
||||
class BIMWindowProperties(PropertyGroup):
|
||||
non_si_units_props = (
|
||||
@@ -712,7 +699,7 @@ class BIMWindowProperties(PropertyGroup):
|
||||
is_editing: bpy.props.BoolProperty(default=False)
|
||||
window_type: bpy.props.EnumProperty(
|
||||
name="Window Type",
|
||||
items=[(i, i, "") for i in get_args(WindowType)],
|
||||
items=[(i, i, "") for i in get_args(tool.Model.WindowType)],
|
||||
default="SINGLE_PANEL",
|
||||
update=window_type_prop_update,
|
||||
)
|
||||
@@ -788,7 +775,7 @@ class BIMWindowProperties(PropertyGroup):
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_editing: bool
|
||||
window_type: WindowType
|
||||
window_type: tool.Model.WindowType
|
||||
overall_height: float
|
||||
overall_width: float
|
||||
lining_depth: float
|
||||
@@ -822,7 +809,7 @@ class BIMWindowProperties(PropertyGroup):
|
||||
return tool.Model.convert_data_to_project_units(kwargs, ["window_type"])
|
||||
|
||||
def get_lining_kwargs(
|
||||
self, window_type: Optional[WindowType] = None, convert_to_project_units: bool = False
|
||||
self, window_type: Optional[tool.Model.WindowType] = None, convert_to_project_units: bool = False
|
||||
) -> dict[str, Any]:
|
||||
if not window_type:
|
||||
window_type = self.window_type
|
||||
@@ -889,18 +876,6 @@ class BIMWindowProperties(PropertyGroup):
|
||||
setattr(target_props, prop_name, prop_value)
|
||||
|
||||
|
||||
DoorType = Literal[
|
||||
"SINGLE_SWING_LEFT",
|
||||
"SINGLE_SWING_RIGHT",
|
||||
"DOUBLE_SWING_LEFT",
|
||||
"DOUBLE_SWING_RIGHT",
|
||||
"DOUBLE_DOOR_SINGLE_SWING",
|
||||
"SLIDING_TO_LEFT",
|
||||
"SLIDING_TO_RIGHT",
|
||||
"DOUBLE_DOOR_SLIDING",
|
||||
]
|
||||
|
||||
|
||||
class BIMDoorProperties(PropertyGroup):
|
||||
non_si_units_props = (
|
||||
"is_editing",
|
||||
@@ -913,7 +888,7 @@ class BIMDoorProperties(PropertyGroup):
|
||||
is_editing: bpy.props.BoolProperty(default=False)
|
||||
door_type: bpy.props.EnumProperty(
|
||||
name="Door Operation Type",
|
||||
items=tuple((i, i, "") for i in get_args(DoorType)),
|
||||
items=tuple((i, i, "") for i in get_args(tool.Model.DoorType)),
|
||||
default="SINGLE_SWING_LEFT",
|
||||
update=update_door,
|
||||
)
|
||||
@@ -1057,7 +1032,7 @@ class BIMDoorProperties(PropertyGroup):
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_editing: bool
|
||||
door_type: DoorType
|
||||
door_type: tool.Model.DoorType
|
||||
overall_height: float
|
||||
overall_width: float
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ from bmesh.types import BMVert
|
||||
from bpy.types import Operator
|
||||
from bpy.props import FloatProperty, IntProperty
|
||||
from bpy_extras.object_utils import AddObjectHelper, object_data_add
|
||||
from typing import get_args
|
||||
|
||||
|
||||
def regenerate_stair_mesh(obj: bpy.types.Object) -> None:
|
||||
@@ -357,13 +358,10 @@ class CycleStairType(bpy.types.Operator):
|
||||
return {"CANCELLED"}
|
||||
|
||||
props = tool.Model.get_stair_props(obj)
|
||||
types = ["CONCRETE", "WOOD/STEEL", "GENERIC"]
|
||||
try:
|
||||
current_idx = types.index(props.stair_type)
|
||||
except ValueError:
|
||||
current_idx = 0
|
||||
stair_types = get_args(tool.Model.StairType)
|
||||
current_idx = stair_types.index(props.stair_type) if props.stair_type in stair_types else 0
|
||||
direction = -1 if self.reverse else 1
|
||||
props.stair_type = types[(current_idx + direction) % len(types)]
|
||||
props.stair_type = stair_types[(current_idx + direction) % len(stair_types)]
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -375,6 +373,13 @@ class GizmoStairEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
bl_region_type = "WINDOW"
|
||||
bl_options = {"3D", "PERSISTENT"}
|
||||
|
||||
# Gizmo layout offsets (meters)
|
||||
GIZMO_X_OFFSET = 0.5 # Horizontal offset from stair end
|
||||
GIZMO_PLUS_X_OFFSET = 0.25 # Additional X offset for plus button
|
||||
GIZMO_MINUS_X_OFFSET = 0.5 # Additional X offset for minus button
|
||||
GIZMO_BUTTON_Z_OFFSET = 0.15 # Vertical offset for +/- buttons above lock
|
||||
GIZMO_CYCLE_Z_OFFSET = 0.5 # Vertical offset for cycle gizmo above lock
|
||||
|
||||
enable_editing_operator = "bim.enable_editing_stair"
|
||||
finish_editing_operator = "bim.finish_editing_stair"
|
||||
cancel_editing_operator = "bim.cancel_editing_stair"
|
||||
@@ -432,6 +437,13 @@ class GizmoStairEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
rotation = self.get_axis_rotation_matrix((0, 1, 0))
|
||||
return translation @ rotation
|
||||
|
||||
def get_gizmo_matrix_width_top(self, props):
|
||||
"""Position for the secondary width gizmo at the top of the stairs."""
|
||||
total_run = self._get_stair_total_run(props)
|
||||
translation = Matrix.Translation(Vector((total_run, props.width, props.height)))
|
||||
rotation = self.get_axis_rotation_matrix((0, 1, 0))
|
||||
return translation @ rotation
|
||||
|
||||
def get_gizmo_matrix_height(self, props):
|
||||
total_run = self._get_stair_total_run(props)
|
||||
translation = Matrix.Translation(Vector((total_run, props.width / 2, props.height)))
|
||||
@@ -490,6 +502,41 @@ class GizmoStairEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
prefs = tool.Blender.get_addon_preferences()
|
||||
highlight_color = prefs.decorator_color_selected[:3]
|
||||
|
||||
# Secondary width gizmo at the top of the stairs (linked to same width property)
|
||||
self.gizmo_width_top = self.gizmos.new("BIM_GT_gizmo_arrow_2d")
|
||||
|
||||
def make_width_get():
|
||||
def move_get():
|
||||
obj = bpy.context.active_object
|
||||
if not obj:
|
||||
return 0.0
|
||||
props = self.get_props(obj)
|
||||
return props.width
|
||||
return move_get
|
||||
|
||||
def make_width_set():
|
||||
def move_set(value):
|
||||
obj = bpy.context.active_object
|
||||
if not obj:
|
||||
return
|
||||
props = self.get_props(obj)
|
||||
props.width = max(0.0, value)
|
||||
return move_set
|
||||
|
||||
self.gizmo_width_top.move_get_cb = make_width_get()
|
||||
self.gizmo_width_top.move_set_cb = make_width_set()
|
||||
self.gizmo_width_top.axis = Vector((0, 1, 0))
|
||||
self.gizmo_width_top.local_axis = Vector((0, 1, 0))
|
||||
self.gizmo_width_top.invert_delta = False
|
||||
self.gizmo_width_top.delta_scale = 1.0
|
||||
self.gizmo_width_top.prop_name = "Width"
|
||||
self.gizmo_width_top.gizmo_group = self
|
||||
self.gizmo_width_top.color = self.COLOR_GREEN
|
||||
self.gizmo_width_top.color_highlight = highlight_color
|
||||
self.gizmo_width_top.alpha = 0.99
|
||||
self.gizmo_width_top.use_draw_modal = True
|
||||
self.gizmo_width_top.use_draw_scale = True
|
||||
|
||||
# Total length lock gizmo
|
||||
self.lock_gizmo = self.gizmos.new("VIEW3D_GT_lock")
|
||||
self.lock_gizmo.use_draw_scale = False
|
||||
@@ -533,65 +580,81 @@ class GizmoStairEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
|
||||
props = self.get_props(obj)
|
||||
mw = obj.matrix_world
|
||||
billboard_rot = gizmo.get_billboard_rotation(context)
|
||||
self.update_property_gizmos(mw, props)
|
||||
self.update_editing_gizmos(mw, props)
|
||||
self.update_lock_gizmo(mw, props)
|
||||
self.update_tread_count_gizmos(mw, props)
|
||||
self.update_cycle_gizmo(mw, props)
|
||||
self.update_editing_gizmos(context, mw, props)
|
||||
self.update_width_top_gizmo(mw, props)
|
||||
self.update_lock_gizmo(mw, props, billboard_rot)
|
||||
self.update_tread_count_gizmos(mw, props, billboard_rot)
|
||||
self.update_cycle_gizmo(mw, props, billboard_rot)
|
||||
|
||||
def update_lock_gizmo(self, mw, props):
|
||||
"""Update lock gizmo position and visibility."""
|
||||
def update_width_top_gizmo(self, mw, props):
|
||||
"""Update the secondary width gizmo at the top of the stairs."""
|
||||
gizmo_prefs = self.get_gizmo_prefs()
|
||||
# Use same visibility as the main width gizmo
|
||||
self.gizmo_width_top.hide = not props.is_editing or not getattr(gizmo_prefs, "width", True)
|
||||
|
||||
if self.gizmo_width_top.hide:
|
||||
return
|
||||
|
||||
self.gizmo_width_top.matrix_basis = mw @ self.get_gizmo_matrix_width_top(props)
|
||||
self.gizmo_width_top.matrix_offset = Matrix.Scale(self.ARROW_SCALE, 4)
|
||||
|
||||
def update_lock_gizmo(self, mw, props, billboard_rot):
|
||||
gizmo_prefs = self.get_gizmo_prefs()
|
||||
self.lock_gizmo.hide = not props.is_editing or not gizmo_prefs.lock
|
||||
|
||||
if self.lock_gizmo.hide:
|
||||
return
|
||||
|
||||
# Update color based on lock state: red when locked, green when unlocked
|
||||
self.lock_gizmo.color = self.COLOR_RED if props.total_length_lock else self.COLOR_GREEN
|
||||
|
||||
total_run = self._get_stair_total_run(props)
|
||||
lock_x = total_run + props.tread_run + 0.5
|
||||
lock_x = total_run + props.tread_run + self.GIZMO_X_OFFSET
|
||||
local_transform = (
|
||||
Matrix.Translation(Vector((lock_x, props.width / 2, props.height)))
|
||||
@ Matrix.Rotation(math.radians(90), 4, (1.0, 0.0, 0.0))
|
||||
@ billboard_rot
|
||||
@ Matrix.Scale(0.2, 4)
|
||||
)
|
||||
self.lock_gizmo.matrix_basis = mw @ local_transform
|
||||
|
||||
def update_tread_count_gizmos(self, mw, props):
|
||||
"""Update plus and minus gizmos for tread count adjustment."""
|
||||
def update_tread_count_gizmos(self, mw, props, billboard_rot):
|
||||
gizmo_prefs = self.get_gizmo_prefs()
|
||||
|
||||
# Plus gizmo - always visible when editing (if preference enabled)
|
||||
self.plus_gizmo.hide = not props.is_editing or not gizmo_prefs.plus
|
||||
# Minus gizmo - hidden when number_of_treads is 1 (if preference enabled)
|
||||
self.minus_gizmo.hide = not props.is_editing or props.number_of_treads <= 1 or not gizmo_prefs.minus
|
||||
|
||||
if self.plus_gizmo.hide and self.minus_gizmo.hide:
|
||||
return
|
||||
|
||||
total_run = self._get_stair_total_run(props)
|
||||
base_x = total_run + props.tread_run + 0.5
|
||||
base_x = total_run + props.tread_run + self.GIZMO_X_OFFSET
|
||||
|
||||
if not self.plus_gizmo.hide:
|
||||
plus_local_transform = (
|
||||
Matrix.Translation(Vector((base_x + 0.25, props.width / 2, props.height + 0.15)))
|
||||
@ Matrix.Rotation(math.radians(90), 4, (1.0, 0.0, 0.0))
|
||||
Matrix.Translation(Vector((
|
||||
base_x + self.GIZMO_PLUS_X_OFFSET,
|
||||
props.width / 2,
|
||||
props.height + self.GIZMO_BUTTON_Z_OFFSET
|
||||
)))
|
||||
@ billboard_rot
|
||||
@ Matrix.Scale(0.2, 4)
|
||||
)
|
||||
self.plus_gizmo.matrix_basis = mw @ plus_local_transform
|
||||
|
||||
if not self.minus_gizmo.hide:
|
||||
minus_local_transform = (
|
||||
Matrix.Translation(Vector((base_x + 0.5, props.width / 2, props.height + 0.15)))
|
||||
@ Matrix.Rotation(math.radians(90), 4, (1.0, 0.0, 0.0))
|
||||
Matrix.Translation(Vector((
|
||||
base_x + self.GIZMO_MINUS_X_OFFSET,
|
||||
props.width / 2,
|
||||
props.height + self.GIZMO_BUTTON_Z_OFFSET
|
||||
)))
|
||||
@ billboard_rot
|
||||
@ Matrix.Scale(0.2, 4)
|
||||
)
|
||||
self.minus_gizmo.matrix_basis = mw @ minus_local_transform
|
||||
|
||||
def update_cycle_gizmo(self, mw, props):
|
||||
"""Update cycle gizmo position - 0.5m above lock gizmo."""
|
||||
def update_cycle_gizmo(self, mw, props, billboard_rot):
|
||||
gizmo_prefs = self.get_gizmo_prefs()
|
||||
self.cycle_gizmo.hide = not props.is_editing or not gizmo_prefs.cycle
|
||||
|
||||
@@ -599,10 +662,23 @@ class GizmoStairEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
return
|
||||
|
||||
total_run = self._get_stair_total_run(props)
|
||||
cycle_x = total_run + props.tread_run + 0.5 # Same X as lock
|
||||
cycle_x = total_run + props.tread_run + self.GIZMO_X_OFFSET
|
||||
local_transform = (
|
||||
Matrix.Translation(Vector((cycle_x, props.width / 2, props.height + 0.5))) # +0.5m above lock
|
||||
@ Matrix.Rotation(math.radians(90), 4, (1.0, 0.0, 0.0))
|
||||
Matrix.Translation(Vector((
|
||||
cycle_x,
|
||||
props.width / 2,
|
||||
props.height + self.GIZMO_CYCLE_Z_OFFSET
|
||||
)))
|
||||
@ billboard_rot
|
||||
@ Matrix.Scale(0.2, 4)
|
||||
)
|
||||
self.cycle_gizmo.matrix_basis = mw @ local_transform
|
||||
|
||||
def draw_prepare(self, context):
|
||||
"""Called before drawing - updates gizmos to face camera."""
|
||||
# Call base class implementation
|
||||
super().draw_prepare(context)
|
||||
|
||||
# Also update the secondary width gizmo to face camera
|
||||
if hasattr(self, "gizmo_width_top") and not self.gizmo_width_top.hide:
|
||||
self.gizmo_width_top.draw_prepare(context)
|
||||
|
||||
@@ -39,6 +39,7 @@ import ifcopenshell.util.shape_builder
|
||||
import ifcopenshell.util.unit
|
||||
from bmesh.types import BMVert
|
||||
from mathutils import Vector, Matrix
|
||||
from typing import get_args
|
||||
|
||||
V_ = tool.Blender.V_
|
||||
|
||||
@@ -579,6 +580,31 @@ class RemoveWindow(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CycleWindowType(bpy.types.Operator, tool.Ifc.Operator):
|
||||
"""Cycle through available window types."""
|
||||
|
||||
bl_idname = "bim.cycle_window_type"
|
||||
bl_label = "Cycle Window Type"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
obj = tool.Blender.get_active_object()
|
||||
if not obj:
|
||||
return {"CANCELLED"}
|
||||
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element or not tool.Blender.Modifier.is_window(element):
|
||||
return {"CANCELLED"}
|
||||
|
||||
props = tool.Model.get_window_props(obj)
|
||||
window_types = list(get_args(tool.Model.WindowType))
|
||||
current_index = window_types.index(props.window_type) if props.window_type in window_types else 0
|
||||
next_index = (current_index + 1) % len(window_types)
|
||||
props.window_type = window_types[next_index]
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class GizmoWindowEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
bl_idname = "OBJECT_GGT_bim_window_edition"
|
||||
bl_label = "Window Editing Gizmo"
|
||||
@@ -589,6 +615,7 @@ class GizmoWindowEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
enable_editing_operator = "bim.enable_editing_window"
|
||||
finish_editing_operator = "bim.finish_editing_window"
|
||||
cancel_editing_operator = "bim.cancel_editing_window"
|
||||
cycle_type_operator = "bim.cycle_window_type"
|
||||
|
||||
gizmo_props = [
|
||||
GizmoPropConfig("overall_height", (0, 0, 1)),
|
||||
@@ -597,10 +624,10 @@ class GizmoWindowEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
GizmoPropConfig("lining_thickness", (1, 0, 0)),
|
||||
GizmoPropConfig("lining_to_panel_offset_x", (1, 0, 0)),
|
||||
GizmoPropConfig("lining_to_panel_offset_y", (0, 1, 0)),
|
||||
GizmoPropConfig("mullion_thickness", (1, 0, 0)),
|
||||
GizmoPropConfig("mullion_thickness", (1, 0, 0), delta_scale=2.0),
|
||||
GizmoPropConfig("first_mullion_offset", (1, 0, 0)),
|
||||
GizmoPropConfig("second_mullion_offset", (1, 0, 0)),
|
||||
GizmoPropConfig("transom_thickness", (0, 0, 1)),
|
||||
GizmoPropConfig("transom_thickness", (0, 0, 1), delta_scale=2.0),
|
||||
GizmoPropConfig("first_transom_offset", (0, 0, 1)),
|
||||
GizmoPropConfig("second_transom_offset", (0, 0, 1)),
|
||||
]
|
||||
@@ -690,6 +717,7 @@ class GizmoWindowEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
return translation @ rotation
|
||||
|
||||
def get_gizmo_matrix_mullion_thickness(self, props):
|
||||
# Position at the right edge of the mullion (offset + thickness/2) so gizmo movement matches property 1:1
|
||||
translation = Matrix.Translation(
|
||||
V_(props.first_mullion_offset + props.mullion_thickness / 2, props.lining_offset, props.overall_height / 2)
|
||||
)
|
||||
@@ -697,7 +725,10 @@ class GizmoWindowEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
return translation @ rotation
|
||||
|
||||
def get_gizmo_matrix_first_mullion_offset(self, props):
|
||||
translation = Matrix.Translation(V_(props.first_mullion_offset, props.lining_offset, props.overall_height / 2))
|
||||
# Position at the left edge of the mullion (offset - thickness/2)
|
||||
translation = Matrix.Translation(
|
||||
V_(props.first_mullion_offset - props.mullion_thickness / 2, props.lining_offset, props.overall_height / 2)
|
||||
)
|
||||
rotation = self.get_axis_rotation_matrix((1, 0, 0))
|
||||
return translation @ rotation
|
||||
|
||||
@@ -707,6 +738,7 @@ class GizmoWindowEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
return translation @ rotation
|
||||
|
||||
def get_gizmo_matrix_transom_thickness(self, props):
|
||||
# Position at the top edge of the transom (offset + thickness/2) so gizmo movement matches property 1:1
|
||||
translation = Matrix.Translation(
|
||||
V_(props.overall_width / 2, props.lining_offset, props.first_transom_offset + props.transom_thickness / 2)
|
||||
)
|
||||
@@ -714,7 +746,10 @@ class GizmoWindowEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
return translation @ rotation
|
||||
|
||||
def get_gizmo_matrix_first_transom_offset(self, props):
|
||||
translation = Matrix.Translation(V_(props.overall_width / 2, props.lining_offset, props.first_transom_offset))
|
||||
# Position at the bottom edge of the transom (offset - thickness/2)
|
||||
translation = Matrix.Translation(
|
||||
V_(props.overall_width / 2, props.lining_offset, props.first_transom_offset - props.transom_thickness / 2)
|
||||
)
|
||||
rotation = self.get_axis_rotation_matrix((0, 0, 1))
|
||||
return translation @ rotation
|
||||
|
||||
@@ -768,4 +803,4 @@ class GizmoWindowEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
props = self.get_props(obj)
|
||||
mw = obj.matrix_world
|
||||
self.update_property_gizmos(mw, props)
|
||||
self.update_editing_gizmos(mw, props)
|
||||
self.update_editing_gizmos(context, mw, props)
|
||||
|
||||
@@ -1401,6 +1401,29 @@ class Model(bonsai.core.tool.Model):
|
||||
|
||||
StairType = Literal["CONCRETE", "WOOD/STEEL", "GENERIC"]
|
||||
|
||||
DoorType = Literal[
|
||||
"SINGLE_SWING_LEFT",
|
||||
"SINGLE_SWING_RIGHT",
|
||||
"DOUBLE_SWING_LEFT",
|
||||
"DOUBLE_SWING_RIGHT",
|
||||
"DOUBLE_DOOR_SINGLE_SWING",
|
||||
"SLIDING_TO_LEFT",
|
||||
"SLIDING_TO_RIGHT",
|
||||
"DOUBLE_DOOR_SLIDING",
|
||||
]
|
||||
|
||||
WindowType = Literal[
|
||||
"SINGLE_PANEL",
|
||||
"DOUBLE_PANEL_HORIZONTAL",
|
||||
"DOUBLE_PANEL_VERTICAL",
|
||||
"TRIPLE_PANEL_BOTTOM",
|
||||
"TRIPLE_PANEL_TOP",
|
||||
"TRIPLE_PANEL_LEFT",
|
||||
"TRIPLE_PANEL_RIGHT",
|
||||
"TRIPLE_PANEL_HORIZONTAL",
|
||||
"TRIPLE_PANEL_VERTICAL",
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def generate_stair_2d_profile(
|
||||
cls,
|
||||
|
||||
Reference in New Issue
Block a user