2

I have the following code:

using (var gp = new GraphicsPath())
{    
    var outer = new PointF[outerpoly.Count];
    for (int i = 0; i < outerpoly.Count; i++)
    {
        outer[i] = new PointF(((int)(scale * outerpoly[i].X - xmin)), (int)(scale * (outerpoly[i].Y + -ymin)));
    }
    gp.AddPolygon(outer);
    foreach (var hole in insideholes)
    {
        if (hole.Count < 3) continue;
        var inner = new PointF[hole.Count];
        for (int i = 0; i < hole.Count; i++)
        {
            inner[i] = new PointF(((int)(scale * hole[i].X - xmin)), (int)(scale * (hole[i].Y + -ymin)));
        }
        gp.AddPolygon(inner);
    }
    Graphics.FromImage(e).FillPath(color, gp);
}

where outerpoly is a list of intpoints (pairs of x and y) representing the outer border of the polygon and inside holes are a list of list of intpoints representing the holes in side the polygon.

Now this code should draw a polygon with a number of holes in it. A example of what the inner and outer might be given as values:

outer
{System.Drawing.PointF[4]}
    [0]: {X=-289, Y=971}
    [1]: {X=-289, Y=0}
    [2]: {X=734, Y=971}
    [3]: {X=-289, Y=971}
inner
{System.Drawing.PointF[4]}
    [0]: {X=-158, Y=797}
    [1]: {X=189, Y=568}
    [2]: {X=-158, Y=568}
    [3]: {X=-158, Y=797}

Now the result of this code is that only the outer is drawn and the holes are ignored. Any idea why?

The code is based on the question.

When trying to use the exclude method instead like in the following:

var outer = new PointF[outerpoly.Count];
for (int i = 0; i < outerpoly.Count; i++)
{
    outer[i] = new PointF(((int)(scale * outerpoly[i].X - xmin)), (int)(scale * (outerpoly[i].Y + -ymin)));
}
var gp = new GraphicsPath();
gp.AddPolygon(outer);
Region rr = new Region(gp);

foreach (var hole in insideholes)
{
    if (hole.Count < 3) continue;
    var inner = new PointF[hole.Count];
    for (int i = 0; i < hole.Count; i++;)
    {
        inner[i] = new PointF(((int)(scale * hole[i].X - xmin)), (int)(scale * (hole[i].Y + -ymin)));
    }
    var gpe = new GraphicsPath();
    gpe.AddPolygon(inner);
    Region.Exclude(gpe);
    gpe.Dispose();
}
gp.Dispose();

Graphics.FromImage(e).FillRegion(color, rr);
rr.Dispose();

This crashed on the line Region.Exclude(gpe); instead, no exception, just a sudden crash to desktop.

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
Thijser
  • 2,625
  • 1
  • 36
  • 71
  • Sounds like a dupe of [this](http://stackoverflow.com/a/15078609/1997232) (note: vb.net). Try using `StartFigure`. – Sinatr Jan 04 '16 at 12:34
  • That question deals with visual basic not c#. How would I translate that? – Thijser Jan 04 '16 at 12:36
  • This is why I am not voting to close it. Try accepted answer from there. If it works for you then post answer for future `C#`-**only** programmers. – Sinatr Jan 04 '16 at 12:38
  • I'm also basing myself on https://stackoverflow.com/questions/4021078/drawing-polygon-with-more-than-one-hole , so I was hoping that I could find out what I was doing wrong compared to that (my vb is really bad) – Thijser Jan 04 '16 at 12:42
  • Try [excluding polygons](https://msdn.microsoft.com/en-us/library/tcbatwtk(v=vs.110).aspx) (holes) instead of adding them. – Sinatr Jan 04 '16 at 12:49
  • I have also added my attempt at using exclude region, this resulted in a crash on the line Region.Exclude(gpe); – Thijser Jan 04 '16 at 13:03
  • Was a bad idea. Maybe you simply have to set proper `FillRule`, see [this](http://www.blackwasp.co.uk/WPFPolygon.aspx). – Sinatr Jan 04 '16 at 13:15
  • A graphicsPath only has a FillMode not a FillRulle (which when I set it to Alternate didn't change anything). Or do you mean in somewhere else? – Thijser Jan 04 '16 at 13:21
  • 1
    More like [this one](https://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.fillmode(v=vs.110).aspx). Sorry for mixing up with wpf. It would be easier if you prepare [mcve](http://stackoverflow.com/help/mcve) for someone else being able to: 1) reproduce the problem 2) try something to fix it. – Sinatr Jan 04 '16 at 13:28
  • You started a bounty for this question. Currently no answer will automatically be awarded the bounty (as all are < 2 votes). Is there anything missing in these answers that you still want to know? – René Vogt Jan 18 '16 at 11:54
  • No just hadn't checked that you were correct yet. I rewarded your answer. – Thijser Jan 18 '16 at 13:08

2 Answers2

3

I generally join all inner graphics before and I create a GraphicsPath with the both outer and inner.
The default fill mode does the holes.

I use clipper to join the polygons:
http://www.angusj.com/delphi/clipper.php

If you need to clip the outer, you should create a clipping region:
https://msdn.microsoft.com/en-us/library/155t36zz(v=vs.110).aspx

        Graphics g = e.Graphics;
        var path = new GraphicsPath();

        Rectangle outer = new Rectangle(100, 100, 300, 300);
        Rectangle inner = new Rectangle(150, 150, 200, 200);

        path.AddRectangle(outer);
        path.AddRectangle(inner);

        var brush = new SolidBrush(Color.Blue);
        g.FillPath(brush, path);

Hole

leonardo
  • 41
  • 1
  • 6
2

I've tried your code by using it in the Paint event and drawing on my Form (using the Graphics from the PaintEventArgs).
You're Exclude attempt actually works fine. I think your problem arises in this line:

Region.Exclude(gpe);

The reason being, you actually mean

rr.Exclude(gpe);

You want to exclude the GraphicsPath from your rr, which you will fill later.
By typing Region you are probably cutting the region of the Control. Region is a property of a Control, not the instance you wanted to draw to.
If you declared this method inside your main Form this would explain why you encounter a "just a sudden crash to desktop", since you are destroying your Form's drawing region.

René Vogt
  • 43,056
  • 14
  • 77
  • 99