The align tool now works on any generic product, not just walls.

This commit is contained in:
Dion Moult
2021-07-17 21:36:03 +10:00
parent 1bf136e93c
commit 02dc7b5274
3 changed files with 87 additions and 28 deletions
@@ -3,7 +3,8 @@ from . import handler, prop, ui, grid, product, wall, slab, stair, door, window,
classes = ( classes = (
product.AddTypeInstance, product.AddTypeInstance,
workspace.HotkeyE, product.AlignProduct,
workspace.Hotkey,
wall.JoinWall, wall.JoinWall,
wall.AlignWall, wall.AlignWall,
wall.FlipWall, wall.FlipWall,
@@ -1,4 +1,5 @@
import bpy import bpy
import mathutils
import ifcopenshell import ifcopenshell
import ifcopenshell.api import ifcopenshell.api
import ifcopenshell.util.element import ifcopenshell.util.element
@@ -6,7 +7,7 @@ import ifcopenshell.util.representation
from . import wall, slab, column from . import wall, slab, column
from blenderbim.bim.ifc import IfcStore from blenderbim.bim.ifc import IfcStore
from ifcopenshell.api.pset.data import Data as PsetData from ifcopenshell.api.pset.data import Data as PsetData
from mathutils import Vector from mathutils import Vector, Matrix
class AddTypeInstance(bpy.types.Operator): class AddTypeInstance(bpy.types.Operator):
@@ -73,6 +74,52 @@ class AddTypeInstance(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
class AlignProduct(bpy.types.Operator):
bl_idname = "bim.align_product"
bl_label = "Align Wall"
bl_options = {"REGISTER", "UNDO"}
align_type: bpy.props.StringProperty()
def execute(self, context):
selected_objs = context.selected_objects
if len(selected_objs) < 2 or not context.active_object:
return {"FINISHED"}
if self.align_type == "CENTERLINE":
point = context.active_object.matrix_world @ (
Vector(context.active_object.bound_box[0]) + (context.active_object.dimensions / 2)
)
elif self.align_type == "POSITIVE":
point = context.active_object.matrix_world @ Vector(context.active_object.bound_box[6])
elif self.align_type == "NEGATIVE":
point = context.active_object.matrix_world @ Vector(context.active_object.bound_box[0])
active_x_axis = context.active_object.matrix_world.to_quaternion() @ Vector((1, 0, 0))
active_y_axis = context.active_object.matrix_world.to_quaternion() @ Vector((0, 1, 0))
active_z_axis = context.active_object.matrix_world.to_quaternion() @ Vector((0, 0, 1))
x_distances = self.get_axis_distances(point, active_x_axis)
y_distances = self.get_axis_distances(point, active_y_axis)
if abs(sum(x_distances)) < abs(sum(y_distances)):
for i, obj in enumerate(selected_objs):
obj.matrix_world = Matrix.Translation(active_x_axis * -x_distances[i]) @ obj.matrix_world
else:
for i, obj in enumerate(selected_objs):
obj.matrix_world = Matrix.Translation(active_y_axis * -y_distances[i]) @ obj.matrix_world
return {"FINISHED"}
def get_axis_distances(self, point, axis):
results = []
for obj in bpy.context.selected_objects:
if self.align_type == "CENTERLINE":
obj_point = obj.matrix_world @ (Vector(obj.bound_box[0]) + (obj.dimensions / 2))
elif self.align_type == "POSITIVE":
obj_point = obj.matrix_world @ Vector(obj.bound_box[6])
elif self.align_type == "NEGATIVE":
obj_point = obj.matrix_world @ Vector(obj.bound_box[0])
results.append(mathutils.geometry.distance_point_to_plane(obj_point, point, axis))
return results
def generate_box(usecase_path, ifc_file, settings): def generate_box(usecase_path, ifc_file, settings):
box_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Box", "MODEL_VIEW") box_context = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Box", "MODEL_VIEW")
if not box_context: if not box_context:
@@ -18,26 +18,14 @@ class BimTool(WorkSpaceTool):
# ("bim.wall_tool_op", {"type": 'MOUSEMOVE', "value": 'ANY'}, {"properties": []}), # ("bim.wall_tool_op", {"type": 'MOUSEMOVE', "value": 'ANY'}, {"properties": []}),
# ("mesh.add_wall", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": []}), # ("mesh.add_wall", {"type": 'LEFTMOUSE', "value": 'PRESS'}, {"properties": []}),
("bim.add_type_instance", {"type": "A", "value": "PRESS", "shift": True}, {"properties": []}), ("bim.add_type_instance", {"type": "A", "value": "PRESS", "shift": True}, {"properties": []}),
("bim.hotkey_e", {"type": "E", "value": "PRESS", "shift": True}, {"properties": []}), ("bim.hotkey", {"type": "E", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "E")]}),
("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.flip_wall", {"type": "F", "value": "PRESS", "shift": True}, {"properties": []}),
("bim.split_wall", {"type": "S", "value": "PRESS", "shift": True}, {"properties": []}), ("bim.split_wall", {"type": "S", "value": "PRESS", "shift": True}, {"properties": []}),
( ("bim.hotkey", {"type": "X", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "X")]}),
"bim.align_wall", ("bim.hotkey", {"type": "C", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "C")]}),
{"type": "X", "value": "PRESS", "shift": True}, ("bim.hotkey", {"type": "V", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "V")]}),
{"properties": [("align_type", "EXTERIOR")]},
),
(
"bim.align_wall",
{"type": "C", "value": "PRESS", "shift": True},
{"properties": [("align_type", "CENTERLINE")]},
),
(
"bim.align_wall",
{"type": "V", "value": "PRESS", "shift": True},
{"properties": [("align_type", "INTERIOR")]},
),
) )
def draw_settings(context, layout, tool): def draw_settings(context, layout, tool):
@@ -57,22 +45,45 @@ class BimTool(WorkSpaceTool):
row.label(text="Mitre", icon="EVENT_Y") row.label(text="Mitre", icon="EVENT_Y")
row.label(text="Flip", icon="EVENT_F") row.label(text="Flip", icon="EVENT_F")
row.label(text="Split", icon="EVENT_S") row.label(text="Split", icon="EVENT_S")
row.label(text="", icon="EVENT_X")
row.label(text="", icon="EVENT_C") row.label(text="", icon="EVENT_X")
row.label(text="", icon="EVENT_V") row.label(text="", icon="EVENT_C")
row.label(text="Align") row.label(text="", icon="EVENT_V")
row.label(text="Align")
class HotkeyE(bpy.types.Operator): class Hotkey(bpy.types.Operator):
bl_idname = "bim.hotkey_e" bl_idname = "bim.hotkey"
bl_label = "Hotkey E" bl_label = "Hotkey"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
hotkey: bpy.props.StringProperty()
def execute(self, context): def execute(self, context):
return IfcStore.execute_ifc_operator(self, context) return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context): def _execute(self, context):
props = context.scene.BIMTypeProperties self.props = context.scene.BIMTypeProperties
if props.ifc_class == "IfcWallType": getattr(self, f"hotkey_{self.hotkey}")()
bpy.ops.bim.join_wall(join_type="T")
return {"FINISHED"} return {"FINISHED"}
def hotkey_C(self):
if self.props.ifc_class == "IfcWallType":
bpy.ops.bim.align_wall(align_type="CENTERLINE")
else:
bpy.ops.bim.align_product(align_type="CENTERLINE")
def hotkey_E(self):
if self.props.ifc_class == "IfcWallType":
bpy.ops.bim.join_wall(join_type="T")
def hotkey_V(self):
if self.props.ifc_class == "IfcWallType":
bpy.ops.bim.align_wall(align_type="INTERIOR")
else:
bpy.ops.bim.align_product(align_type="POSITIVE")
def hotkey_X(self):
if self.props.ifc_class == "IfcWallType":
bpy.ops.bim.align_wall(align_type="EXTERIOR")
else:
bpy.ops.bim.align_product(align_type="NEGATIVE")