Speed up Display of many line segments with unique colors

I have a display conduit that shows a bunch of line segments that each have unique colors. These line segments are often transformed between render frames, but they are all transformed by the same transform value. These segments are always touching sequentially in a way that could be represented by a polyline.

I am trying to think through ways to speed up this conduit. My first thought was to draw a polyline through all the points when the conduit is initialized, then for each frame just transform the single polyline instead of all the individual points and use DrawPolyline to make one draw call. This doesn’t seem to work because I can only provide a single color value for the polyline instead of a list of colors for each segment. I have some questions here:

  1. is it faster to DrawPolyline than DrawLine over and over?
  2. is there any way to draw a polyline with more than one color?
  3. would it be faster to transform the polyline instead of individual points then draw the segments from the polyline so I could color each segment?

My next thought is that I am currently using PostDrawObjects for all of my calculations. It seems like I could move the transform logic to PreDrawObjects and maybe the drawing to DrawForeground, but then I would need to store the transformed geometry which seems inefficient. Should I split my logic into PreDraw and DrawForeground?

This is kind of how my conduit is working right now:

protected override void PostDrawObjects(DrawEventArgs e) {
    base.PostDrawObjects(e);
    var xform = GetTransform();
    DrawPath(e, xform);
}

private void DrawPath(DrawEventArgs e, Transform xform){
    for (var i = 0; i < _pathPoints.Count - 1; ++i){
        var a = _pathPoints[i];
        var b = _pathPoints[i + 1];
        a.Transform(xform);
        b.Transform(xform);
        var line = new Line(a, b);
        e.Display.DrawLine(line, _colors[i]);
     }
}

It looks like I am transforming all of my points twice (except first and last), so maybe transforming in PreDraw would help quite a bit.

My list of points is VERY long like a couple hundred thousand.

Use PushModelTransform and PopModelTransform on the pipeline instead of transform each individual line. You should also then be able to call DrawLines once instead of a bunch of DrawLine calls.

1 Like

Thanks @stevebaer, I will look into this. I haven’t played with Push or Pop in the conduit.

So you are saying I should keep everything in PostDraw as it already works, but I should not do the transforms on every line in my Draw method. I should use DrawLines instead of DrawLine on my list of lines and colors.

Is there an example with Pop or PushModelTransform?

Using PushModelTransform and PopModelTransform on the pipeline eliminates the need to transform every individual point. I don’t have a sample, but in general you would do the following

Transform xf = e.Display.ModelTransform;
xf = xf * GetTransform();
e.Display.PushModelTransform(xf);
e.Display.DrawLines(mylines, mycolors);
e.Display.PopModelTransform();
1 Like

Sweeeeeeeet! Thank you very much. That sounds awesome.

One more question if you don’t mind…

Is it faster to DrawPolyline than DrawLines with the same number of segments?

Many of my line segments have the same color, so I could join those into polylines if that is faster to display.

I don’t have a good answer for that at the moment. I would recommend profiling yourself to see if it makes a difference.

Sounds good. I will setup a simple grasshopper component and try different options.

Again, thank you for all the help!

@stevebaer, it looks like DrawPolyline is much faster than DrawLines.
I made a test that has 500,000 points. DrawPolyline too ~ 30ms and DrawLines took ~ 75ms.

Example methods:

        private void DrawPolyline(DrawEventArgs e)
        {
            var stopWatch = new System.Diagnostics.Stopwatch();
            stopWatch.Start();

            var xform = e.Display.ModelTransform * _xform;
            e.Display.PushModelTransform(xform);
            e.Display.DrawPolyline(_pline, System.Drawing.Color.DarkSalmon);
            e.Display.PopModelTransform();

            var time = stopWatch.ElapsedMilliseconds;
            RhinoApp.WriteLine($"PolylineDrawTime : {time}");
        }
        private void DrawSegments(DrawEventArgs e)
        {
            var stopWatch = new System.Diagnostics.Stopwatch();
            stopWatch.Start();

            var xform = e.Display.ModelTransform * _xform;
            e.Display.PushModelTransform(xform);
            e.Display.DrawLines(_segments, System.Drawing.Color.DarkOliveGreen);
            e.Display.PopModelTransform();

            stopWatch.Stop();
            var time = stopWatch.ElapsedMilliseconds;
            RhinoApp.WriteLine($"LineSegmentDrawTime : {time}");
        }

I also tested these methods being called from PostDraw, DrawOverlay, and DrawForeground. I didn’t see any real difference in the draw time.
I didn’t have any other objects in rhino, so maybe that would impact the results.

I could compute the transform ahead of time to speed things up, but other than that, I think this is close to the limit of what I know how to do.

1 Like