Search code examples
c#system.drawing

Self-intersecting GraphicsPath with z-order


I need to create a framed GraphicsPath that self-intersects giving a z-order feeling:

Required effect

The code that I used to obtain the image is the following:

private void Example1(PaintEventArgs e) {
    Brush brush = new SolidBrush(Color.FromArgb(200, Color.LightBlue));

    GraphicsPath path1 = new GraphicsPath(FillMode.Winding);
    path1.AddLines(new Point[] {
        new Point(400, 200),
        new Point(400, 300),
        new Point(100, 300),
        new Point(100, 400),
        new Point(500, 400),
        new Point(500, 100)
    });
    e.Graphics.FillPath(brush, path1);
    e.Graphics.DrawPath(Pens.Blue, path1);

    GraphicsPath path2 = new GraphicsPath(FillMode.Winding);
    path2.AddLines(new Point[] {
        new Point(500, 100),
        new Point(200, 100),
        new Point(200, 500),
        new Point(300, 500),
        new Point(300, 200),
        new Point(400, 200)
    });
    e.Graphics.FillPath(brush, path2);
    e.Graphics.DrawPath(Pens.Blue, path2);
}

in which I draw the two paths independently.

My need is to handle it as a unique graphic object, but if I join the paths I obtain this image:

No good image

Example code:

private void Example2(PaintEventArgs e) {
    Brush brush = new SolidBrush(Color.FromArgb(200, Color.LightBlue));

    GraphicsPath path1 = new GraphicsPath(FillMode.Winding);
    path1.AddLines(new Point[] {
        new Point(400, 200),
        new Point(400, 300),
        new Point(100, 300),
        new Point(100, 400),
        new Point(500, 400),
        new Point(500, 100)
    });

    GraphicsPath path2 = new GraphicsPath(FillMode.Winding);
    path2.AddLines(new Point[] {
        new Point(500, 100),
        new Point(200, 100),
        new Point(200, 500),
        new Point(300, 500),
        new Point(300, 200),
        new Point(400, 200)
    });

    path1.AddPath(path2, true);
    e.Graphics.FillPath(brush, path1);
    e.Graphics.DrawPath(Pens.Blue, path1);
}

Same problem if I use StartFigure/CloseFigure. Maybe I can solve the problem using the SetMarkers method in conjunction with the GraphicsPathIterator, but it seems overwhelming.


Solution

  • The simplest way that I found is to use the GraphicsPathIterator. In this way I can store more figures on a single path and have the flexibility I need during the painting. The only drawback is that the paint method has to be modified accordingly.

    Here is an example in which I define the path and that do also the painting:

    private void Example4(PaintEventArgs e) {
        Brush brush = new SolidBrush(Color.FromArgb(200, Color.LightBlue));
    
        GraphicsPath path = new GraphicsPath(FillMode.Winding);
        path.StartFigure();
        path.AddLines(new Point[] {
            new Point(400, 200),
            new Point(400, 300),
            new Point(100, 300),
            new Point(100, 400),
            new Point(500, 400),
            new Point(500, 100)
        });
    
        path.StartFigure();
        path.AddLines(new Point[] {
            new Point(500, 100),
            new Point(200, 100),
            new Point(200, 500),
            new Point(300, 500),
            new Point(300, 200),
            new Point(400, 200)
        });
    
        GraphicsPathIterator pathIterator = new GraphicsPathIterator(path);
        GraphicsPath p = new GraphicsPath();
        while (pathIterator.NextSubpath(p, out bool isClosed) > 0) {
            e.Graphics.FillPath(brush, p);
            e.Graphics.DrawPath(Pens.Blue, p);
        }
    }