-
-
Save piac/ef91ac83cb5ee92a1294 to your computer and use it in GitHub Desktop.
def list_to_tree(input, none_and_holes=True, source=[0]): | |
"""Transforms nestings of lists or tuples to a Grasshopper DataTree""" | |
from Grasshopper import DataTree as Tree | |
from Grasshopper.Kernel.Data import GH_Path as Path | |
from System import Array | |
def proc(input,tree,track): | |
path = Path(Array[int](track)) | |
if len(input) == 0 and none_and_holes: tree.EnsurePath(path); return | |
for i,item in enumerate(input): | |
if hasattr(item, '__iter__'): #if list or tuple | |
track.append(i); proc(item,tree,track); track.pop() | |
else: | |
if none_and_holes: tree.Insert(item,path,i) | |
elif item is not None: tree.Add(item,path) | |
if input is not None: t=Tree[object]();proc(input,t,source[:]);return t |
# written by Giulio Piacentino, [email protected] | |
def tree_to_list(input, retrieve_base = lambda x: x[0]): | |
"""Returns a list representation of a Grasshopper DataTree""" | |
def extend_at(path, index, simple_input, rest_list): | |
target = path[index] | |
if len(rest_list) <= target: rest_list.extend([None]*(target-len(rest_list)+1)) | |
if index == path.Length - 1: | |
rest_list[target] = list(simple_input) | |
else: | |
if rest_list[target] is None: rest_list[target] = [] | |
extend_at(path, index+1, simple_input, rest_list[target]) | |
all = [] | |
for i in range(input.BranchCount): | |
path = input.Path(i) | |
extend_at(path, 0, input.Branch(path), all) | |
return retrieve_base(all) |
I didn't realize this at first so I want to mention in case it helps others: it seems that in order for tree_to_list
to work properly (the version included with Rhino 6) the incoming tree must have the same dimensions as your target list. For instance, I had a list with 9 branches {0}...{8}
and 40 items in each branch. I had to use path mapper to remap the incoming paths as {0;0}...{0;8}
to output a 9x40 list of lists.
@laurend I think this topic:
https://discourse.mcneel.com/t/treehelpers-with-simplify/92531/2
will explain more in detail for you.
@piac yes, I wish I had found that earlier!
@cromlyngames what type are you passing to the script? Can you email me a sample?
Thank you! [email protected]
What can we do when the "tree" has been simplified and represents a forest?
(for example, it contains {0,1} and also {3,1}, which do not have a "trunk", or first index, in common).
You can use retrieve_base and source like this:
import ghpythonlib.treehelpers as TH
nested = TH.tree_to_list(data, retrieve_base=lambda x: x)
a = TH.list_to_tree(nested, False, source=[])
Background
The key here is to notice that Grasshopper will never create forests, when it does normal tree handling. Forests are "trees" that have distinct trunks, or first branch indices. That's why, the default of the functions does not create an empty list to hold these distinct trunks, -- otherwise, with standard components, there would be one more [0] to deal with all the time.
Please also note that trees that have overlapping branches, that is, a branch with a path that is equal to the beginning of the path to another branch, cannot be rendered as instances of this type of lists of lists. Just keeping paths to the same depth will fix this problem.
This function doesn't work when the tree index doesn't start on

0
.