我使用WinForm在onPaint事件中提供的简单图形函数创建了一个维恩图。这是我创建维恩的代码。
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)来处理click事件。有人可以帮忙吗?
答案 0 :(得分: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;
}
}
修改
Region 只有 Fill 方法,没有 Draw 方法。所以你不能用地区来做。 GraphicPath
但是 HAS 填充和绘制。
你说你需要验证一个点是否在区域内但是你可以用 GraphicPath
myGraphicPath.IsVisible();
所以,不要使用区域而是使用路径。其他原因更好。 GraphicPath 可以绘制 AntiAlias ,但区域不。设置
g.SmoothingMode = SmoothingMode.AntiAlias;
启用 AntiAlias 。所有带路径的好东西!
将函数名称从 FindRegions 更改为 FindPaths ,并将路径作为参考发送:
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();
}