我在圆周上有三个点:
pt A =(A.x,A.y); pt B =(B.x,B.y); pt C =(C.x,C.y);
如何计算圆心?
在Processing(Java)中实现它。
我找到了答案并实施了一个有效的解决方案:
pt circleCenter(pt A, pt B, pt C) {
float yDelta_a = B.y - A.y;
float xDelta_a = B.x - A.x;
float yDelta_b = C.y - B.y;
float xDelta_b = C.x - B.x;
pt center = P(0,0);
float aSlope = yDelta_a/xDelta_a;
float bSlope = yDelta_b/xDelta_b;
center.x = (aSlope*bSlope*(A.y - C.y) + bSlope*(A.x + B.x)
- aSlope*(B.x+C.x) )/(2* (bSlope-aSlope) );
center.y = -1*(center.x - (A.x+B.x)/2)/aSlope + (A.y+B.y)/2;
return center;
}
答案 0 :(得分:18)
这是我的Java端口,当行列式以非常优雅的IllegalArgumentException
消失时,避开错误条件,我的方法是应对“点是两个相距甚远”或“点在一条线上”的条件。此外,这会计算您的相交斜率方法不会做的半径(并应对异常条件)。
public class CircleThree
{
static final double TOL = 0.0000001;
public static Circle circleFromPoints(final Point p1, final Point p2, final Point p3)
{
final double offset = Math.pow(p2.x,2) + Math.pow(p2.y,2);
final double bc = ( Math.pow(p1.x,2) + Math.pow(p1.y,2) - offset )/2.0;
final double cd = (offset - Math.pow(p3.x, 2) - Math.pow(p3.y, 2))/2.0;
final double det = (p1.x - p2.x) * (p2.y - p3.y) - (p2.x - p3.x)* (p1.y - p2.y);
if (Math.abs(det) < TOL) { throw new IllegalArgumentException("Yeah, lazy."); }
final double idet = 1/det;
final double centerx = (bc * (p2.y - p3.y) - cd * (p1.y - p2.y)) * idet;
final double centery = (cd * (p1.x - p2.x) - bc * (p2.x - p3.x)) * idet;
final double radius =
Math.sqrt( Math.pow(p2.x - centerx,2) + Math.pow(p2.y-centery,2));
return new Circle(new Point(centerx,centery),radius);
}
static class Circle
{
final Point center;
final double radius;
public Circle(Point center, double radius)
{
this.center = center; this.radius = radius;
}
@Override
public String toString()
{
return new StringBuilder().append("Center= ").append(center).append(", r=").append(radius).toString();
}
}
static class Point
{
final double x,y;
public Point(double x, double y)
{
this.x = x; this.y = y;
}
@Override
public String toString()
{
return "("+x+","+y+")";
}
}
public static void main(String[] args)
{
Point p1 = new Point(0.0,1.0);
Point p2 = new Point(1.0,0.0);
Point p3 = new Point(2.0,1.0);
Circle c = circleFromPoints(p1, p2, p3);
System.out.println(c);
}
}
void circle_vvv(circle *c)
{
c->center.w = 1.0;
vertex *v1 = (vertex *)c->c.p1;
vertex *v2 = (vertex *)c->c.p2;
vertex *v3 = (vertex *)c->c.p3;
float bx = v1->xw; float by = v1->yw;
float cx = v2->xw; float cy = v2->yw;
float dx = v3->xw; float dy = v3->yw;
float temp = cx*cx+cy*cy;
float bc = (bx*bx + by*by - temp)/2.0;
float cd = (temp - dx*dx - dy*dy)/2.0;
float det = (bx-cx)*(cy-dy)-(cx-dx)*(by-cy);
if (fabs(det) < 1.0e-6) {
c->center.xw = c->center.yw = 1.0;
c->center.w = 0.0;
c->v1 = *v1;
c->v2 = *v2;
c->v3 = *v3;
return;
}
det = 1/det;
c->center.xw = (bc*(cy-dy)-cd*(by-cy))*det;
c->center.yw = ((bx-cx)*cd-(cx-dx)*bc)*det;
cx = c->center.xw; cy = c->center.yw;
c->radius = sqrt((cx-bx)*(cx-bx)+(cy-by)*(cy-by));
}
答案 1 :(得分:15)
它可以是一个相当深入的计算。这里有一个简单的步骤:http://paulbourke.net/geometry/circlesphere/。一旦你得到圆的方程,你可以简单地把它放在一个涉及H和K的形式。点(h,k)将是中心。
(在链接处向下滚动一点以获得方程式)
答案 2 :(得分:4)
当我在这个问题上盘旋时,我正在寻找类似的算法。 拿到你的代码,但发现这在斜率为0或无穷大的情况下都不起作用(当xDelta_a或xDelta_b为0时可以为真)。
我更正了算法,这是我的代码。 注意:我使用的是Objective-c编程语言,我只是更改了点值初始化的代码,所以如果这是错误的,我相信在java中工作的程序员可以纠正它。然而,逻辑对所有人来说都是一样的(上帝保佑算法!! :))
就我自己的功能测试而言,工作完全正常。 如果逻辑错误,请告诉我。
pt circleCenter(pt A, pt B, pt C) {
float yDelta_a = B.y - A.y;
float xDelta_a = B.x - A.x;
float yDelta_b = C.y - B.y;
float xDelta_b = C.x - B.x;
pt center = P(0,0);
float aSlope = yDelta_a/xDelta_a;
float bSlope = yDelta_b/xDelta_b;
pt AB_Mid = P((A.x+B.x)/2, (A.y+B.y)/2);
pt BC_Mid = P((B.x+C.x)/2, (B.y+C.y)/2);
if(yDelta_a == 0) //aSlope == 0
{
center.x = AB_Mid.x;
if (xDelta_b == 0) //bSlope == INFINITY
{
center.y = BC_Mid.y;
}
else
{
center.y = BC_Mid.y + (BC_Mid.x-center.x)/bSlope;
}
}
else if (yDelta_b == 0) //bSlope == 0
{
center.x = BC_Mid.x;
if (xDelta_a == 0) //aSlope == INFINITY
{
center.y = AB_Mid.y;
}
else
{
center.y = AB_Mid.y + (AB_Mid.x-center.x)/aSlope;
}
}
else if (xDelta_a == 0) //aSlope == INFINITY
{
center.y = AB_Mid.y;
center.x = bSlope*(BC_Mid.y-center.y) + BC_Mid.x;
}
else if (xDelta_b == 0) //bSlope == INFINITY
{
center.y = BC_Mid.y;
center.x = aSlope*(AB_Mid.y-center.y) + AB_Mid.x;
}
else
{
center.x = (aSlope*bSlope*(AB_Mid.y-BC_Mid.y) - aSlope*BC_Mid.x + bSlope*AB_Mid.x)/(bSlope-aSlope);
center.y = AB_Mid.y - (center.x - AB_Mid.x)/aSlope;
}
return center;
}
答案 3 :(得分:2)
public Vector2 CarculateCircleCenter(Vector2 p1, Vector2 p2, Vector2 p3)
{
Vector2 center = new Vector2();
float ma = (p2.y - p1.y) / (p2.x - p1.x);
float mb = (p3.y - p2.y) / (p3.x - p2.x);
center.x = (ma * mb * (p1.y - p3.y) + mb * (p1.x - p2.x) - ma * (p2.x + p3.x)) / (2 * (mb - ma));
center.y = (-1 / ma) * (center.x - (p1.x + p2.x) * 0.5) + (p1.y + p2.y) * 0.5;
return center;
}
答案 4 :(得分:0)
对不起,我的回答来晚了。当两个点形成一条垂直线时,任何使用“坡度”的解决方案都将失败,因为坡度将是无限的。
这是一个适用于2019的简单而强大的解决方案,始终可以正常工作:
public static boolean circleCenter(double[] p1, double[] p2, double[] p3, double[] center) {
double ax = (p1[0] + p2[0]) / 2;
double ay = (p1[1] + p2[1]) / 2;
double ux = (p1[1] - p2[1]);
double uy = (p2[0] - p1[0]);
double bx = (p2[0] + p3[0]) / 2;
double by = (p2[1] + p3[1]) / 2;
double vx = (p2[1] - p3[1]);
double vy = (p3[0] - p2[0]);
double dx = ax - bx;
double dy = ay - by;
double vu = vx * uy - vy * ux;
if (vu == 0)
return false; // Points are collinear, so no unique solution
double g = (dx * uy - dy * ux) / vu;
center[0] = bx + g * vx;
center[1] = by + g * vy;
return true;
}
只有在3点共线的情况下,以上代码才会返回“ false”。
答案 5 :(得分:0)
def circle_mid_point(list_b):
list_k = []
for i in range(3):
for j in range(1,4):
if i+j <=3:
midpoint_x1 = (list_b[i][0] + list_b[i+j][0])/2
midpoint_y1 = (list_b[i][1] + list_b[i + j][1]) / 2
list_k.append([midpoint_x1,midpoint_y1]) # list of all the midpoints of the lines
for k in range(len(list_k)):
for j in range(1,len(list_k)-1):
if list_k[k] == list_k[k+j]: #at centre only two midpoints will have the same value
return list_k[k]
k = circle_mid_point([[0,1],[1,0],[-1,0],[0,-1]])
print(k)