circle CNR component C# Grasshopper

Read and edit persistent data in Grasshopper components with C#

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.

circle CNR Grasshopper component

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);

  }

circle CNR component C# Grasshopper

6 thoughts on “Read and edit persistent data in Grasshopper components with C#”

  1. 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

  2. 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!

    1. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.