mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
New wall flip tool with hotkey. Wall aligner now allows flipped walls.
This commit is contained in:
@@ -6,6 +6,7 @@ classes = (
|
|||||||
operator.AddWall,
|
operator.AddWall,
|
||||||
operator.JoinWall,
|
operator.JoinWall,
|
||||||
operator.AlignWall,
|
operator.AlignWall,
|
||||||
|
operator.FlipWall,
|
||||||
prop.BIMModelProperties,
|
prop.BIMModelProperties,
|
||||||
ui.BIM_PT_authoring,
|
ui.BIM_PT_authoring,
|
||||||
ui.BIM_PT_authoring_architectural,
|
ui.BIM_PT_authoring_architectural,
|
||||||
|
|||||||
@@ -124,21 +124,57 @@ class AlignWall(bpy.types.Operator):
|
|||||||
if self.align_type == "CENTERLINE":
|
if self.align_type == "CENTERLINE":
|
||||||
aligner.align_centerline()
|
aligner.align_centerline()
|
||||||
elif self.align_type == "EXTERIOR":
|
elif self.align_type == "EXTERIOR":
|
||||||
aligner.align_exterior()
|
aligner.align_first_layer()
|
||||||
elif self.align_type == "INTERIOR":
|
elif self.align_type == "INTERIOR":
|
||||||
aligner.align_interior()
|
aligner.align_last_layer()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
def recalculate_dumb_wall_origin(wall):
|
class FlipWall(bpy.types.Operator):
|
||||||
new_origin = wall.matrix_world @ Vector(wall.bound_box[0])
|
bl_idname = "bim.flip_wall"
|
||||||
if (wall.matrix_world.translation - new_origin).length > 0.001:
|
bl_label = "Flip Wall"
|
||||||
wall.data.transform(
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
Matrix.Translation(
|
|
||||||
(wall.matrix_world.inverted().to_quaternion() @ (wall.matrix_world.translation - new_origin))
|
def execute(self, context):
|
||||||
)
|
selected_objs = context.selected_objects
|
||||||
|
if len(selected_objs) == 0:
|
||||||
|
return {"FINISHED"}
|
||||||
|
for obj in selected_objs:
|
||||||
|
DumbWallFlipper(obj).flip()
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
def recalculate_dumb_wall_origin(wall, new_origin=None):
|
||||||
|
if new_origin is None:
|
||||||
|
new_origin = wall.matrix_world @ Vector(wall.bound_box[0])
|
||||||
|
if (wall.matrix_world.translation - new_origin).length < 0.001:
|
||||||
|
return
|
||||||
|
wall.data.transform(
|
||||||
|
Matrix.Translation(
|
||||||
|
(wall.matrix_world.inverted().to_quaternion() @ (wall.matrix_world.translation - new_origin))
|
||||||
)
|
)
|
||||||
wall.matrix_world.translation = new_origin
|
)
|
||||||
|
wall.matrix_world.translation = new_origin
|
||||||
|
|
||||||
|
|
||||||
|
class DumbWallFlipper:
|
||||||
|
# A flip switches the origin from the min XY corner to the max XY corner, and rotates the origin by 180.
|
||||||
|
def __init__(self, wall):
|
||||||
|
self.wall = wall
|
||||||
|
|
||||||
|
def flip(self):
|
||||||
|
if (
|
||||||
|
self.wall.matrix_world.translation - self.wall.matrix_world @ Vector(self.wall.bound_box[0])
|
||||||
|
).length < 0.001:
|
||||||
|
recalculate_dumb_wall_origin(self.wall, self.wall.matrix_world @ Vector(self.wall.bound_box[7]))
|
||||||
|
self.rotate_wall_180()
|
||||||
|
else:
|
||||||
|
recalculate_dumb_wall_origin(self.wall)
|
||||||
|
|
||||||
|
def rotate_wall_180(self):
|
||||||
|
flip_matrix = Matrix.Rotation(pi, 4, "Z")
|
||||||
|
self.wall.data.transform(flip_matrix)
|
||||||
|
self.wall.rotation_euler.rotate(flip_matrix)
|
||||||
|
|
||||||
|
|
||||||
class DumbWallAligner:
|
class DumbWallAligner:
|
||||||
@@ -150,37 +186,71 @@ class DumbWallAligner:
|
|||||||
self.reference_wall = reference_wall
|
self.reference_wall = reference_wall
|
||||||
|
|
||||||
def align_centerline(self):
|
def align_centerline(self):
|
||||||
|
recalculate_dumb_wall_origin(self.wall)
|
||||||
|
recalculate_dumb_wall_origin(self.reference_wall)
|
||||||
|
self.align_rotation()
|
||||||
|
|
||||||
width = (Vector(self.wall.bound_box[3]) - Vector(self.wall.bound_box[0])).y
|
width = (Vector(self.wall.bound_box[3]) - Vector(self.wall.bound_box[0])).y
|
||||||
reference_width = (Vector(self.reference_wall.bound_box[3]) - Vector(self.reference_wall.bound_box[0])).y
|
reference_width = (Vector(self.reference_wall.bound_box[3]) - Vector(self.reference_wall.bound_box[0])).y
|
||||||
offset = self.wall.matrix_world.to_quaternion() @ Vector((0, (reference_width / 2) - (width / 2), 0))
|
|
||||||
|
if self.is_rotation_flipped():
|
||||||
|
offset = self.wall.matrix_world.to_quaternion() @ Vector((0, - (reference_width / 2) - (width / 2), 0))
|
||||||
|
else:
|
||||||
|
offset = self.wall.matrix_world.to_quaternion() @ Vector((0, (reference_width / 2) - (width / 2), 0))
|
||||||
|
|
||||||
self.align(
|
self.align(
|
||||||
self.reference_wall.matrix_world @ Vector(self.reference_wall.bound_box[0]),
|
self.reference_wall.matrix_world @ Vector(self.reference_wall.bound_box[0]),
|
||||||
self.reference_wall.matrix_world @ Vector(self.reference_wall.bound_box[4]),
|
self.reference_wall.matrix_world @ Vector(self.reference_wall.bound_box[4]),
|
||||||
offset,
|
offset,
|
||||||
)
|
)
|
||||||
|
|
||||||
def align_exterior(self):
|
def align_last_layer(self):
|
||||||
wall_width = (Vector(self.wall.bound_box[3]) - Vector(self.wall.bound_box[0])).y
|
recalculate_dumb_wall_origin(self.wall)
|
||||||
offset = self.wall.matrix_world.to_quaternion() @ Vector((0, -wall_width, 0))
|
recalculate_dumb_wall_origin(self.reference_wall)
|
||||||
self.align(
|
self.align_rotation()
|
||||||
self.reference_wall.matrix_world @ Vector(self.reference_wall.bound_box[3]),
|
|
||||||
self.reference_wall.matrix_world @ Vector(self.reference_wall.bound_box[7]),
|
|
||||||
offset,
|
|
||||||
)
|
|
||||||
|
|
||||||
def align_interior(self):
|
if self.is_rotation_flipped():
|
||||||
self.align(self.reference_wall.matrix_world.translation, self.reference_wall.matrix_world @ Vector((1, 0, 0)))
|
DumbWallFlipper(self.wall).flip()
|
||||||
|
bpy.context.view_layer.update()
|
||||||
|
start = self.reference_wall.matrix_world @ Vector(self.reference_wall.bound_box[3])
|
||||||
|
end = self.reference_wall.matrix_world @ Vector(self.reference_wall.bound_box[7])
|
||||||
|
|
||||||
|
wall_width = (Vector(self.wall.bound_box[3]) - Vector(self.wall.bound_box[0])).y
|
||||||
|
|
||||||
|
offset = self.wall.matrix_world.to_quaternion() @ Vector((0, -wall_width, 0))
|
||||||
|
self.align(start, end, offset)
|
||||||
|
|
||||||
|
def align_first_layer(self):
|
||||||
|
recalculate_dumb_wall_origin(self.wall)
|
||||||
|
recalculate_dumb_wall_origin(self.reference_wall)
|
||||||
|
self.align_rotation()
|
||||||
|
|
||||||
|
if self.is_rotation_flipped():
|
||||||
|
DumbWallFlipper(self.wall).flip()
|
||||||
|
bpy.context.view_layer.update()
|
||||||
|
|
||||||
|
start = self.reference_wall.matrix_world @ Vector(self.reference_wall.bound_box[0])
|
||||||
|
end = self.reference_wall.matrix_world @ Vector(self.reference_wall.bound_box[4])
|
||||||
|
|
||||||
|
self.align(start, end)
|
||||||
|
|
||||||
def align(self, start, end, offset=None):
|
def align(self, start, end, offset=None):
|
||||||
if offset is None:
|
if offset is None:
|
||||||
offset = Vector()
|
offset = Vector((0, 0, 0))
|
||||||
recalculate_dumb_wall_origin(self.wall)
|
|
||||||
recalculate_dumb_wall_origin(self.reference_wall)
|
|
||||||
point, distance = mathutils.geometry.intersect_point_line(self.wall.matrix_world.translation, start, end)
|
point, distance = mathutils.geometry.intersect_point_line(self.wall.matrix_world.translation, start, end)
|
||||||
new_origin = point + offset
|
new_origin = point + offset
|
||||||
self.wall.matrix_world.translation[0] = new_origin[0]
|
self.wall.matrix_world.translation[0] = new_origin[0]
|
||||||
self.wall.matrix_world.translation[1] = new_origin[1]
|
self.wall.matrix_world.translation[1] = new_origin[1]
|
||||||
self.wall.rotation_euler[2] = self.reference_wall.rotation_euler[2]
|
|
||||||
|
def align_rotation(self):
|
||||||
|
reference_rotation = self.reference_wall.rotation_euler[2] % (2 * pi)
|
||||||
|
self.wall.rotation_euler[2] = (pi * round(self.wall.rotation_euler[2] / pi)) + reference_rotation
|
||||||
|
|
||||||
|
def is_rotation_flipped(self):
|
||||||
|
pi2 = pi * 2
|
||||||
|
wall_delta_to_nearest_360 = abs((pi2 * round(self.wall.rotation_euler[2] / pi2)) - self.wall.rotation_euler[2])
|
||||||
|
reference_delta_to_nearest_360 = abs((pi2 * round(self.reference_wall.rotation_euler[2] / pi2)) - self.reference_wall.rotation_euler[2])
|
||||||
|
return abs(reference_delta_to_nearest_360 - wall_delta_to_nearest_360) > 0.1
|
||||||
|
|
||||||
|
|
||||||
class DumbWallJoiner:
|
class DumbWallJoiner:
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ class BIM_PT_authoring_architectural(Panel):
|
|||||||
row.operator("bim.align_wall", icon="ANCHOR_TOP", text="Ext.").align_type = "EXTERIOR"
|
row.operator("bim.align_wall", icon="ANCHOR_TOP", text="Ext.").align_type = "EXTERIOR"
|
||||||
row.operator("bim.align_wall", icon="ANCHOR_CENTER", text="C/L").align_type = "CENTERLINE"
|
row.operator("bim.align_wall", icon="ANCHOR_CENTER", text="C/L").align_type = "CENTERLINE"
|
||||||
row.operator("bim.align_wall", icon="ANCHOR_BOTTOM", text="Int.").align_type = "INTERIOR"
|
row.operator("bim.align_wall", icon="ANCHOR_BOTTOM", text="Int.").align_type = "INTERIOR"
|
||||||
|
row = self.layout.row(align=True)
|
||||||
|
row.operator("bim.flip_wall", icon="ORIENTATION_NORMAL", text="Flip")
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_misc_utilities(Panel):
|
class BIM_PT_misc_utilities(Panel):
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class WallTool(WorkSpaceTool):
|
|||||||
("bim.join_wall", {"type": "E", "value": "PRESS", "shift": True}, {"properties": [("join_type", "T")]}),
|
("bim.join_wall", {"type": "E", "value": "PRESS", "shift": True}, {"properties": [("join_type", "T")]}),
|
||||||
("bim.join_wall", {"type": "T", "value": "PRESS", "shift": True}, {"properties": [("join_type", "L")]}),
|
("bim.join_wall", {"type": "T", "value": "PRESS", "shift": True}, {"properties": [("join_type", "L")]}),
|
||||||
("bim.join_wall", {"type": "Y", "value": "PRESS", "shift": True}, {"properties": [("join_type", "V")]}),
|
("bim.join_wall", {"type": "Y", "value": "PRESS", "shift": True}, {"properties": [("join_type", "V")]}),
|
||||||
|
("bim.flip_wall", {"type": "F", "value": "PRESS", "shift": True}, {"properties": []}),
|
||||||
(
|
(
|
||||||
"bim.align_wall",
|
"bim.align_wall",
|
||||||
{"type": "X", "value": "PRESS", "shift": True},
|
{"type": "X", "value": "PRESS", "shift": True},
|
||||||
|
|||||||
Reference in New Issue
Block a user