Thanks both,
I wrote a script with ChatGPT that pretty much did what I’m after (with a couple of errors in some of the viewports), but I think with the ability to move the Snappy Gumball using a double click that does indeed create a more elegant way to move objects without align commands.
Regardless, here’s the script for reference. Essentially it aligns using the bounding boxes of two objects, rather than aligning to a point:
import rhinoscriptsyntax as rs
def AlignToObject():
# Alignment options
align_options = [“VertCenter”, “HorizCenter”, “Top”, “Bottom”, “Left”, “Right”, “Concentric”]
# Check if an object is pre-selected
object_to_align = rs.GetObject("Select object to align") if not rs.SelectedObjects() else rs.SelectedObjects()[0]
if not object_to_align: return
# Choose alignment option via command line
alignment = rs.GetString("Enter alignment option", None, align_options)
if not alignment or alignment not in align_options: return
# Select the reference object
ref_object = rs.GetObject("Select object to align to")
if not ref_object: return
# Determine the active viewport and its orientation
view_name = rs.CurrentView()
view_info = rs.ViewCPlane(view_name)
# Apply alignment
align_objects(object_to_align, ref_object, alignment, view_info)
def align_objects(obj_to_align, ref_obj, alignment, view_info):
# Get bounding boxes for objects
ref_box = rs.BoundingBox(ref_obj)
target_box = rs.BoundingBox(obj_to_align)
if not ref_box or not target_box: return
# Calculate translation based on alignment and view
translation = calculate_translation(alignment, ref_box, target_box, view_info)
# Apply transformation
rs.MoveObject(obj_to_align, translation)
# Provide feedback
print("Object aligned to reference using " + alignment + " in " + rs.CurrentView() + " view.")
def calculate_translation(alignment, ref_box, target_box, view_info):
translation = [0, 0, 0]
view_normal = view_info.Normal
is_top_view = view_normal == rs.VectorCreate([0,0,1], [0,0,0])
is_front_view = view_normal == rs.VectorCreate([0,-1,0], [0,0,0])
is_right_view = view_normal == rs.VectorCreate([1,0,0], [0,0,0])
if alignment == "VertCenter":
if is_front_view:
translation[0] = (ref_box[1][0] + ref_box[0][0]) / 2 - (target_box[1][0] + target_box[0][0]) / 2
else:
translation[1] = (ref_box[3][1] + ref_box[0][1]) / 2 - (target_box[3][1] + target_box[0][1]) / 2
elif alignment == "HorizCenter":
if is_front_view:
translation[2] = (ref_box[4][2] + ref_box[0][2]) / 2 - (target_box[4][2] + target_box[0][2]) / 2
elif is_right_view:
translation[2] = (ref_box[4][2] + ref_box[0][2]) / 2 - (target_box[4][2] + target_box[0][2]) / 2
else:
translation[0] = (ref_box[1][0] + ref_box[0][0]) / 2 - (target_box[1][0] + target_box[0][0]) / 2
elif alignment == "Top":
if is_top_view:
translation[1] = ref_box[3][1] - target_box[3][1]
else:
translation[2] = ref_box[4][2] - target_box[4][2]
elif alignment == "Bottom":
if is_top_view:
translation[1] = ref_box[0][1] - target_box[0][1]
else:
translation[2] = ref_box[0][2] - target_box[0][2]
elif alignment == "Left":
if is_right_view:
translation[2] = ref_box[0][2] - target_box[0][2]
else:
translation[0] = ref_box[0][0] - target_box[0][0]
elif alignment == "Right":
if is_right_view:
translation[2] = ref_box[1][2] - target_box[1][2]
else:
translation[0] = ref_box[1][0] - target_box[1][0]
elif alignment == "Concentric":
ref_center = rs.PointAdd(ref_box[0], rs.PointScale(rs.PointSubtract(ref_box[6], ref_box[0]), 0.5))
target_center = rs.PointAdd(target_box[0], rs.PointScale(rs.PointSubtract(target_box[6], target_box[0]), 0.5))
translation = rs.PointSubtract(ref_center, target_center)
return translation
Run the command
AlignToObject()