Assign Random Color HSV Values to One or More New Layers

Starting a new thread with more specific details (and my last one got a bit hi-jacked :innocent:)

@Helvetosaur I was hoping maybe you had a thought about this?

Using Python, would like to ask user how many sublayers named “sol_” they’d like to create as a child of a newly created layer.

Then I’d like to assign random colors to those “sol_” layers, within certain HSV parameters.

#Create Random Light Color

def random_color_light():
    h=random.random()
    s=random.uniform(0.2,0.3)
    v=random.uniform(0.3,0.8)
    rs.LayerColor(layer,Rhino.Display.ColorHSV(h,s,v).ToArgbColor())

#Create Layers named per user-submitted new_element

rs.AddLayer(name=new_element, parent=overall_parent)
bbox_layer_name = rs.AddLayer("bbox"+new_element, Color.FromArgb(20, 0, 0, 0), parent=new_element)
crv_layer_name = rs.AddLayer("crv"+new_element, Color.Red, parent=new_element)
sol_layer_name = rs.AddLayer("sol"+new_element, random_color_light(), parent=new_element)

Thx
Alan

Each sublayer of the same parent layer needs to have a different name… So, it’s like
sol_1
sol_2
sol_3
etc?

Thanks for the reply, Mitch. Yes. The script asks for a “New Element” and then uses that in the layer name in camelCase, so if the new element is, “Wall” the layers, and they specified 3 “sol” layers, it would look like:

solWall_1
solWall_2
solWall_3

And then each would have their own color.

Here’s what I have at the moment:

NewElement_Simple_v07.py (3.3 KB)

'''
Creates a simple layer tree for a new element, 
including a user-defined number of "solids" layers
# v07 by Alan Farkas 230805
'''

from rhinoscript.layer import CurrentLayer
import rhinoscriptsyntax as rs
import random
import rhinocontext as rc
from System.Drawing import Color

#Asks for new layer tree name

new_element = rs.GetString(message="New Element?")
new_element = new_element[0].upper()+new_element[1:] #camelCase

"""
Create number of "sol" layers via user input...
Getting problem: "iteration over non-sequence of type int"
Tried also as a List, but couldn't figure it out.

def CreateSolLayers():

    input = rs.GetInteger(message="How many Solid Layers?")
    print(input)

    if input is None: return

    for i in input:
        rs.AddLayer("sol_"+input)
"""

overall_parent = CurrentLayer() # Defines CurrentLayer to be used as "parent" for new element tree

#Create Random Light Color

def random_color_light():
    h=random.random()
    s=random.uniform(0.2,0.3)
    v=random.uniform(0.3,0.8)
    hsv = rc.Display.ColorHSV(h,s,v)
    rgb = hsv.ToArgbColor()

#Create default and "sol" layer(s) with integrated New Element name

rs.AddLayer(name=new_element, parent=overall_parent) #////creates new element tree as child of overall_parent, defined above///
bbox_layer_name = rs.AddLayer("bbox"+new_element, Color.FromArgb(20, 0, 0, 0), parent=new_element)
crv_layer_name = rs.AddLayer("crv"+new_element, Color.Red, parent=new_element)
sol_layer_name = rs.AddLayer("sol"+new_element, random_color_light(), parent=new_element)

#Sets all print colors to black (otherwise they'll mimic layer color)

layers = rs.LayerNames(new_element)
if layers:
    for layer in layers:
        black = rs.CreateColor((0,0,0))
        if rs.LayerPrintColor(layer)!=black:
            rs.LayerPrintColor(layer, black)

#Set LayerPrintWidths for nonPlot layers (Works as of v03A)

rs.LayerPrintWidth(bbox_layer_name, -1)
rs.LayerPrintWidth(crv_layer_name, -1)

#Assign Specific Material to Specific Layer 230728
#Furnished by @Clement on Rhino Discourse 230728

import Rhino
import scriptcontext

def AssignRenderMaterialToLayer(layer_path, render_material_name):
    
    # find the layer by it's full path
    index = scriptcontext.doc.Layers.FindByFullPath(layer_path, -1)
    if index < 0: 
        print ("Layer '{}' not found".format(layer_path))
        return False
    
    # find any rendermaterials by render_material_name
    data = scriptcontext.doc.RenderMaterials.GetEnumerator()
    mats = filter(lambda rm: rm.Name == render_material_name, data)
    if not mats:
        print ("Material '{}' not found".format(render_material_name))
        return False
    
    # assign first found rendermaterial to layer
    layer = scriptcontext.doc.Layers[index]
    layer.RenderMaterial = mats[0]
    return True

#Use this line to Call Out defined function AssignRenderMaterialToLayer once it's been added to script.

rc = AssignRenderMaterialToLayer(bbox_layer_name, "MI_bBox")
rc = AssignRenderMaterialToLayer(sol_layer_name, "MI_BaseGrey80")

This looks like what I’m trying to do for the user input number of sol layers:

Will have to try it when it’s not some ungodly hour, and add the random light color snippet.

Think I have this in a good place so far. It creates the user-defined number of layers, which are then named correctly, and assigned random light colors…

test_sol_layers_num.py (717 Bytes)

…But if anyone has a way to make sure the layers’ hues (“h”) are more separated from each other, I’d be much obliged for some guidance. (See image: Sol_01 to sol_04 is great. But then the hues are super close to each other in 04-05, and 06-08.)

image

import rhinoscriptsyntax as rs
import Rhino, random

def AddNumberedLayersStartFin():

    num_lay = rs.GetInteger("How many solid layers?", minimum=0)

    if num_lay is None: return
    
    for i in range(1, num_lay+1):
        layername = "sol_"+"{}".format(i).zfill(2)
        h=random.random()
        s=random.uniform(0.2,0.3)
        v=random.uniform(0.8,1.0)
        if not rs.IsLayer(layername): rs.AddLayer(layername, (Rhino.Display.ColorHSV(h,s,v)).ToArgbColor())

AddNumberedLayersStartFin()

maybe this?

import rhinoscriptsyntax as rs
import Rhino, random

def AddNumberedLayersStartFin():

    num_lay = rs.GetInteger("How many solid layers?", minimum=0)

    if num_lay is None: return
    

    for i in range(num_lay):
        layername = "sol_"+"{}".format(i+1).zfill(2)
        h=(1/num_lay)*i
        s=random.uniform(0.2,0.3)
        v=random.uniform(0.8,1.0)
        if not rs.IsLayer(layername): rs.AddLayer(layername, (Rhino.Display.ColorHSV(h,s,v)).ToArgbColor())

AddNumberedLayersStartFin()
1 Like

Thanks, @Gijs - I’m actaually embarrassed I didn’t think of trying something like that :sweat_smile: