2014-09-23 478 views
0

我已经在onPaint事件中使用由WinForm提供的简单图形函数创建维恩图。这是我创建Venn的代码。使用图形区域定义维恩图的区域

using (Brush brushLeft = new SolidBrush(LeftVennColor)) 
    { 
    leftvennPath.AddEllipse(leftVenn); 
    leftOnlyRegion = new Region(leftVenn); 
    e.Graphics.FillEllipse(brushLeft, leftVenn); 
    e.Graphics.DrawEllipse(pen, leftVenn); 
    } 

    using (Brush brushRight = new SolidBrush(RightVennColor)) 
    { 
    rightvennPath.AddEllipse(rightVenn); 
    rightOnlyRegion = new Region(rightVenn); 
    e.Graphics.FillEllipse(brushRight, rightVenn); 
    e.Graphics.DrawEllipse(pen, rightVenn); 
    } 

    using (GraphicsPath circle_path = new GraphicsPath()) 
    { 
    circle_path.AddEllipse(leftVenn); 
    commonRegion.Intersect(circle_path); 
    } 

    using (GraphicsPath circle_path = new GraphicsPath()) 
    { 
    circle_path.AddEllipse(rightVenn); 
    commonRegion.Intersect(circle_path); 
    } 

的维恩图被创建,但与此代码我的共同区域是左右两个椭圆的交点。我想在公共区域外有两个单独的区域,它们之间用一条线隔开。下面是..我在小鼠使用Region.IsVisible(e.location),用于使得图像,

enter image description here

因此,基本上,我需要所有这四个区域分开和可点击(不同颜色的每个区域)点击事件来处理点击事件。有人可以帮忙吗?

+0

你想要它们作为路径或地区? – 2014-09-23 20:07:58

+0

作为地区,我可以处理鼠标点击事件。 – user1821499 2014-09-23 20:08:24

+0

请参阅最终修改。 – 2014-09-24 02:09:53

回答

0

最终溶液:

CX0,CY0,radius0中心和左圆的半径
CX1,CY1,radius1的中心和右圆的半径

该函数由REF取区域。

private void FindRegions(int cx0, int cx1, int cy0, int cy1, int radius0, int radius1, ref Region rgnLeft, ref Region rgnRight) 
    { 
     //Left circle 
     GraphicsPath gpL = new GraphicsPath(); 
     //Right circle 
     GraphicsPath gpR = new GraphicsPath(); 
     //The right small region (yellow color) 
     GraphicsPath gp = new GraphicsPath(); 
     //Points of intersection 
     PointF pnt1 = new PointF(); 
     PointF pnt2 = new PointF(); 

     Graphics g = this.CreateGraphics(); 

     gpL.AddEllipse(new Rectangle(cx0 - radius0, cy0 - radius0, 2 * radius0, 2 * radius0)); 
     gpR.AddEllipse(new Rectangle(cx1 - radius0, cy1 - radius1, 2 * radius1, 2 * radius1)); 

     g.DrawPath(Pens.Red, gpL); 
     g.DrawPath(Pens.Blue, gpR); 

     int numPoints = FindCircleCircleIntersections((single)cx0, (single)cx1, (single)cy0, (single)cy1, (single)radius0, (single)radius1, ref pnt1, ref pnt2); 

     if (numPoints != 2) 
     { 
      //No regions 
      return; 
     } 

     Double theta, fe; 
     Double dx = (double)pnt1.X - (double)pnt2.X; 
     Double dy = (double)pnt1.Y - (double)pnt2.Y; 
     Double dist = Math.Sqrt(dx * dx + dy * dy); 

     PointF minPoint, maxPoint; 

     if (pnt2.Y < pnt1.Y) 
     { 
      minPoint = pnt2; 
      maxPoint = pnt1; 
     } 
     else 
     { 
      minPoint = pnt1; 
      maxPoint = pnt2; 
     } 

     //theta is the angle between the three points pnt1, pnt2 and left center 
     theta = Math.Acos((dist/2D)/100D); 
     theta = (theta * 180D)/Math.PI; 
     theta = 90D - theta; 
     theta *= 2D; 

     //fe is the starting angle of the point(between pnt1 and pnt2) with 
     //the smaller y coordinate. The angle is measured from x axis and clockwise 
     fe = Math.Asin(Math .Abs ((-(Double)minPoint.Y + (double)cy0))/ (double)radius0); 
     fe = (fe * 180D)/Math.PI; 

     if (minPoint.X > cx0 && minPoint.Y >= cy0) 
     { 
      //fe = (90 - fe) + 270; 
     } 
     else if (minPoint.X > cx0 && minPoint.Y < cy0) 
     { 
      fe = (90D - fe) + 270D; 
     } 
     else if (minPoint.X == cx0 && minPoint.Y < cy0) 
     { 
      fe = 270D; 
     } 
     else 
     { 
      fe += 180D; 
     } 

     gp.AddArc(new Rectangle(cx0 - radius0, cy0 - radius0, 2 * radius0, 2 * radius0), (float)fe, (float)theta); 
     gp.AddLine(maxPoint, minPoint); 

     gp.CloseFigure(); 

     g.DrawPath(Pens.Green, gp); 

     Region rgnL = new Region(gpL); 
     Region rgnR = new Region(gpR); 
     Region rgnInt = new Region(gpL); 
     Region rgn = new Region(gp); //right small 

     rgnInt.Intersect(rgnR); 

     rgnInt.Exclude(rgn); //left small 

     g.FillRegion(Brushes.DarkGreen, rgnInt); 
     g.FillRegion(Brushes.DarkGray, rgn); 

     rgnLeft = rgnInt.Clone(); 
     rgnRight = rgn.Clone(); 

     g.Dispose(); 
     rgnL.Dispose(); 
     rgnR.Dispose(); 
     rgnInt.Dispose(); 
     rgn.Dispose(); 
     gpL.Dispose(); 
     gpR.Dispose(); 
     gp.Dispose(); 
    } 

    private int FindCircleCircleIntersections(Single cx0, Single cx1, Single cy0, Single cy1, Single radius0, Single radius1, 
               ref PointF intersection1, ref PointF intersection2) 
    { 
     // Find the distance between the centers. 
     Single dx = cx0 - cx1; 
     Single dy = cy0 - cy1; 
     Double dist = Math.Sqrt(dx * dx + dy * dy); 

     // See how many solutions there are. 
     if (dist > radius0 + radius1) 
     { 
      //No solutions, the circles are too far apart. 
      intersection1 = new PointF(Single.NaN, Single.NaN); 
      intersection2 = new PointF(Single.NaN, Single.NaN); 
      return 0; 
     } 
     else if (dist < Math.Abs(radius0 - radius1)) 
     { 
      // No solutions, one circle contains the other. 
      intersection1 = new PointF(Single.NaN, Single.NaN); 
      intersection2 = new PointF(Single.NaN, Single.NaN); 
      return 0; 
     } 
     else if ((dist == 0) && (radius0 == radius1)) 
     { 
      // No solutions, the circles coincide. 
      intersection1 = new PointF(Single.NaN, Single.NaN); 
      intersection2 = new PointF(Single.NaN, Single.NaN); 
      return 0; 
     } 
     else 
     { 
      // Find a and h. 
      Double a = (radius0 * radius0 - radius1 * radius1 + dist * dist)/(2 * dist); 
      Double h = Math.Sqrt(radius0 * radius0 - a * a); 

      // Find P2. 
      Double cx2 = cx0 + a * (cx1 - cx0)/dist; 
      Double cy2 = cy0 + a * (cy1 - cy0)/dist; 

      // Get the points P3. 
      intersection1 = new PointF((Single)(cx2 + h * (cy1 - cy0)/dist), (Single)(cy2 - h * (cx1 - cx0)/dist)); 
      intersection2 = new PointF((Single)(cx2 - h * (cy1 - cy0)/dist), (Single)(cy2 + h * (cx1 - cx0)/dist)); 

      // See if we have 1 or 2 solutions. 
      if (dist == radius0 + radius1) return 1; 
      return 2; 
     } 
    } 

编辑

地区只有一个填写方法,没有绘制之一。所以你不能与地区做。 GraphicPath 然而HAS填写绘制
你说,你需要验证,如果一个点的区域内,但你可以做同样的GraphicPath

myGraphicPath.IsVisible(); 

所以,不要使用地区,但路径。另一个原因更好。 GraphicPath可以绘制AntiAlias但区域。设置

g.SmoothingMode = SmoothingMode.AntiAlias; 

要启用消除锯齿。所有的道具好东西!

改变函数的名字从FindRegionsFindPaths和发送路径,REFFERENCE:

private void FindPaths(int cx0, int cx1, int cy0, int cy1, int radius0, int radius1, ref GraphicsPath gpLeft, ref GraphicsPath gpRight) 

的代码是完全一样的,但增加在与:

private void FindPaths(int cx0, int cx1, int cy0, int cy1, int radius0, int radius1, ref GraphicsPath gpLeft, ref GraphicsPath gpRight) 
{ 
    ... 
    ... 
    //Above code exactly the same  

    //replace these 
    //rgnLeft = rgnInt.Clone(); 
    //rgnRight = rgn.Clone(); 

    //with these 
    GraphicsPath gpLeftSmall = (GraphicsPath)gp.Clone(); 
    Matrix matrix = new Matrix(); 

    PointF pntf = new PointF(); 

    pntf.X = (float)(Math.Min((double)pnt1.X, (double)pnt2.X) + Math.Abs((double)(pnt1.X - pnt2.X)/2D)); 
    pntf.Y = (float)(Math.Min((double)pnt1.Y, (double)pnt2.Y) + Math.Abs((double)(pnt1.Y - pnt2.Y)/2D)); 

    matrix.RotateAt(180, pntf); 

    gpLeftSmall.Transform(matrix); 

    g.DrawPath(Pens.Black, gpLeftSmall); //If you want to draw it 

    //passed by refference 
    gpLeft = gpLeftSmall.Clone(); 
    gpRight = gp.Clone(); 


    g.Dispose(); 

    rgnL.Dispose(); 
    rgnR.Dispose(); 
    rgnInt.Dispose(); 
    rgn.Dispose(); 

    gpL.Dispose(); 
    gpR.Dispose(); 
    gp.Dispose(); 
    gpLeftSmall.Dispose(); 

    matrix.Dispose(); 
} 

参考: Determine where two circles intersect

+0

非常感谢这..我还有一个问题,我需要突出显示选定的区域(边界)与黑色的笔指示这个区域被选中。例如,如果我只选择左边的维恩区域,那么该区域的边界应该变成黑色(突出显示)。有什么办法可以解决这个问题吗? – user1821499 2014-09-25 17:14:01

+0

@ user1821499请参阅编辑:) – 2014-09-25 18:51:56