Hiding component outputs for Rhino.Compute

Hello Together!

I’m currently developing some custom components that send data from grasshopper to a web app. They’re working fine, but to make it work with rhino.compute i had to add the outputs to the pManager. Now to my question, I would like to hide the outputs of the component properly… I hacked something together with medium success using custom attributes. This is the current state I’m at ': )

Is there a way to do this more elegant, or would one use a parameter component to do so? It should work a bit like the context bake/print component.

Thank you, already in advanced.

This is my attempt to hide the output

protected override void Render(GH_Canvas canvas, Graphics graphics, GH_CanvasChannel channel)
        {

            switch (channel)
            {
                case GH_CanvasChannel.Wires:
                    foreach (IGH_Param item in base.Owner.Params.Input)
                    {
                        item.Attributes.RenderToCanvas(canvas, GH_CanvasChannel.Wires);
                    }

                    break;
                case GH_CanvasChannel.Objects:


                    GH_Palette gH_Palette = GH_CapsuleRenderEngine.GetImpliedPalette(base.Owner);
                    if (gH_Palette == GH_Palette.Normal && !base.Owner.IsPreviewCapable)
                    {
                        gH_Palette = GH_Palette.Hidden;
                    }
                    bool left = base.Owner.Params.Input.Count == 0;
                    bool right = true;

                    GH_Capsule gH_Capsule = GH_Capsule.CreateCapsule(Bounds, gH_Palette);
                    gH_Capsule.SetJaggedEdges(left, right);
                    GH_PaletteStyle impliedStyle = GH_CapsuleRenderEngine.GetImpliedStyle(gH_Palette, Selected, base.Owner.Locked, base.Owner.Hidden);

                    bool drawComponentBaseBox = true;
                    bool drawParameterGrips = true;
                    RectangleF MessageRectangle = RectangleF.Empty;
                    bool drawComponentNameBox = true;
                    bool drawParameterNames = true;
                    bool drawZuiElements = true;

                    if (drawParameterGrips)
                    {
                        foreach (IGH_Param item in base.Owner.Params.Input)
                        {
                            gH_Capsule.AddInputGrip(item.Attributes.InputGrip.Y);
                        }
                    }

                    graphics.SmoothingMode = SmoothingMode.HighQuality;
                    if (GH_Attributes<IGH_Component>.IsIconMode(base.Owner.IconDisplayMode))
                    {
                        if (drawComponentBaseBox)
                        {
                            if (!string.IsNullOrWhiteSpace(base.Owner.Message))
                            {
                                MessageRectangle = gH_Capsule.RenderEngine.RenderMessage(graphics, base.Owner.Message, impliedStyle);
                            }

                            gH_Capsule.Render(graphics, impliedStyle);
                        }

                        if (drawComponentNameBox)
                        {
                            if (base.Owner.Icon_24x24 == null)
                            {
                                //gH_Capsule.RenderEngine.RenderIcon(graphics, Res_ObjectIcons.Icon_White_24x24, m_innerBounds);
                            }
                            else if (base.Owner.Locked)
                            {
                                gH_Capsule.RenderEngine.RenderIcon(graphics, base.Owner.Icon_24x24_Locked, m_innerBounds);
                            }
                            else
                            {
                                gH_Capsule.RenderEngine.RenderIcon(graphics, base.Owner.Icon_24x24, m_innerBounds);
                            }
                        }
                    }
                    else
                    {
                        if (drawComponentBaseBox)
                        {
                            if (base.Owner.Message != null)
                            {
                                gH_Capsule.RenderEngine.RenderMessage(graphics, base.Owner.Message, impliedStyle);
                            }

                            gH_Capsule.Render(graphics, impliedStyle);
                        }

                        if (drawComponentNameBox)
                        {
                            GH_Capsule gH_Capsule2 = GH_Capsule.CreateTextCapsule(m_innerBounds, m_innerBounds, GH_Palette.Black, base.Owner.NickName, GH_FontServer.LargeAdjusted, GH_Orientation.vertical_center, 3, 6);
                            gH_Capsule2.Render(graphics, Selected, base.Owner.Locked, hidden: false);
                            gH_Capsule2.Dispose();
                        }
                    }

                    if (drawComponentBaseBox)
                    {
                        IGH_TaskCapableComponent iGH_TaskCapableComponent = base.Owner as IGH_TaskCapableComponent;
                        if (iGH_TaskCapableComponent != null)
                        {
                            if (iGH_TaskCapableComponent.UseTasks)
                            {
                                gH_Capsule.RenderEngine.RenderBoundaryDots(graphics, 2, impliedStyle);
                            }
                            else
                            {
                                gH_Capsule.RenderEngine.RenderBoundaryDots(graphics, 1, impliedStyle);
                            }
                        }
                    }

                    if (drawComponentNameBox && base.Owner.Obsolete && CentralSettings.CanvasObsoleteTags && canvas.DrawingMode == GH_CanvasMode.Control)
                    {
                        GH_GraphicsUtil.RenderObjectOverlay(graphics, base.Owner, m_innerBounds);
                    }

                    if (drawParameterNames)
                    {
                        RenderComponentParameters(canvas, graphics, base.Owner, impliedStyle);
                    }

                    if (drawZuiElements)
                    {
                        RenderVariableParameterUI(canvas, graphics);
                    }

                    gH_Capsule.Dispose();
                    break;
            }
        }

Sorry for the confusion. I guess I’m wondering why the output parameter needs to be hidden?

I introduced some changes to rhino.compute that automatically detect this specific component class and sends the output data from this component with some metadata to the web app. So I want to make visually also sure that the output data is not needed inside grasshopper itself. But it’s probably a lack of my knowledge building components specifically for rhino.compute.

What I’m manly aiming for, is to build a context bake like component with my own logic.

Are you using the source code for the 7.x or 8.x branch of the rhino.compute repo? The reason I ask is that I think it would be easier to simply remove a section of the code that prevents you from not registering an output parameter… rather than trying to hack the component itself to have a parameter that isn’t actually shown.
If you’re using the 7.x branch, then you need to go to the GrasshopperDefinition.cs class and comment out lines 915 and 916. If you’re on the 8.x branch, then you need to go to GrasshopperDefinition.cs and comment out lines 1006 and 1007. Basically, the lines you’re trying to remove look like this:

if (outputSchema.Values.Count < 1)
    throw new System.Exceptions.PayAttentionException("Looks like you've missed something..."); // TODO

Once you comment out those lines and rebuild, you should be able to create a definition that doesn’t include an output parameter and it should still work. Can you try that and see if that helps?

1 Like

I’m using the 8.x branch, but sounds definitely like a better idea than my approach, thank you! I’ll give it a try tomorrow.

Hey Andy, I tried this approach, but I could figure out how I expose my data now to compute in a concise way, without starting to mess too much with the rhino.compute code itself or misusing some component properties…

This is how I got my the data from my custom components’ so far

  if (className.StartsWith("_"))
  {
      var webDataComponent = obj as GH_Component;
      IGH_Param param = webDataComponent.Params.Output[0];
      param.NickName = "Data_" + param.InstanceGuid;
      AddOutput(param, param.NickName, ref rc);
  }

Since now, I would not register any outputs I’m searching for something like

IGH_Param param = webDataComponent.Params.CustomDataParam[0]

Thank you, already in advance
Best Felix