链接:洛谷P1742 最小圆覆盖(Welzl’s算法,三点求圆心的证明)_tomjobs的博客-CSDN博客
重点:
1.WelZl定理:
如果第i个点不在当前i-1个点求出的圆的范围内,则第i个点肯定在新圆上面。
三点圆公式,推导过程。
//判断点是否在圆形内
bool IsPointOnCirCle(const AcGePoint2d& centerPt,const double& radius, const AcGePoint2d& pt)
{
//如果小于半径则在圆内
if ((centerPt.distanceTo(pt) - radius)<DTE)
{
return true;
}
return false;
}
//三点圆求解公式
void GetCircleCenterPt(const AcGePoint2d& p0, const AcGePoint2d& p1, const AcGePoint2d& p2, AcGePoint2d& cp)
{
double a1 = p1.x - p0.x, b1 = p1.y - p0.y, c1 = (p1.x * p1.x - p0.x * p0.x + p1.y * p1.y - p0.y * p0.y) / 2;
double a2 = p2.x - p0.x, b2 = p2.y - p0.y, c2 = (p2.x * p2.x - p0.x * p0.x + p2.y * p2.y - p0.y * p0.y) / 2;
cp.x = (b2 * c1 - b1 * c2) / (a1 * b2 - a2 * b1);
cp.y = (a2 * c1 - a1 * c2) / (a2 * b1 - a1 * b2);
}
//输入多个点获取最小覆盖圆,采用WelZl算法
void GetCircleByWelZl(const vector<AcGePoint2d>& pts,double& radius, AcGePoint2d& centerPt)
{
if (pts.size()<2)
{
return;
}
radius = 0.0;
centerPt = pts[0];
for (int i = 1; i < pts.size(); ++i)
{
//如果在圆内
if (IsPointOnCirCle(centerPt, radius, pts[i]))
{
continue;
}
//如果不在,则以此点为圆心
centerPt = pts[i];
radius = 0.0;
for (int j = 0; j < i; ++j)
{
//如果在圆内
if (IsPointOnCirCle(centerPt, radius, pts[j]))
{
continue;
}
//获取两点圆心和半径
centerPt = AcGePoint2d((pts[i].x + pts[j].x) / 2, (pts[i].y + pts[j].y) / 2);
radius = centerPt.distanceTo(pts[j]);
for (int k = 0; k < j; ++k)
{
//如果在圆内
if (IsPointOnCirCle(centerPt, radius, pts[k]))
{
continue;
}
//不在,则根据三点圆求解公式
GetCircleCenterPt(pts[i], pts[j], pts[k], centerPt);
radius = centerPt.distanceTo(pts[k]);
}
}
}
}