Wish: Align to Object option

It would be nice if one of the options for Align were CPlane, World, and then Object. You could then align to the top, bottom, left, right, horizcenter, vertcenter, or center of an object quickly and efficiently, and could be sped up even further with macros.

Best,
Paul

can you show what you are trying to do? I generally find that gumbal set to snappy dragging and using osnaps has replaced my need for any type of alignment tools.

Hi Kyle,

Thanks, I gave the snappy gumball a try. Let’s say, for instance, I want to align the bottom of the lower square to the top of the upper square in this example. Seems like this would not be possible without first moving the gumball location.

I think what I was thinking about was the ability to simply click anywhere on the object and have the other object auto-align to top, left, right, bottom, etc.

Hi Paul - I may be missing the question but this seems to me how it works now.

Select the bottom square, the one to move, if I understand, and start Align. Set the alignment to ‘Bottom’ and then snap any location on the top line of the upper square (Near, Mid, or End snaps)…?

image

Is that what we want?

-Pascal

yes, you need to move the gumball, which you can hotkey in v7 (gumballrelocate is the command to hotkey) or in v8 you simply double click the gumball origin to relocate it. snap the gumball to your transform origin and move the object with snappy dragging. I have found this to be a super efficient way to move stuff and in v8, the double click to relocate the gumball is quite elegant.

1 Like

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()

I think what makes it (very slightly) more efficient is that there is higher tolerance for error using the mouse, so instead of having to precisely find the point you can just click the object.