-1

Is there any reason why FillPolygon in Winform's paint event is slow? Is it because it calculates all px it should draw inside the triangle?

This is the part that uses the most time of the entire application to draw. Therefore, I would like to optimize it.

SolidBrush myBrush = new SolidBrush(Color.Black);
MatrixCellZoom zoom = rectangle.CellZoom;
List<Point> points = new List<Point>();
points.Add(zoom.pont1.ToPoint());
points.Add(zoom.pont2.ToPoint());
points.Add(zoom.pont3.ToPoint());

graphics.FillPolygon(myBrush, points.ToArray()); /* the show part */
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
eriksv88
  • 3,482
  • 3
  • 31
  • 50
  • 1
    What is `MatrixCellZoom`, here? What does `zoom.pont1.ToPoint()` perform? Above all, what is `graphics`? Have you tested this with `GraphicsPath`? + You're not disposing of the `Brush`. Testing the painting of a triangle using three fixed points, `FillPolygon` takes less than a millisecond to complete. – Jimi Dec 30 '18 at 18:11
  • MatrixCellZoom is just a class that have points like System.Drawing.Point. .ToPoint() is an extension feature for graphics, to convert it into System.Drawing.Point in the winforms project. I have a Commom library for all logic between platforms.zoom is a point of the triangle. – eriksv88 Dec 30 '18 at 19:41
  • Then your method (probably, you haven't posted it) takes too much time. But => *Above all, what is graphics?*. Test this in a control's `Paint` event using three points, as previously described. Measure the timing using a `StopWatch`. – Jimi Dec 30 '18 at 20:05
  • I use StopWatch to debug:). I have comment the line that is slow. I can't upload all code her. Its a big project. graphics=System.Drawing.Graphics. – eriksv88 Dec 30 '18 at 20:09
  • Yes, of course `graphics=System.Drawing.Graphics` :). But, where does the `graphics` object come from? Usually, when it's provided by the `PaintEventArgs` of a graphic method (`Paint`, `DrawItem` etc.), you have an `e.Graphics` object. In other words, how and where is this painting performed? – Jimi Dec 30 '18 at 20:15
  • PaintEventArgs, e.Graphics in a usercontrol . Where i call a extension function that call other extension functions – eriksv88 Dec 30 '18 at 20:49
  • 1
    Right. Now, read again all the comments, stepping carefully on 1) my first comment, about the drawing *speed* of `FillPolygon`, 2) *MatrixCellZoom is just a class that have points like System.Drawing.Point. .ToPoint() is an extension feature*. 3) *I have a Commom library for all logic between platforms.zoom is a point of the triangle* 4) *(...) Where i call a extension function that call other extension functions*. => What do you derive from this? I guess that `FillPolygon` has nothing to do with the *slow results* (undefined). It's all that comes before that's *slow* (undefined). – Jimi Dec 30 '18 at 20:56
  • 1
    Can you show us more meaningfull example of what you are trying to do? Drawing single triangle is obviously not the problem. – Antonín Lejsek Dec 30 '18 at 21:46
  • 1
    It is not slow at all. Go ahead and don't solves issue you do not have. (See: Premature Optimization) – TaW Dec 31 '18 at 11:19

1 Answers1

1

Revised answer - it's as fast as .FillRectangle. At least for a triangle.

enter image description here

        int incr = 1000000;
        using (var bmp = new Bitmap(200, 500))
        using (var gr = Graphics.FromImage(bmp))
        {
            DateTime timeBeforeFillRectangle = DateTime.Now;
            for (int i = 0; i < incr; i++)
            {
                gr.FillRectangle(Brushes.Orange, new Rectangle(0, 0, 100, 300));
            }
            Point[] points = new Point[] { new Point(10, 100), new Point(190, 200), new Point(80, 400) };
            DateTime timeBeforeFillPolygon = DateTime.Now;
            for (int i = 0; i < incr; i++)
            {
                gr.FillPolygon(Brushes.Orange, points);
            }

            TimeSpan ts1 = timeBeforeFillPolygon.Subtract(timeBeforeFillRectangle);
            TimeSpan ts2 = DateTime.Now.Subtract(timeBeforeFillPolygon);

            Console.WriteLine("FillRectangle seconds: " + ts1.TotalSeconds.ToString());
            Console.WriteLine("FillPolygon seconds: " + ts2.TotalSeconds.ToString());
        }
    }
toni
  • 133
  • 1
  • 10
  • thx,also if I have to fill the triangle with RGBA Color (opacity)? Or how would you solve this? – eriksv88 Dec 30 '18 at 17:07
  • Create a brush that has opacity - Brush b = new SolidBrush(Color.FromArgb(10, Color.Red)); That has 10% red. Correction, maybe not 10%. I think alpha is a number from 0 to 255. But you get the idea :) – toni Dec 30 '18 at 17:15
  • Yes, but the problem is really speed, will it be faster to fill it yourself px by px? :) – eriksv88 Dec 30 '18 at 17:22
  • I'm not sure, but when dealing with regions GDI creates an array of rectangles to cover the region. If it does the same here it will do some math and execute a series of fillrectangles. Do you have any proof to backup your assumption that we can do it faster than the system? - Also: _a flower, a swirl_ You seem to be confusing FillPolygon with FillCurves. – TaW Dec 31 '18 at 11:14
  • Drawing pixel by pixel would probably be slow as well. Another possible solution is to use .FillPolygon for a small representation of your triangle and then stretch the image. I think a triangle would resize without loss of resolution - but there is an example here if that doesn't work: https://stackoverflow.com/questions/1922040/how-to-resize-an-image-c-sharp/24199315 – toni Dec 31 '18 at 16:18
  • I don't understand the comment about FillCurves (.FillClosedCurve? ). What are the splines in a swirl? Or a lightning strike. Or the shape of Alaska. – toni Dec 31 '18 at 16:30
  • Ugh. I'll be deleting my answer tomorrow because it's wrong and when I delete it, I will no longer be able to comment. I tested .FillPolygon and it's super fast for a triangle (just as fast as .FillRectangle in a loop of 10,000 iterations). No one is more surprised than me! – toni Dec 31 '18 at 22:19
  • OR, you could convert this answer (which is not correct, that's for sure) and post the result of your tests. If you do, test the code in **release** mode, using the .exe file, not the VS IDE. Use 1 Million iterations as a base test. – Jimi Jan 01 '19 at 03:36
  • I like your idea better... revised with output. – toni Jan 01 '19 at 16:14
  • That's more like it. These timings can be considered higher that *expected* (it depends on who's expecting what) because you're painting a Bitmap. If you use the `e.Graphics` object provided by the Paint event of a WinForms control (what this question is about), the time required for both `FillRectangle` and `FillPolygon` is much less: the same test (`1,000,000` drawings) Painting on a Bitmap: `~28` seconds for both. Painting on a canvas: `12.72454` for `FillRectangle`, `7.12974` for `FillPolygon` (.Net 4.7.2, release mode). – Jimi Jan 01 '19 at 21:00