Alignment objects at the same distance from each other


Hi all.
This is the UV Curve of cylinder, which has a 60 mm in length.
In this example, there are three united groups inside the bounding boxes.
These groups need to be distributed at the same distance from each other.

In manual I make calculations as follows:

I use the addition operation, length of each BB group together (10.84 + 13.19 + 20.97 = 45), then the resulting value subtract from the length of UV curve (60 - 45 = 15).

The resulting difference (15) is divided into the number of objects or groups (3) 15/3 = 5
This value (5) will be the same distance between objects.
One of the distances (5) divide into 2. 5/2 = 2.5. The resulting value (2.5) will be the distance from the left and right sides of UV curve.

Can someone help write a script that would make these calculations and move objects automatically?

Thanks in advance.

Don’t forget to calculate the height of the text too, to keep the same aspect ratio, to preserve the design’s look. To cram 19 capital letters into 60mm of length, I’m guessing each must be 2-3mm high, for the result to be legible (from close up).

It’s well worth checking nothing that does this already exists. It’s straightforward to produce a simple script. The padding calculation itself is only 1 line.

Will the text direction always be aligned with the x-axis?
Are the text objects always going to neatly start from the left edge?
Is the user going to select the text objects and containing box, or can the script work on all the text boxes and containers it finds?

It all depends how you’d like to run it too, e.g. from Rhinoscript or Grasshopper.

Hi James -
This is a small part of the jewelry ring, just the area of ​​the words.
As a rule, I make UV Crv. And I use flat elements in the group or separate curves.
It can be letters, markup for precious stones or seamless ornament.
Usually, the UV Crv is located the long side along the X axis.
I’m not interested in vertical distances, it is always handmade.

In the script I would like any objects that are grouped to be perceived as a single object.
There is no difference for me Rhinoscript or Python. But wouldn’t want from Grasshopper.

There should be the same distance on the left and right sides. Exactly half of the calculated length.

Does it help?

Maybe this pseudo code helps (not guaranteed error free):

#pseudo code:
words = [<objects>]
total_length = <float>
word_lengths = [<float>]

words_length =0
for wl in word_lengths:
    words_length += wl

remainder = total_length-words_length
am = len(words)
increment = remainder / am
pos_x = increment/2
for i, word in enumerate(words):
    if i = am-1:
        break
    word.xpos  = pos_x
    pox_x += increment
    pos_x += word_lengths[i]

Hi Gijs, and thank you for your help.
I try and try, but I can’t understand what I’m doing)
I’m getting multiple errors.



import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc

def AlignObjs():
    frame=rs.GetObjects("Select frame")
    objects=rs.GetObjects("Select objects to align")
    
    
    total_length = frame
    words_length = objects
    
    words_length =0
    for wl in words_length:
        words_length += wl

    remainder = total_length-words_length
    am = len(words)
    increment = remainder / am
    pos_x = increment/2
    for i, word in enumerate(words):
       if i == am-1:
           break
    word.xpos = pos_x
    pox_x += increment
    pos_x += word_lengths[i]
AlignObjs()






I didn’t try your code, but to check for equality you need to use == (2 characters).

1 equal sign (=) is the assignment operator
2 equal signs (==) is the equality operator

-Kevin

1 Like

Thank you Kevin.
Next error now.
How to solve it?

Backspace so the beginning of line 25 matches the vertical line shown on lines 24 & 26 (need to do same on following lines).

-Kevin

1 Like

(post deleted by author)

I think this does what you’re looking for.

import rhinoscriptsyntax as rs

def AlignObjs():
    frame = rs.GetObjects("Select frame")
    frame_bbox = rs.BoundingBox(frame)
    frame_left = frame_bbox[0][0]
    frame_width = abs(frame_bbox[0][0] - frame_bbox[1][0])
    
    objects = rs.GetObjects("Select objects to align")
    bboxes = [rs.BoundingBox(obj) for obj in objects]
    widths = [abs(bbox[0][0] - bbox[1][0]) for bbox in bboxes]
    x_positions = [bbox[0][0] for bbox in bboxes]

    width_sum = sum(widths)
    gap = (frame_width - width_sum) / len(objects)
    current_x = frame_left + (gap/2)
    
    for i, obj in enumerate(objects):
        transform = [current_x - x_positions[i] ,0 ,0]
        rs.MoveObject(obj, transform)
        current_x += widths[i] + gap

AlignObjs()

space_objects.py (752 Bytes)

Items are placed from left to right following their selection order.

-Kevin

Hi Kevin
This is exactly what I’m looking for.
Thank you very much for your support!

Is there a way not to move the elements inside the groups?
The first thing that come to mind is convert groups to blocks and run script.

Is there a way not to violate the order of elements, sort from left to right and align in order?
If there are many elements, it will be very difficult to chose for each individually.

Using blocks, It may not be the best idea.
But I did not find another way to freeze the groups.
It works. I got this code from Mitch. https://discourse.mcneel.com/t/group-to-block
It remains to align in order.

import rhinoscriptsyntax as rs

def onegroup_filt(rhino_object, geometry, component_index):
    return rhino_object.GroupCount==1
    
    
def ConvertGroupsToBlocks():
    msg="Select group of objects to convert to block"
    objs=rs.GetObjects(msg,group=True,preselect=True,custom_filter=onegroup_filt)
    if not objs: return
    group_set=set()
    for obj in objs:
        obj_g_names=rs.ObjectGroups(obj)
        for g_name in obj_g_names:
            group_set.add(g_name)
    all_obj_groups=list(group_set)
    
    #all_obj_groups should now contain unique list of groups
    for group in all_obj_groups:
        g_objs=rs.ObjectsByGroup(group)
        origin=rs.coerce3dpoint([0,0,0])
        block=rs.AddBlock(g_objs,origin,group,delete_input=True)
        rs.InsertBlock(block,origin)
    
ConvertGroupsToBlocks()



def AlignObjs():
    frame = rs.GetObjects("Select frame")
    frame_bbox = rs.BoundingBox(frame)
    frame_left = frame_bbox[0][0]
    frame_width = abs(frame_bbox[0][0] - frame_bbox[1][0])

    objects = rs.GetObjects("Select objects to align")
    bboxes = [rs.BoundingBox(obj) for obj in objects]
    widths = [abs(bbox[0][0] - bbox[1][0]) for bbox in bboxes]
    x_positions = [bbox[0][0] for bbox in bboxes]

    width_sum = sum(widths)
    gap = (frame_width - width_sum) / len(objects)
    current_x = frame_left + (gap/2)
    
    for i, obj in enumerate(objects):
        transform = [current_x - x_positions[i] ,0 ,0]
        rs.MoveObject(obj, transform)
        current_x += widths[i] + gap
        rs.UnselectAllObjects()

AlignObjs()