如何涂制特定区域?

3
我是新手,正在学习使用C#绘图和画笔,并尝试制作一个简单的程序,其中包含3个相交的圆(A、B、C)。我的目标是根据得到的结果涂上特定的颜色。
例如:如果结果为1,则我想填充黄色边框区域;如果结果为4,则我想填充绿色边框区域,以此类推。

Circles

绘制这些圆的代码:

private void button1_Click(object sender, EventArgs e)
    {
        Graphics A = this.CreateGraphics();
        Graphics B = this.CreateGraphics();
        Graphics C = this.CreateGraphics();
        Pen Bluepen = new Pen(Color.Blue, 2);
        Pen RedPen = new Pen(Color.Red, 2);
        Pen BlackPen = new Pen(Color.Black, 2);
        A.DrawEllipse(Bluepen,100, 100, 150, 150);
        B.DrawEllipse(RedPen, 195, 100, 150, 150);
        C.DrawEllipse(BlackPen, 145, 190, 150, 150);
    }

1
你只需要一个 Graphics 对象,使用完毕后需要调用 Dispose() 方法释放它。 - H H
1个回答

5

由于您对这个主题还不熟悉,我必须告诉您:这比人们所期望的要难得多。

有三种解决方案:

  • 构建一个GraphicsPath,您可以从三个Arcs中填充它。要计算弧线,您需要拥有矩形,还需要扫描角度和起始角度。这将需要一些数学知识。

  • 在绘制到Bitmap之后,您可以洪泛填充要着色的区域。这仅适用于可以从中提取每个像素的当前颜色的位图,而不适用于绘制到控件上。

  • 最简单的方法还是有点复杂,但只是稍微复杂一点。

第三种解决方案(创建区域并填充)

你可以使用各种集合操作来组合称为区域的区域。并且您可以从GraphicsPath构造一个Region。您还可以通过添加椭圆来构造GraphicsPath。您可以将Graphics对象的绘图区域剪切到Region中。

让我们试试:

enter image description here

private void panel1_Paint(object sender, PaintEventArgs e)
{
    Graphics g = e.Graphics;
    g.SmoothingMode = SmoothingMode.AntiAlias;

    Rectangle r1 = new Rectangle(100, 100, 150, 150);
    Rectangle r2 = new Rectangle(195, 100, 150, 150);
    Rectangle r3 = new Rectangle(145, 190, 150, 150);
    GraphicsPath gp1 = new GraphicsPath();
    GraphicsPath gp2 = new GraphicsPath();
    GraphicsPath gp3 = new GraphicsPath();
    gp1.AddEllipse(r1);
    gp2.AddEllipse(r2);
    gp3.AddEllipse(r3);
    Region r_1 = new Region(gp1);
    Region r_2 = new Region(gp2);
    Region r_3 = new Region(gp3);

    r_1.Intersect(r_2);   // just two of five..
    r_1.Exclude(r_3);     // set operations supported!

    g.SetClip(r_1, CombineMode.Replace);
    g.Clear(Color.Magenta);    // fill the remaining region
    g.ResetClip();

    g.DrawEllipse(Pens.Red, r1);
    g.DrawEllipse(Pens.Blue, r2);
    g.DrawEllipse(Pens.Green, r3);

   // finally dispose of all Regions and GraphicsPaths!!
    r_1.Dispose();
    gp1.Dispose();
    .....

}

请注意,区域操作会更改当前区域;如果您想填充更多区域,则需要恢复更改的区域!
还要注意,我在任何持久绘图所属的位置进行绘制:在Paint事件中,并使用其e.Graphics对象。 GraphicsPaths作为Regions是GDI对象,应该被处理!

解决方案1的注意事项(通过数学创建GraphicsPath)

完整的数学运算相当复杂。通过做出一些假设,可以大大简化任务:让我们假设圆的大小相同。同样,我们只看具有相同y位置的两个圆。最后,假设这些圆形成对称图形。(顺便说一句,它们并不是对称的:红色圆应该有x=190和绿色圆y=186.45..)

获得两个交点以及扫描角度并不那么困难。

接下来,我们可以使用Matrix将整个图形的中心旋转两次,每次旋转120°;请参见此处的示例。现在我们有了六个点;我们仍然需要较小的扫描角度,这也可以通过简单的数学找到。

最后,我们可以构造所有12(!)GraphicsPaths,从12个弧形组合它们。

好处是我们可以填充和绘制这些路径。但是,代码相当复杂。


关于解决方案2(泛洪填充)的注释

虽然您不能直接在控件上进行泛洪填充,但可以在位图上准备结果,然后使用Graphics.DrawImage在控件上显示该图像。

有关编写泛洪填充的示例,请参见this post


1
非常感谢,我想在做这件事之前需要学习很多东西。再次感谢。 - Danial Ahmed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接