Modify color and arrowheads of AddLineParameter in OutputParams

Dear all,

how can I change the way Grasshopper displays geometry in the RegisterOutputParams?

More specifically, I’d like to assign colors and add arrowheads to the lines in pManager.AddLineParameters

I don’t want to use Rhino.Geometry, because I need to redraw a lot and I have the feeling, “unbaked” geometry in Grasshopper draws much faster.

Thanks a lot for any help.

Best,
Christoph

Hi Christoph,

you’ll have to override the DrawViewportWires and/or DrawViewportMeshes on your GH_Component derived class. This means you’ll have to exactly duplicate the existing functionality for those parameters you don’t want to change and provide alternative functionality for those you do want to change.

Do note that there’s nothing you can do to make a line parameter draw arrowheads, all you can do is change the colour and thickness of all the lines. If you want more advanced preview or have per-line control, then I recommend you simply set the output Line parameter to Hidden=true and keep a separate list of preview data inside your component.

Just to be sure, you’re doing this in C# and Visual Studio? Or are you working in the scripting components?

1 Like

Here’s some C# code for a component which overrides the preview of the output parameter:

using System;
using System.Collections.Generic;
using System.Drawing;
using Grasshopper.Kernel;
using Rhino.Geometry;

namespace TestComponents
{

  public class LineComponent : GH_Component
  {
    public LineComponent()
      : base("Funky Line", "FLine", "Funky line creator", "Test", "Test")
    { }

    public readonly static Guid FunkyLineId = new Guid("{89F93645-4985-44CA-AED6-1C87DCF6D9EE}");
    public override Guid ComponentGuid
{
  get { return FunkyLineId; }
}

    protected override void RegisterInputParams(GH_InputParamManager pManager)
{
  pManager.AddPointParameter("A", "A", "A", GH_ParamAccess.item);
  pManager.AddPointParameter("B", "B", "B", GH_ParamAccess.item);
}
    protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
  pManager.AddLineParameter("Line", "L", "Funky lines", GH_ParamAccess.item);
  pManager.HideParameter(0);
}

    protected override void BeforeSolveInstance()
{
  _lines.Clear();
  _widths.Clear();
  _colors.Clear();
}
    protected override void SolveInstance(IGH_DataAccess DA)
    {
      Point3d a = Point3d.Unset;
      Point3d b = Point3d.Unset;

      if (!DA.GetData(0, ref a)) return;
      if (!DA.GetData(1, ref b)) return;
      if (!a.IsValid || !b.IsValid)
        return;

      Line line = new Line(a, b);
      DA.SetData(0, line);

      _lines.Add(line);
      _widths.Add(Math.Min(10, (int)(line.Length * 0.1) + 1));
      if (b.X > a.X)
        _colors.Add(Color.HotPink);
      else
        _colors.Add(Color.CornflowerBlue);
    }

    private readonly List<Line> _lines = new List<Line>();
    private readonly List<int> _widths = new List<int>();
    private readonly List<Color> _colors = new List<Color>();

    public override void DrawViewportWires(IGH_PreviewArgs args)
    {
      base.DrawViewportWires(args);

      for (int i = 0; i < _lines.Count; i++)
      {
        args.Display.DrawLine(_lines[i], _colors[i], _widths[i]);
        args.Display.DrawArrowHead(_lines[i].To, _lines[i].Direction, _colors[i], 40, 0);
      }
    }
  }
}
2 Likes

wow this is awesome! I was just about to ask about the output parameter.
This clarifies it. Thanks a lot!

I’m encountering another issue, I don’t really understand. I have a loop in my SolveInstance, during which the lines change (it’s a FFD fast fluid dynamics solver). but instead of replacing the grasshopper-lines, they are being added to the output list in every iteration:

This is the code excerpt:

        while (true)
        {
            if (f.checkBox1.Checked == true)
            {
                doc.NewSolution(false);
                Rhino.RhinoDoc.ActiveDoc.Views.Redraw();
                Rhino.RhinoApp.Wait();

                t += dt;
                ffd.time_step();

                List<Line> velolist = new List<Line>();
                for (int i = 0; i < Nx; i++)
                {
                    for (int u = 0; u < Ny; u++)
                    {
                        double[] vel = de.get_velocity((i - 0.5) * omega.hx, (u - 0.5) * omega.hy, (5 - 0.5) * omega.hz);
                        Line arrowlines = new Rhino.Geometry.Line(new Rhino.Geometry.Point3d(i * omega.hx, u * omega.hy, 5 * omega.hz),
                             new Vector3d(vel[0], vel[1], vel[2]));
                        velolist.Add(arrowlines);
                    }
                }
                DA.SetDataList(0, velolist);
            }
            else
            {
                Rhino.RhinoDoc.ActiveDoc.Views.Redraw();
                Rhino.RhinoApp.Wait();
            }
        }

If I set doc.NewSolution(true); then no lines are drawn.

I also get the “Grasshopper Breakpoint - An object expired during a solution”- error, which I just click away. But probably that already gives me a hint, that my general code setup is not as it should be?

actually I think, your code example also answeres my new question.
I would just call DA.SetDataList(lines) once in solveInstance, after that in my infinite loop I just change _lines, _width, _colors etc. and the overridden DrawViewportWires does the rest.

Hi @DavidRutten and all,

your example was great and I can now happily color my lines as I want:

I’m really sorry to ask again but I just can’t figure out how to implement the dynamic redraw.

What I try to achieve is something similar to Processing, where it’s

 public void draw(){ }

is being called forever, until you close the app.

Am I right, that in order to get the same in Grasshopper, I would need to call

SolveInstance(){ }

in an infinite loop?

My current attempt is, that within SolveInstance I have a separate class which would then draw Rhino.Geometry and refresh the viewport during the iterations. Sth like this:

 public class MyComponent : GH_Component{
 int counter=0;
 (...)
 protected override SolveInstance(){
      solver s = new solver();
      while(counter < 100){
           s.runAndDraw();        //new geometry being redrawn in Rhino in every iteration here
      }
 }
 }

However, the problem I have with this solution, is that within this while-loop, the solver won’t react to changes being made in the Grasshopper Canvas.

I would appreciate a lot any ideas on this!
Thanks and best, Christoph