Problems appending elements to GH_Structure at a higher path level

Hi there,

I am not very familiar with GH_Structures and hope someone more experienced can help me out with the following issue:
I have been trying to add elements to a GH_Structure at a higher path level but somehow it always appends the elements at the lowest level.

My code is similar to the following example:

GH_Structure<GH_Integer> tree = new GH_Structure<GH_Integer>();
for(int i = 0; i < x; i++)
  GH_Path pth = new GH_Path(i);
  for(int j = 0; j < y; j++)
    GH_Path pth2 = new GH_Path(i, j);
    for(int k = 0; k < z; k++)
      tree.Append(new GH_Integer(k), pth2);
return tree;

For e.g. x =2, y=3 and z=4, this returns a structure {4;4;4;4;4;4}, which is neither what I wanted nor expected.

It would be great if someone could let me know what I am missing out on because I really have no clue.

Many thanks in advance for your help,

— edited and added for reasons of clarity—

Essentially the above code does not return the tree structure as expected (see graph on the left) but returns a GH_Structure with a tree structure as is depicted in the graph on the right.

The issue I am still having is that I cannot access items in the tree based on the actual but not exposed path structure in the GH_Structure and that I thus lose the topological information and the relationship between elements (which is important and which is why I used trees in the first place).

Hello @katja.knecht,

Is your code running inside a script component or inside a custom one (developped with Visual Studio)?

If you are using a script, then you can use DataTree instead of GH_Structure and your code will work. Otherwise you shoudn’t get this weird structure output, I think/guess the GH_Structure should be converted back to a tree when the component process the output parameters. I don’t know exactly where though.

  private void RunScript(int x, int y, int z, ref object A)
   DataTree<GH_Integer> tree = new DataTree<GH_Integer>();

   for(int i = 0; i < x; i++){
  for(int j = 0; j < y; j++){
    GH_Path pth2 = new GH_Path(i, j);

    for(int k = 0; k < z; k++){
      tree.Add(new GH_Integer(k), pth2);
A = tree;
1 Like

The \{4;4;4;4;4;4\} you’re seeing is the string representation of the GH_Structure. It basically lists the lengths of each branch in the tree. It’s neither a particularly helpful, nor clear format. If you’re doing this in a C# script component, you should use DataTree<int> instead of GH_Structure<GH_Integer>:

DataTree<int> tree = new DataTree<int>();
for(int i = 0; i < x; i++)
  for(int j = 0; j < y; j++)
    GH_Path path = new GH_Path(i, j);
    for(int k = 0; k < z; k++)
      tree.Add(k, path);
A = tree;
1 Like

Dear Xavier, dear David,

Many thanks for your replies and my apologies for not specifying which environment I was coding in in the first place. It is Visual Studio, which is why I did not use DataTree and have been struggling with GH_Structure.

Thanks to Xavier’s hint that the GH_Structure should be converted back to a tree during the output process, I actually managed to get my component to work. The issue I described is only a problem when I try to access the items via the intended path structure in my code, e.g. in a separate function that I call and pass it on to. It is not possible then to access the items in the GH_Structure via the paths I originally set because the exposed path structure of the tree somehow collapses when it is meant to have more than 2 levels. However, when I output the GH_Structure, it outputs perfectly fine and the resulting tree has the intended mapping. Weird.

Unless there is another workaround, I guess I will just have to avoid using GH_Structures with a higher number of levels internally.

Many thanks, again, for your help!

Ok, DataTree was only added to make life easier for scripters. It basically removes the constraint on IGH_Goo, allowing you to use regular data types. However if you’re in VS then you should always use GH_Structure.

Just be sure to assign your tree to the appropriate output using DA.SetDataTree();, rather than DA.SetData(); You must also set the access level of that output parameter to tree in the RegisterOutputParams method.

1 Like

Allow me to put forth, in the scope of this topic, a doubt I encountered working with GH_Structure .

I can easily Append() or Insert() items into the GH_Structure using IGH_Goo, but in one specific occasion I’m trying to append an entire list to a new branch, using AppendRange().

I have set this up with IEnumerable of type IGH_Goo and the compiler doesn’t throw any errors, but running the component in GH it is broken: “collection can’t be null”.

It is guaranteed it is connected to the IEnumerable part of the code.

Can anyone shed some light on the matter?


Can you show the code that fails?

///Declare IEnumerables for 3 lists/branches
IEnumerable<gt.IGH_Goo> Xset;
IEnumerable<gt.IGH_Goo> Yset;
IEnumerable<gt.IGH_Goo> Zset;

///Create GH_Structure Paths
dt.GH_Path pX = new dt.GH_Path(0,0);
dt.GH_Path pY = new dt.GH_Path(1,0);
dt.GH_Path pZ = new dt.GH_Path(2,0);

///Lists setX, setY, setZ are now created

///“Convert” lists to DataTree interface
Xset = setX as IEnumerable<gt.IGH_Goo>;
Yset = setY as IEnumerable<gt.IGH_Goo>;
Zset = setZ as IEnumerable<gt.IGH_Goo>;

///Add data to DataTree
XYZsets.AppendRange(Xset, pX);
XYZsets.AppendRange(Yset, pY);
XYZsets.AppendRange(Zset, pZ);

And setX, setY, and setZ are what sort of object? Did you null check Xset after the cast?

Hi David,

setX, setY, setZ are List. Probably it is best to give you the complete code. I’m sure it is a simple mistake, but I don’t see it.

AdvancedSortComponent.cs (13.2 KB)

When I load that code I get the following warning for your attempted cast:

double is a framework type, IGH_Goo is an interface in Grasshopper. double does not (cannot, because it was written by Microsoft way before I wrote IGH_Goo) implement this interface so the cast will fail, resulting in Xset being null.

Specifically, the as keyword will not convert data from one type into another. It will only allow you to assign data to a variable of type T if that data is already of type T.

Well, it’s surprising that in VS that invalid cast error did not come up at all.
I thought that you could interface practically any Rhino type with IGH_Goo, but maybe I need to better understand such implementation.
What would be your advice to append a List ofSomeType to GH_Structure branch?