Autolabel by Layer name

Hi All,

I’ve got around 400 objects i need to send to the CNC - Each part is different.

As the CNC program we use can read layer names i would like to set each object to a different layer name. For example in Rhino I will have a main layer folder named - “Slats” then sub folders inside this labelled with the item numbers - “S001,S002,S003” ETC. That way our CNC guys can auto nest parts and then the layer name can also be placed on the part automatically.

I found a script which would label each part up, but only by object name not by layer.

As per attached below;

Autolabel.3dm (76.5 KB)

Has anyone used a script to do this or know a quick way to assign each part to a different layer?

Thanks,

Jed

You’re kind of already explaining what you need to do. :smile:
So in the script you’ll need to check for the object later instead of the object name. Have a look at objectlayer in rhinoscriptsyntax.

Thanks for your reply.

I know little to nothing about rhino python (I would love to learn however)

The below was the script i copied to set object names

import rhinoscriptsyntax as rs

AutoLabel Subroutine

def AutoLabel():
# Select objects
arrObjects = rs.GetObjects(“Select objects to name”)
if not arrObjects: return

# Prompt for a prefix to add to the labels
name = rs.GetString("Prefix for labels, press Enter for none")
if name is None: name = ""

# Prompt for a suffix starting number
suffix = rs.GetInteger("Starting base number to increment",0)
if suffix is None: return

# Prompt for direction
dirPoint1 = rs.GetPoint("Base point for sort direction")
if not dirPoint1: return
dirPoint2 = rs.GetPoint("Pick point for sort direction", dirPoint1)
if not dirPoint2: return

# Initialize collection
collection = []

# Process each seleted object
for obj in arrObjects:
    # Process curves
    if rs.IsCurve(obj):
        # Get the curve starting point
        point = rs.CurveStartPoint(obj)
        collection.append( (point, obj) )

    # Process surfaces
    if rs.IsSurface(obj):
        # Get the Surface center point
        point, error = rs.SurfaceAreaCentroid(obj)
        collection.append( (point, obj) )

    # Process points
    if rs.IsPoint(obj):
        # Get the Point Corrdinates point
        point = rs.PointCoordinates(obj)
        collection.append( (point, obj) )

    # TODO: add support for additional object types here

# Determine Direction of sort for each axis
sortDir = dirPoint2 - dirPoint1
# compare function for sorting
def sortcompare(a, b):
    pointa, pointb = a[0], b[0]
    rc = cmp(pointa.X, pointb.X)
    if sortDir.X<0: rc = -1*rc
    if rc==0:
        rc = cmp(pointa.Y, pointb.Y)
        if sortDir.Y<0: rc = -1*rc
    if rc==0:
        rc = cmp(pointa.Z, pointb.Z)
        if sortDir.Z<0: rc = -1*rc
    return rc
# sort the collection
collection = sorted(collection, sortcompare)

# Process each item in the collection
for point, item in collection:
    #Curves need to have the textdot at thier Midpoint
    if rs.IsCurve(item): point = rs.CurveMidPoint(item)
    # Add a text dot at the point location
    dot = rs.AddTextDot(name + str(suffix), point)
    # Set the dot name to the originating object
    rs.ObjectName(dot, item)
    rs.ObjectName(item, name+str(suffix))
    rs.SetUserText(item, "AutoCount::DotUuid", dot)
    suffix += 1

if name==“main”:
AutoLabel()

I found the above script here;

https://wiki.mcneel.com/developer/scriptsamples/autolabel

Would it simply be as easy as chaging ObjectName to LayerName? Or i imagine there is a bit more to it?

Hi,

selection_to_layers.py (825 Bytes)
This example will ask for the objects and place them in layers starting with ‘S’ (LAYER_PREFIX= ‘S’) and a 3 digit serial like so:

S001
S002
S003

import rhinoscriptsyntax as rs



def objects_to_layers():
    
    
    LAYER_PREFIX = 'S'
    
    all_ids = rs.GetObjects('select objects to layerize')
    if not(all_ids): return
    
    #test for existing layernames
    existing = []
    for i in range(len(all_ids)):
        layer_name = '{}{:03d}'.format(LAYER_PREFIX,i+1)
        if rs.IsLayer(layer_name):
            existing.append(layer_name)
    
    if existing:
        msg  = 'STOPPING:\nLayer conflict with existing layers:\n'
        msg += '\n'.join(existing)
        rs.MessageBox(msg)
        return
    
    for i,id in enumerate(all_ids):
        layer_name = '{}{:03d}'.format(LAYER_PREFIX,i+1)
        rs.AddLayer(layer_name)
        rs.ObjectLayer(id, layer_name)
    

objects_to_layers()

Does this make sense?
-Willem

Hi Willem,

Thanks for your help!

That’s worked perfectly

The only issue I’m having is that when i select all 400 Objects it looks like it is assigning the layer name based on the Objects ID. So when i run it they’re not necessarily in the order that i want. I could individually click on each object in the order i want and that seems to work, but that would mean clicking 400 times.

Thanks again for your help, it’s much appreicated

Jed

Hi Jed,

I had to do some waiting on some testruns to finish so I made this script to also sort the input based on a seed object you select:

sorted_layerized.py (2.3 KB)

import rhinoscriptsyntax as rs

def proximitysort(ids, seed_id):
    
    
    class BoxSorter(object):
        
        def __init__(self, id):
            self.id = id
            bbox= rs.BoundingBox(id)
            self.cpt = 0.5 * (bbox[0]+bbox[6])
            self.distances = {}

        def distance_to(self,other):
            return rs.Distance(self.cpt, other.cpt)

    #create classed containing id and boundingbox center
    box_sorters = [BoxSorter(id) for id in ids]
    
    
    #store distances in dictionaries
    for bs1 in box_sorters:
        for bs2 in box_sorters:
            if bs1 == bs2 : continue
            if bs1.id in bs2.distances: continue
            
            distance = bs1.distance_to(bs2)
            bs1.distances[bs2.id] = distance
            bs2.distances[bs1.id] = distance
            
            
    
    #get seed_box and others
    seed_box = [bs for bs in box_sorters if bs.id == seed_id][0]
    
    
    sorted_boxes = [seed_box.id]
    
    other_boxes = [bs for bs in box_sorters if not bs == seed_box]
    
    while other_boxes:
        other_boxes.sort(key= lambda bs : bs.distances[sorted_boxes[-1]])
        sorted_boxes.append(other_boxes[0].id)
        other_boxes= other_boxes[1:]

    return sorted_boxes



def objects_to_layers():
    
    
    LAYER_PREFIX = 'S'
    
    all_ids = rs.GetObjects('select objects to layerize')
    if not(all_ids): return
    
    seed_id = rs.GetObject('Select first object')
    if not seed_id: return
    if not seed_id in all_ids:
        rs.MessageBox('ERROR: first object not in previous selection')
        return
        
        
        
    all_ids = proximitysort(all_ids, seed_id)
    
    
    #test for existing layernames
    existing = []
    for i in range(len(all_ids)):
        layer_name = '{}{:03d}'.format(LAYER_PREFIX,i+1)
        if rs.IsLayer(layer_name):
            existing.append(layer_name)
    
    if existing:
        msg  = 'STOPPING:\nLayer conflict with existing layers:\n'
        msg += '\n'.join(existing)
        rs.MessageBox(msg)
        return
    
    for i,id in enumerate(all_ids):
        layer_name = '{}{:03d}'.format(LAYER_PREFIX,i+1)
        rs.AddLayer(layer_name)
        rs.ObjectLayer(id, layer_name)
    

objects_to_layers()

Hope you did not yet selected all 400 by hand :wink:

-Willem

3 Likes

Hi Willem,

You’ve saved me a lot of clicking, thank you so much for that!

I want to start looking up some tutorials for pythonscript soon, i would love to be able to do all this myself.

Thanks again

Jed,

2 Likes

Me again!

I know I’m probably asking too much and i appreciate people don’t have spare time just to find/create scripts for me.

But just wanted to see if it was possible to find a way to write a text label on the part. (I know this seems backwards as I’ve already got the item name in the layer)

So from having a part on its correct layer, say for example Part No. 40, would i be able to somehow click the part to pull the layer name as text on the part?

For example see picture below

Thanks,

Jed

https://www.rhino3d.com/download/ironpython/5.0/rhinopython101

1 Like

Point taken

I do want to learn, so guess its a good time to start!

Thanks,

Jed

1 Like

I found a similar script in the end;

1 Like