You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何合并带Z序效果的自相交GraphicsPath为单个图形对象?

实现带Z序视觉效果的单GraphicsPath自相交图形

需要创建具有Z序视觉效果的带边框自相交图形:后绘制的路径覆盖前路径的重叠区域,且两个路径各自保留完整边框。当前分开绘制两个GraphicsPath可实现预期效果,但合并为单个路径后,填充和边框均不符合需求。

现有实现(分开绘制,效果正确)

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);
}

合并路径后的问题(效果不符合预期)

合并路径后,系统会按FillMode规则计算整体填充区域,边框也会变成整个路径的外轮廓,丢失了两个路径的独立边框和Z序覆盖效果:

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);
}

简便解决方案:单个GraphicsPath+子路径遍历绘制

将两个路径作为独立子路径存入单个GraphicsPath,绘制时遍历每个子路径分别填充和描边,既保留单个对象的可操作性(统一变换),又还原分开绘制的视觉效果:

步骤1:封装遍历绘制方法

public static void DrawPathWithZOrder(Graphics g, Brush brush, Pen pen, GraphicsPath path)
{
    using (GraphicsPathIterator iterator = new GraphicsPathIterator(path))
    {
        using (GraphicsPath subPath = new GraphicsPath())
        {
            bool isClosed;
            while (iterator.NextSubpath(subPath, out isClosed))
            {
                g.FillPath(brush, subPath);
                g.DrawPath(pen, subPath);
                subPath.Reset();
            }
        }
    }
}

步骤2:创建包含子路径的单个GraphicsPath

private void Example3(PaintEventArgs e)
{
    Brush brush = new SolidBrush(Color.FromArgb(200, Color.LightBlue));
    GraphicsPath combinedPath = new GraphicsPath(FillMode.Winding);

    // 添加第一个子路径
    combinedPath.StartFigure();
    combinedPath.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)
    });
    combinedPath.CloseFigure();

    // 添加第二个子路径
    combinedPath.StartFigure();
    combinedPath.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)
    });
    combinedPath.CloseFigure();

    // 统一变换示例(可选)
    e.Graphics.TranslateTransform(50, 50);

    // 使用自定义方法绘制,还原Z序和独立边框
    DrawPathWithZOrder(e.Graphics, brush, Pens.Blue, combinedPath);
}

原理说明

  • StartFigure()和CloseFigure()将两条路径标记为GraphicsPath中的独立子路径
  • GraphicsPathIterator负责遍历每个子路径,分别执行填充和描边,完全复刻分开绘制的视觉效果
  • 单个combinedPath可直接应用平移、缩放等变换,满足“单个图形对象处理”的需求

内容的提问来源于stack exchange,提问作者stenio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 14:20:49