Search code examples
pythonarraystreegrasshopperrhino3d

convert list of arrays in python, to tree in grasshopper


I'm a beginner in Python and have a question about converting data structure, for using it in Grasshopper.

As an output from my python code, I have a grid of cubes (GUID's), layered up in what I call 'generations'. Besides that, it outputs a grid of data, which contains the information about what color each cube should get.

For example: for j=5 in i=3, in generation=5, I have a cube. In the other list, for j=5 in i=3 , in generation=5, I have 'green' as a string. In grasshopper, I want to link this 'green' value to a swatch, and then color the right cube with it.

The problem is that Python outputs a three-dimensional array, while Grasshopper works in trees. So, I have to convert my outputs to a tree structure in which the first level is 'generations', the second level is 'i' and the third is 'j'.

A friend sent me this piece of code, so I guess that is how to begin:

import clr clr.AddReference("Grasshopper") from Grasshopper.Kernel.Data import GH_Path from Grasshopper import DataTree

I hope you guys can help! Tessa

This is my mainfunction:

def Main():
    intLength = input1
    intWidth  = input2
    intGen    = input3
arrValues = randomizeArray01(intLength,intWidth)        
arrDensity = densityfunction(arrValues)
arrMeshes = render(arrValues,-1)                        
for k in range(intGen):
    arrValues = applyGOL(arrValues,arrDensity)          
    arrDensity = densityfunction(arrValues)
    genC = colorObject(arrValues)
    colorList.append(genC)
    genR = render(arrValues,k)   
    renderList.append(genR)

In which this is the renderfunction:

def render(arrValues, z):
    rs.EnableRedraw(False)
    arrMeshes = []
    for i in range(len(arrValues)):
        arrRow = []
        for j in range(len(arrValues[i])):
            box = addMeshBox([(i-0.5),(len(arrValues[i])-j-0.5),z-0.5], [(i+0.5),(len(arrValues[i])-j+0.5),z+0.5])
            arrRow.append(box)
        arrMeshes.append(arrRow)
    rs.EnableRedraw(True)                               
    return arrMeshes

And this is the colorfunction:

def colorObject(arrValues):
    arrColor = []
    for i in range(len(arrValues)):
        rowColor= []
        for j in range(len(arrValues[i])):
            if arrValues[i][j] == 0:
                color = green
                rowColor.append(color)
            elif arrValues[i][j] ==1:
                color = residential
                rowColor.append(color)
            elif arrValues[i][j] ==100:
                color = retail
                rowColor.append(color)
            elif arrValues[i][j] ==1000:
                color = road
                rowColor.append(color)
        arrColor.append(rowColor)
    return arrColor

And in the end, this is what I output to Grasshopper:

a = renderList
b = colorList

In grasshopper, this gives me a list of 'Iron.Python.Runtime.List'.


Solution

  • I don't have a working version of grasshopper to hand, but my code for doing this is:

    import rhinoscriptsyntax as rs
    
    import Rhino.Geometry as rg
    from clr import AddReference as addr
    addr("Grasshopper")
    
    from System import Object
    from Grasshopper import DataTree
    from Grasshopper.Kernel.Data import GH_Path
    
    
    def raggedListToDataTree(raggedList):
        rl = raggedList
        result = DataTree[object]()
        for i in range(len(rl)):
            temp = []
            for j in range(len(rl[i])):
                temp.append(rl[i][j])
            #print i, " - ",temp
            path = GH_Path(i)
            result.AddRange(temp, path)
        return result
    

    There is a gist of this here that also has a function that turns trees into lists.

    There's still quite a lot wrong with this, no recursion, no error checking, no branch magic, but it does the job in most cases. I'd love to see it improved!

    In your case you can just pipe the output that would otherwise give you a runtime list into the raggedListToDataTree function.