Create a grasshopper group from the last N components

Hi,

Is it possible to group last N components in grasshopper using C# ?
By group I mean ctrl+g.

without testing, this seems to be interesting:

maybe paired with this one:

oh, and I’d like to use the opportunity to say thank you to you Petras, your website is an amazing add with great examples of c# code. Your site saved me sooooo much time!!
Thank you!

Thank you;)

I have a small issue with this code you referenced:

        List<Guid> guids = new List<Guid>();
        foreach (Grasshopper.Kernel.IGH_Param param in base.Params.Input)
        {
            foreach (IGH_Param source in param.Sources)
            {
                guids.Add(source.Attributes.Parent.InstanceGuid);
            }
        }

I create a grasshopper component, but within this component I create some more components as input. The moment I use this option for my case Parent.InstanceGuid return null.

I create additional input components like this:

 public override void AddedToDocument(GH_Document document)
        {

            base.AddedToDocument(document);

            //Add Curve

            Curve[] lines = new Curve[] {
                (new Line(new Point3d(200,-200,300),new Point3d(200,-200,400))).ToNurbsCurve()
                 };

            int[] recID = new int[] { 0 };

            for (int i = 0; i < recID.Length; i++)
            {
                Grasshopper.Kernel.Parameters.Param_Curve ri = Params.Input[recID[i]] as Grasshopper.Kernel.Parameters.Param_Curve;
                if (ri == null || ri.SourceCount > 0 || ri.PersistentDataCount > 0) return;
                Attributes.PerformLayout();
                int x = (int)ri.Attributes.Pivot.X - 225;
                int y = (int)ri.Attributes.Pivot.Y;
                IGH_Param lineParam = new Grasshopper.Kernel.Parameters.Param_Curve();
                lineParam.AddVolatileData(new Grasshopper.Kernel.Data.GH_Path(0), 0, lines[i]);
                lineParam.CreateAttributes();
                lineParam.Attributes.Pivot = new System.Drawing.PointF(x, y);
                lineParam.Attributes.ExpireLayout();
                document.AddObject(lineParam, false);
                ri.AddSource(lineParam);

            }


            //Add sliders
            double[] sliderValue = new double[] { 42, 20000, 650, 40, 1, };
            double[] sliderMinValue = new double[] { 1, 1000, 0, 300, 1, };
            double[] sliderMaxValue = new double[] { 110, 30000, 650, 0, 20 };
            int[] sliderID = new int[] { 1, 2, 3, 4, 5 };

            for (int i = 0; i < sliderValue.Length; i++)
            {
                Grasshopper.Kernel.Parameters.Param_Number ni = Params.Input[sliderID[i]] as Grasshopper.Kernel.Parameters.Param_Number;
                if (ni == null || ni.SourceCount > 0 || ni.PersistentDataCount > 0) return;
                Attributes.PerformLayout();
                int x = (int)ni.Attributes.Pivot.X - 250;
                int y = (int)ni.Attributes.Pivot.Y - 10;
                Grasshopper.Kernel.Special.GH_NumberSlider slider = new Grasshopper.Kernel.Special.GH_NumberSlider();
                slider.SetInitCode(string.Format("{0}<{1}<{2}", sliderMinValue[i], sliderValue[i], sliderMaxValue[i]));
                slider.CreateAttributes();
                slider.Attributes.Pivot = new System.Drawing.PointF(x, y);
                slider.Attributes.ExpireLayout();
                document.AddObject(slider, false);
                ni.AddSource(slider);
            }

            //Add Booleans
            bool[] boolValue = new bool[] { true };
            int[] boolID = new int[] { 6 };

            for (int i = 0; i < boolID.Length; i++)
            {
                Grasshopper.Kernel.Parameters.Param_Boolean bi = Params.Input[boolID[i]] as Grasshopper.Kernel.Parameters.Param_Boolean;
                if (bi == null || bi.SourceCount > 0 || bi.PersistentDataCount > 0) return;
                Attributes.PerformLayout();
                int x = (int)bi.Attributes.Pivot.X - 250;
                int y = (int)bi.Attributes.Pivot.Y - 10;
                Grasshopper.Kernel.Special.GH_BooleanToggle booleanToggle = new Grasshopper.Kernel.Special.GH_BooleanToggle();
                booleanToggle.CreateAttributes();
                booleanToggle.Attributes.Pivot = new PointF(x, y);
                booleanToggle.Attributes.ExpireLayout();
                booleanToggle.Value = boolValue[i];
                document.AddObject(booleanToggle, false);
                bi.AddSource(booleanToggle);
            }




        }

I assume that c# component runs the code to retrieve guids before all these components are created.
So the question is when do I need to call this function, so that the returned guids are not null?

Oh yes, I have seen that the code returns null for e.g. sliders. I reduced the problem to a simple slider.

I made it work (very simple, I wasn’t able to quickly rebuild your building solution) by using this code from this post from rolf:

// Checking the first Input param (at index = 0)
    var param = Component.Params.Input[0];
    if (param.Sources.Count < 1)
    {        
      return; // No source was connected to inport
    }

    A = param.Sources[0].InstanceGuid; // Output the Guid

which will give you the correct GUID id

I guess you need to loop through them as you set the inputs yourself.

update:

here a working code that groupes all the inputs like sliders etc (not nodes though) as soon as they are connected. this is in the solveInstance:

private void RunScript(Brep B, string M, ref object A, ref object C)
  {
    if(B == null) return;
    //get volume in metric volume
    double volcm = B.GetVolume() / 1000;
    //Component.Params.Input[1].Optional = true;

    //populate val list
    if(M == "1")
    {
      var input = Component.Params.Input[1].Sources[0]; //get the first thing connected to the first input of this component
      var valList = input as Grasshopper.Kernel.Special.GH_ValueList;
      valList.ListItems.Clear();
      List <Grasshopper.Kernel.Special.GH_ValueListItem> materials = new List<Grasshopper.Kernel.Special.GH_ValueListItem>()
        {
          new Grasshopper.Kernel.Special.GH_ValueListItem("silver ag 999", "10.49"),
          new Grasshopper.Kernel.Special.GH_ValueListItem("silver ag 925", "10.40"),
          new Grasshopper.Kernel.Special.GH_ValueListItem("white gold Au750Pd130", "15.80"),
          new Grasshopper.Kernel.Special.GH_ValueListItem("white gold Au750Pd150", "	15.90"),
          new Grasshopper.Kernel.Special.GH_ValueListItem("white gold Au750Pd210", "	16.30"),
          new Grasshopper.Kernel.Special.GH_ValueListItem("pale gold 2N Au750Ag160", "	15.60"),
          new Grasshopper.Kernel.Special.GH_ValueListItem("yellow gold 3N Au750Ag125", "	15.40"),
          new Grasshopper.Kernel.Special.GH_ValueListItem("rosé gold 4N Au750Ag90", "15.30"),
          new Grasshopper.Kernel.Special.GH_ValueListItem("red gold 5N Au750Ag45", "15.10"),
          new Grasshopper.Kernel.Special.GH_ValueListItem("most red gold 6N Au750Ag5Pt4", "15.10"),
          new Grasshopper.Kernel.Special.GH_ValueListItem("platine 950", "20.40"),
          new Grasshopper.Kernel.Special.GH_ValueListItem("palladium 950", "11.80")
          };
      valList.ListItems.AddRange(materials);
      Component.Params.Output[1].VolatileData.Clear();
      valList.ExpireSolution(true);
    }
    if(M == null) A = "please connect a item list node to M and select a material";
    else
    {
      A = string.Format("{0}g", Math.Round(volcm * Convert.ToDouble(M), 2));
    }

    List<Guid> guids = new List<Guid>();

    foreach(IGH_Param param in Component.Params.Input)
    {
      foreach(IGH_Param source in param.Sources)
      {
        guids.Add(source.InstanceGuid);
      }
    }


    Grasshopper.Kernel.Special.GH_Group g = new Grasshopper.Kernel.Special.GH_Group();
    g.NickName = "hhh";
    g.Colour = System.Drawing.Color.FromArgb(150, 150, 0, 0);
    GrasshopperDocument.AddObject(g, false, GrasshopperDocument.ObjectCount);
    for(int i = 0;i < guids.Count;i++) g.AddObject(guids[i]);
    g.ExpireCaches();

I might be wrong, but I think the order of objects when you iterate GrasshopperDocument.Objects is the order of instantiation (a quick GHPython test):

So maybe you could just grab the last N objects in this list and group these. Maybe :man_shrugging:

Here’s quick go at implementing what I suggested above, seems to work okay:


211105_AddLastNGroup_00.gh (3.1 KB)

2 Likes

what a beauty!

1 Like

@benedict and @AndersDeleuran

Thank you, you are awesome, it works and solves my issue. :partying_face:

2 Likes

Hi @Petras_Vestartas, @benedict, @AndersDeleuran, maybe not related to the topic but How could a C# change only the colour of the group that belongs to, without using a group name?. I’d like to implement these lines inside my code, I’d really appreciate any help, thank you in advance!
T.

g.NickName = "hhh";
    g.Colour = System.Drawing.Color.FromArgb(150, 150, 0, 0);

@Petras_Vestartas how did you make align components on the left with the inputs on the right? Did you code it?

int x = (int)ni.Attributes.Pivot.X - 250;
int y = (int)ni.Attributes.Pivot.Y - 10;

I am having a hard time to make them align. Any advice?

Exactly, and the pivot point is the alignment point

        double[] sliderValue = new double[] { 42, 20000, 650, 40, 1, };
        double[] sliderMinValue = new double[] { 1, 1000, 0, 300, 1, };
        double[] sliderMaxValue = new double[] { 110, 30000, 650, 0, 20 };
        int[] sliderID = new int[] { 1, 2, 3, 4, 5 };

        for (int i = 0; i < sliderValue.Length; i++)
        {
            Grasshopper.Kernel.Parameters.Param_Number ni = Params.Input[sliderID[i]] as Grasshopper.Kernel.Parameters.Param_Number;
            if (ni == null || ni.SourceCount > 0 || ni.PersistentDataCount > 0) return;
            Attributes.PerformLayout();
            int x = (int)ni.Attributes.Pivot.X - 250;
            int y = (int)ni.Attributes.Pivot.Y - 10;
            Grasshopper.Kernel.Special.GH_NumberSlider slider = new Grasshopper.Kernel.Special.GH_NumberSlider();
            slider.SetInitCode(string.Format("{0}<{1}<{2}", sliderMinValue[i], sliderValue[i], sliderMaxValue[i]));
            slider.CreateAttributes();
            slider.Attributes.Pivot = new System.Drawing.PointF(x, y);
            slider.Attributes.ExpireLayout();
            document.AddObject(slider, false);
            ni.AddSource(slider);
        }
2 Likes

It works perfect. Thanks for the explanation!