Associate list item with tree branch? (1:1)

I created a component that takes as inputs:

  • a point, and

  • a list of four colors.

In code:

pManager.AddPointParameter("Point", "P", "Center point", GH_ParamAccess.item);
pManager[0].Optional = true;
pManager.AddColourParameter("Colors", "C", "Colors of vertices", GH_ParamAccess.list);
pManager[1].Optional = true;

Now, if I pass a list of points and a list of lists of colors (tree), then all possible combinations are created:

This is not what I want. I want each point associated with the corresponding color list. I can do so by grafting the list of points. Then each input is a tree:

This is what I want!

Is it possible to make this grafting step part of my component, so that the user of it doesn’t have to do it?

I would assume, this grafting happens outside the component and somewhere within the logic of grasshopper, as your inputs are set to item/list. My guess is, grasshopper realizes that the structure of your inputs (tree/tree) doesn’t match the structure and tries to match them.

I think one robust solution, which doesn’t require much from the user, is to set your inputs to tree/tree, and manage the different scenarios yourself. In your case the component requires a very specific tree structure, so you can see yourself if that structure exists, and throw an error, in case of an invalid tree structure.

I guess you can also do something like that: this.Params.Input[0].VolatileData.Graft(…), maybe if you do that outside SolveInstance (maybe withing BeforeSolveInstance() or something like that), you won’t break the grasshopper workflow. Seems very error prone to me though, better do some testing :wink:

Edit: Thinking about it, it also seems to me, that in the first case you show, you actually wouldn’t want to graft the input… So just always graftig the input doesn’t make sense. So if you only want to that in certain specific cases, might as well handle all that yourself within the component.

1 Like

Thank you for the suggestions. Maybe in the end I just leave it as it is.

Tried that with the parameter GH_GraftMode.GraftAll but the result is not what I want. It runs the component an additional time on the first element in the list, pretty much the opposite of what I want.

Isn’t there a way to use code to enable the graft option that can be manually selected by right clicking on the input?

It is my understanding that the graft component does essentially what you described. It copies the volatile data from the input to the output, then calls the Graft method on the volatile data of the output, with a graftmode dependent on the selected options (GraftMode.None per default). I would be surprised if the option in the parameter menu of a component does something fundamentally different.

I don’t really understand what your problem is, but my guess is that it has more to do with the grasshopper logic of expiring components and data, raising events which trigger recomputes, etc.

I must be doing something wrong then. It doesn’t work for me:

Relevant code snippet from SolveInstance(IGH_DataAccess DA):

var point = new GH_Point();
DA.GetData(0, ref point);
var p = point.Value;
mesh.Translate(new Vector3d(p));

How the parameter is registered:

pManager.AddPointParameter("Point", "P", "Point in location of node", GH_ParamAccess.item);
pManager[0].Optional = true;

The desired outcome is illustrated in detail in my original post. If someone wants to give it a try, here is the full code: (5.5 MB) (14.7 KB)

I still don’t understand, why instead of handling the tree structure yourself you somehow want to mess with the grasshopper workflow (besides the fact that as a user I would find it highly counterintuitive if a component automatically grafts my inputs).

And as I pointed out before, putting the grafting inside the solve instance doesn’t make sense. The matching of your provided data structure (tree/tree) to the data structure your component requires (item/list) happens before SolveInstance is called.