mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-09 21:53:40 +00:00
The align tool now works on any generic product, not just walls.
This commit is contained in:
@@ -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")
|
||||||
|
|||||||
Reference in New Issue
Block a user