给出三个点时找到圆心

时间:2013-07-09 13:54:41

标签: algorithm math linear-equation

我研究了this link并进行了相应的编码,但是对链接中解释的示例进行了错误的答案, 在求解方程期间,我从方程1中减去方程2,从方程2中减去方程3,然后进一步进行。请查看链接以获得澄清。

我的代码是:

include<stdio.h>
int is_formCircle(float a1,float b1,float a2,float b2,float a3,float b3) {
  float p1=a2-a1;
  float p2=a3-a2;
  float p3=b2-b1;
  float p4=b3-b2;
  float alpha=(a1+a2)*(a1-a2) + (b1+b2)*(b1-b2);
  float beta =(a2+a3)*(a2-a3) + (b2+b3)*(b2-b3);
  float y1=p1*beta - p2*alpha;
  float y2=p2*p3 - p1*p4;
  if(y2==0 || y1==0) return 1;
  float y=y1/y2;
  float x1 = 2*p4*y + beta;
  float x2 = 2*p2;
  float x = x1/x2;
  printf("x=%f  y=%f\n",x,y);
  return 0;
}
int main() {
 float a1,a2,a3,a4,b1,b2,b3,b4;
 a1=4.0;
 b1=1.0;
 a2=-3.0;
 b2=7.0;
 a3=5.0;
 b3=-2.0;
 is_formCircle(a1,b1,a2,b2,a3,b3);
 return 0;
}

我的另一个代码:

#include<stdio.h>
int is_formCircle(float a1,float b1,float a2,float b2,float a3,float b3) {                  
  float mid1,mid2,mid3,mid4,m1,m2,D,Dx,Dy,x,y;
  mid1 = a1+(a2-a1)/2;
  mid2 = b1+(b2-b1)/2;
  mid3 = a2+(a3-a2)/2;
  mid4 = b2+(b3-b2)/2;
  m1=(b2-b1)/(a2-a1);
  m2=(b3-b2)/(a3-a2);
  m1=-1*m1;
  m2=-1*m2;
  D=m2-m1;
  Dx=mid2-(m1*mid1) + (mid3*m2) - mid4;
  Dy=(m1*(mid3*m2-mid4))-(m2*(mid1*m1-mid2));
  x=Dx/D;
  y=Dy/D;
  printf("%f %f",x,y);    
  return 0;
}
int main() {
 float a1,a2,a3,b1,b2,b3;      
 a1=4.0;
 b1=1.0;
 a2=-3.0;
 b2=7.0;
 a3=5.0;
 b3=-2.0;
 is_formCircle(a1,b1,a2,b2,a3,b3);      
 return 0;
}

为什么我的代码给出了错误的答案?

2 个答案:

答案 0 :(得分:4)

链接中给出的解决方案是一个“盲目”解决方案,即你知道方程式,繁荣解决它。

然而,如果您更深入地了解幕后背后的内容,您将能够:

  1. 编写更易读,可靠,灵活的代码。
  2. 轻松调试。
  3. 从等式2中减去等式1时会发生什么?你实际上试图找到直线的方程,描述与点1和点2等距的那些点。然后,你对第2点和第3点做同样的事情。最后,你找到这些点与线之间的交点,给你圆圈的中心。

    如何描述与点1和2等距的点的直线?你取两个中间的点,然后沿着与点1和2之间的方向垂直的方向前进。

    如果这不是绝对清楚的,请拿一张纸画一个例子:放点1,2和3,找到两条线并找到交点。

    现在您已经了解了所有内容,使用两个函数对代码进行整形,找到两个点之间的等距线,另一个用于计算两条线之间的交点......


    编辑完成后,代码看起来更好,但理解起来并不简单。我认为错误是当你解决两条线的交叉时,不要忘记你是在参数形式下:

    Dx = (mid4-mid2) - m2*(mid3-mid1);
    
    lambda=Dx/D;
    
    x = mid1 + lambda*m1;
    y = mid2 + lambda*1.0;
    

    使用Matlab以图形方式检查。

答案 1 :(得分:4)

我不得不说,如果您按照列出的链接,它将有助于保持变量名称相同。我们可以更好地理解算法,看到x1,y1,x2,y2,x3,y3而不是p1,p2,p3,p4,alpha和beta。实际上,我在您的算法中看不到与链接匹配的内容。我并不想像评论一样严厉(如果你担心将float切换为double,这对于typedef来说是一个非常好的例子),但是当你不必转换时,调试算法是最简单的变量名称。

我建议只使用他们为链接中的h和k提供的内容,即通过计算3x3矩阵的行列式来完成。你可以找到很多references

我将创建两个函数,如下所示:

float calculateH(float x1, float y1, float x2, float y2, float x3, float y3) {
    float numerator = (x2*x2+y2*y2)*y3 - (x3*x3+y3*y3)*y2 - 
                      ((x1*x1+y1*y1)*y3 - (x3*x3+y3*y3)*y1) +
                      (x1*x1+y1*y1)*y2 - (x2*x2+y2*y2)*y1;
    float denominator = (x2*y3-x3*y2) -
                        (x1*y3-x3*y1) +
                        (x1*y2-x2*y1);
    denominator *= 2;
    return numerator / denominator;
}
float calculateK(float x1, float y1, float x2, float y2, float x3, float y3) {
    float numerator = x2*(x3*x3+y3*y3) - x3*(x2*x2+y2*y2) -
                      (x1*(x3*x3+y3*y3) - x3*(x1*x1+y1*y1)) +
                      x1*(x2*x2+y2*y2) - x2*(x1*x1+y1*y1);
    float denominator = (x2*y3-x3*y2) -
                        (x1*y3-x3*y1) +
                        (x1*y2-x2*y1);
    denominator *= 2;
    return numerator / denominator;
}

然后你的is_formCircle就是:

float is_formCircle(float x1, float y1, float x2, float y2, float x3, float y3) {
    float h = calculateH(x1, y1, x2, y2, x3, y3);
    float k = calculateK(x1, y1, x2, y2, x3, y3);
    printf("x=%f  y=%f\n",h,k);
}

有很多方法可以对此进行优化,并且我有可能将任何决定因素计算错误,但它应该让你前进。