A guide to accessing, reading and editing the persistent data property of Grasshopper components. This guide follows on from this post.
Every input of normal Grasshopper components has the ability to save persistent data. Persistent data is what you see when you right-click on a component and set the input’s value from there. The opposite, data fed into a component from another component, is called volatile data.
In this example, I will take the Circle CNR component. Using techniques borrowed from this post and this post, I am going to create a new CNR component using C#, then modify its persistent data.
Add persistent data
Firstly, we need to add or reference the component for which we want to modify the persistent data.
Here, I am creating a new instance of Circle_CNR, which is contained within curve.gha.
//Create the component var cs = new CurveComponents.Component_CircleCNR(); //add the circle centre (input 0) var pp = cs.Params.Input[0] as Grasshopper.Kernel.GH_PersistentGeometryParam<Grasshopper.Kernel.Types.GH_Point>; pp.PersistentData.ClearData(); pp.PersistentData.Append(new GH_Point(new Point3d(0, 0, 0))); //add the circle radius var pn = cs.Params.Input[2] as Grasshopper.Kernel.GH_PersistentParam<Grasshopper.Kernel.Types.GH_Number>; pn.PersistentData.ClearData(); pn.PersistentData.Append(new GH_Number(y)); //y is another variable
Read persistent data
Persistent data is saved as a GH_Structure. This is a tree-like data structure.
The ‘Append’ method above will add the data item to the final branch in the structure. Since we cleared the structure in the line before, there are no branches, so Grasshopper adds the data to a new branch.
So, in order to read our data, we need to access the list contained in branch 0.
var readpt = cs.Params.Input[0] as Grasshopper.Kernel.GH_PersistentParam<Grasshopper.Kernel.Types.GH_Point>; return readpt.PersistentData[0];
A full example
In the manner of this post, here I have a C# component that creates an instance of the CNR component hidden from the user on a dummy document. By modifying the CNR component’s input persistent data, we can modify the properties of the circle. The circle is calculated, and we read the output from the CNR component.
private void RunScript(double y, ref object A) { //Create the component var cs = new CurveComponents.Component_CircleCNR(); //add the circle centre (input 0) var pp = cs.Params.Input[0] as Grasshopper.Kernel.GH_PersistentGeometryParam<Grasshopper.Kernel.Types.GH_Point>; pp.PersistentData.ClearData(); pp.PersistentData.Append(new GH_Point(new Point3d(0, 0, 3))); //add the circle radius (input 2) var pn = cs.Params.Input[2] as Grasshopper.Kernel.GH_PersistentParam<Grasshopper.Kernel.Types.GH_Number>; pn.PersistentData.ClearData(); pn.PersistentData.Append(new GH_Number(y)); //y is another variable //run calculations cs.ExpireSolution(true); //add to a dummy document so we can read outputs var doc = new Grasshopper.Kernel.GH_Document(); doc.AddObject(cs, false); //read output circle cs.Params.Output[0].CollectData(); A = cs.Params.Output[0].VolatileData.get_Branch(0)[0]; //remove that component doc.RemoveObject(cs.Attributes, false); }
Hi James,
Thank you in advance for sharing this. I got inspired from this page and solve essential problems in my algorithm.
But this way of passing inputs params in this code is a bit inelegant for me. Is there other way out?
Please join the discussion here:
http://www.grasshopper3d.com/forum/topics/passing-inputs-to-clusters-and-loading-them-into-the-document?xg_source=activity
Hi James,
appriciate the good work. Still having some trouble finding out how its working. I got a little problem with the first code line of yours and cant figure out how to implement it:
///////////code
var cs = new CurveComponents.Component_CircleCNR();
/////////////////////code
////////////////////////////out
Error (CS0246): The type or namespace name ‘CurveComponents’ could not be found (are you missing a using directive or an assembly reference?) (line 71)
///////////////////////////////////out
Do i miss to declare the use or sth?
idbe Happy for feedback
red
Hi Red,
Yes, you need to add a reference to access some namespaces yourself. These references are contained within varous GHA files, which you can read about here: http://james-ramsden.com/run-a-grasshopper-component-from-within-your-c-code/ (Scroll down to the update.) Then, once you’ve found the GHA file you need, add it to your C# component by right-clicking it and selecting ‘Manage Assemblies’. Hope this helps!
Hi James,
This is awesome! Have figured it out generally, but ran into trouble trying to call the “Cull Duplicates” components. It includes drop-down menu items (“Average”, “Leave One” and “Cull All”) that I need to change within my code (default is Average-I want CullAll.) Any idea how to handle this?
Thanks!
Interesting challenge… It seems that all of the methods and properties related to this option are private, meaning they can’t be accessed programatically. In order to use the technique in this post, the only way I can think of would be to somehow call the context menu programatically, and then ‘click’ on the desired option. This would be messy, and likely not worth the effort.
In this situation, I would have recommended looking up some kind of ‘cull duplicate’ class somewhere in the API. But in this case, even this isn’t possible, since the ‘cull duplicate’ logic is baked directly into the component’s SolveInstance.
So all I can recommend in this case is that you create your own ‘cull duplicate’ class from scratch. Though if you google around I’m sure there’s something out there you can copy-paste.