How to paint a certain area

邮差的信 提交于 2021-01-27 15:30:32

问题


I am new to drawing and paints in c# & I am trying to make a simple program it has 3 intersecting circles (A,B,C). What i want to do is paint a certain (according to result I get).

For example: If I get 1 as a result I want to fill the yellow bordered region, if I get 4 I want to fill green bordered region and so on.

My Code to draw these 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:


Since you are new to this topic I have to tell you: This is a lot harder that one would hope for.

Three solutions come to mind:

  • Construct a GraphicsPath you could fill from three Arcs. To calculate the arcs you need the rectangles you have but also the sweeping angle and also the starting angle. This will take quite some math..

  • After having drawn into a Bitmap you could floodfill the area you want to color. This will only work for bitamps from which you can extract the current color of each pixel, not for drawing onto controls..

  • The simplest way it still a bit involved, but only mildly so

Solution 3 (Create a Region and fill it)

You can use all sorts of set operations to combine areas called Regions. And you can construct a Region from a GraphicsPath. And you can construct a GraphicsPath by adding an ellipse. And you can clip the drawing area of a Graphics object to a Region.

Let's try:

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();
    .....

}

Do note that the region operations change the current region; if you want to fill more areas you need to restore the changed region!

Also note that I draw where any persistent drawing belongs: In the Paint event and that I use its e.Graphics object..

GraphicsPaths as Regions are GDI objects and should be disposed off!


Notes on solution 1 (Create a GraphicsPath by Math)

The full math is rather involved. By making a few assumptions the task can be greatly simplified: Let's assume the circles have the same size. Also that we first look at two circles only, with the same y-position. Finally that the circles form a symmetrical figure. (Which btw they don't: the red circle should have x=190 and the green one y=186,45..)

Getting the two intersection points as well as the sweeping angle is not so hard.

Next one can rotate the two points twice around the center of the whole figure by 120° using a Matrix; see here for an example. Now we have six points; we still need the smaller sweeping angle, which is also found with simple math.

Finally we can construct all 12 (!) GraphicsPaths from the 12 arcs and combine them at will.

The good part is that we can both fill and draw those paths. But, the code is rather extensive..


Notes on solution 2 (floodfill)

While you can't floodfill directly on a control you can prepare the result in a bitmap and then display that image on the control with Graphics.DrawImage.

For an example of coding a floodfill see this post!



来源:https://stackoverflow.com/questions/49964007/how-to-paint-a-certain-area

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!