C++练习:已知三点,求过这三点的圆

    在论坛里看到了这个问题,基本上都是平面几何里的问题。把点,线做成了结构。

  

//  3point.cpp : Defines the entry point for the console application.
// 已知三点 求过这三点的圆心坐标和圆的半径
//  xmxoxo 2006.11.8 at XiaMen

#include 
" stdafx.h "
#include 
" stdlib.h "
#include 
" math.h "
#include 
" stdio.h "
#include 
" iostream.h "

// 常数
double   const  pai  =   3.1415926535897932384626 ;

// 坐标点结构
struct  point
{
    
double  x;     // 横坐标
     double  y;     // 纵坐标
};

// 直线方程结构
struct  line
{
    
double  k;     // 斜率
     double  b;     // 截距
};

// 判断两点是否相同
bool  samep(point p1,point p2)
{
    
if  ((p1.x == p2.x) && (p1.y == p2.y))
    {
        
return   1 ;
    }
    
else
    {
        
return   0 ;
    }
}

// 求两点距离
double  dist(point p1,point p2)
{
    
double  ret = 0 ;
    ret
= sqrt((p1.x - p2.x) * (p1.x - p2.x) +  (p1.y - p2.y) * (p1.y - p2.y));
    
return  ret;
}


/*
已知两点,求连线中点坐标
---------------------------------
两点(x1,y1),(x2,y2)的连线中点坐标
((x1+x2)/2,(y1+y2)/2)
*/
point midpoint(point p1, point p2)
{
    point ret;
    ret.x 
=  (p1.x  +  p2.x ) / 2 ;
    ret.y 
=  (p1.y  +  p2.y ) / 2 ;
    
return  ret;
}

/*
已知两点,求连线方程
-------------------------------------
两点(x1,y1),(x2,y2)的连线方程表示成Y=ax+b
a=(y1-y2)/(x1-x2)

b= y2 - x2*a
或者
b= y1- x1*a
-------------------------------------

*/
line line2p(point p1,point p2)
{
    line ret;
    
if  ((p1.x == p2.x)  &&  (p1.y  =  p2.y))
    {
        ret.k 
=   0 ;
        ret.b 
=   0 ;
    }
    
else
    {
        ret.k 
=  (p1.y  -  p2.y) /  (p1.x  - p2.x);
        ret.b 
=  p1.y  -  p1.x  *  ret.k ;
    }
    
return  ret;
}


// 判断两直线是否相交

bool  iscross(line l1,line l2)
{
    
if  (l1.k == l2.k)
    {
        
return   0 ;
    }
    
else
    {
        
return   1 ;
    }
}

/*
已知两直线,求交点坐标
两条直线

y1=ax+b
y2=cx+d
求交点
a<>c时有交点(不平行)
y1=y2时
=> ax+b=cx+d
=> x=(d-b)/(a-c)

x1=x2 时
y=(ad-cb)/(a-c)

交点坐标是( (d-b)/(a-c),(ad-cb)/(a-c))
*/
point crosspoint(line l1,line l2)
{
    point ret;
    
if  ( ! iscross(l1,l2))
    {
        ret.x 
=   0 ;
        ret.y 
=   0 ;
    }
    
else
    {
        ret.x 
=  (l2.b - l1.b )  /  (l1.k  -  l2.k);
        ret.y 
=  (l1.k * l2.b - l2.k * l1.b) / (l1.k - l2.k);
    }
    
return  ret;
}

/*
求斜率为k的直线,转过n弧度后,且经过某一点的方程
*/
line linepoint(point p,
double  k, double  n)  // 过某点直线方程
{
    line ret;
    ret.k 
=  tan(atan(k) + n);
    ret.b 
=  p.y  -   ret.k  *  p.x ;
    
return  ret;
}

/*
-------------------------------------
直线Y=ax+b 与X轴夹角是
atan((-b)/a)
转90度只要加上90度(3.14/2)就可以了
---------------------------------
*/

point p1,p2,p3;
point m1,m2,m3;
line l1,l2,l3;
line lm1,lm2,lm3;
point circlep;
double  circler,dis2,dis3;

int  main( int  argc,  char *  argv[])
{

    printf(
" 几何问题图解 2006.11.8 Xmxoxo " );
    
while  ( 1 )
    {
        cout
<< " 请输入第1点坐标: " ;
        cin
>> p1.x >> p1.y;
        printf(
" 请输入第2点坐标: " );
        cin
>> p2.x >> p2.y;
        printf(
" 请输入第3点坐标: " );
        cin
>> p3.x >> p3.y;
        
        
if  (samep(p1,p2))
        {
            printf(
" 两点相同! " );
            
break ;
        }
        
// cout<<setprecision(10)<<setiosflags(ios::showpos);

        cout
<< " 第1点坐标是: ( " << p1.x  << " , "   << p1.y  << " ) " ;
        cout
<< " 第2点坐标是: ( " << p2.x  << " , "   << p2.y  << " ) " ;
        cout
<< " 第3点坐标是: ( " << p3.x  << " , "   << p3.y  << " ) " ;
        
        m1
= midpoint(p1,p2);
        m2
= midpoint(p2,p3);
        m3
= midpoint(p3,p1);

        cout
<< " p1,p2中点坐标是: ( " << m1.x  << " , "   << m1.y  << " ) " ;

        l1
= line2p(p1,p2);
        l2
= line2p(p2,p3);
        l3
= line2p(p3,p1);

        cout
<< " P1,P2连线方程是: Y=( " <<  ( float ) l1.k  << " )X+( "   <<  ( float ) l1.b  << " ) " ;
        cout
<< " P2,P3连线方程是: Y=( " <<  ( float ) l2.k  << " )X+( "   <<  ( float ) l2.b  << " ) " ;
        cout
<< " P3,P1连线方程是: Y=( " <<  ( float ) l3.k  << " )X+( "   <<  ( float ) l3.b  << " ) " ;
        
        lm1
= linepoint(m1,l1.k,pai / 2 );
        lm2
= linepoint(m2,l2.k,pai / 2 );
        lm3
= linepoint(m3,l3.k,pai / 2 );

        cout
<< " P1,P2连线的垂线方程是: Y=( "   <<  ( float ) lm1.k  <<   " )X+( " <<  ( float ) lm1.b  <<   " ) " ;
        cout
<< " P2,P3连线的垂线方程是: Y=( "   <<  ( float ) lm2.k  <<   " )X+( " <<  ( float ) lm2.b  <<   " ) " ;
        cout
<< " P3,P1连线的垂线方程是: Y=( "   <<  ( float ) lm3.k  <<   " )X+( " <<  ( float ) lm3.b  <<   " ) " ;
        
        circlep
= crosspoint(lm1,lm2);
        circler
= dist(circlep,p1);
        dis2
= dist(circlep,p2);
        dis3
= dist(circlep,p3);

        cout
<<   " 圆心坐标是: ( "   <<  circlep.x  <<   " , "   <<  circlep.y  <<   " ) " ;
        cout
<<   " 半径是: ( "   <<  circler  <<   " ) " ;
        cout
<<   " 到另两点的距离是: ( "   <<  dis2  <<   " , "   <<  dis3  <<   " ) " ;
        
// break;
    }

    
return   0 ;
}

 运行情况如下:

几何问题图解 2006.11.8 Xmxoxo

请输入第1点坐标:158.25 352.25
请输入第2点坐标:15.88 36.58
请输入第3点坐标:78.06 105.43
第1点坐标是: (158.25,352.25)
第2点坐标是: (15.88,36.58)
第3点坐标是: (78.06,105.43)
p1,p2中点坐标是: (87.065,194.415)
P1,P2连线方程是: Y=(2.21725)X+(1.37006)
P2,P3连线方程是: Y=(1.10727)X+(18.9966)
P3,P1连线方程是: Y=(3.07794)X+(-134.834)
P1,P2连线的垂线方程是: Y=(-0.451009)X+(233.682)
P2,P3连线的垂线方程是: Y=(-0.903123)X+(113.425)
P3,P1连线的垂线方程是: Y=(-0.324893)X+(267.228)
圆心坐标是: (-265.989,353.646)
半径是: (424.242)
到另两点的距离是: (424.242,424.242)

这里只解出了三角形的外接圆,如果要得到内切圆,也很简单,只要计算经过任意两个顶点的角平分线,

再计算这两条角平分线的交点就可以了。另外还可以推算出三角形的面积,周长等,都只是公式的应用,写

成表达式就可以了。

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是用 C++ 实现已知三点的中心坐标和半径的代码,其中使用了高斯消元法求解线性方程组: ```c++ #include <iostream> #include <cmath> using namespace std; const double eps = 1e-8; struct Point { double x, y; }; Point p1, p2, p3; double A[3][4]; // 线性方程组的系数矩阵 double X[3]; // 线性方程组的解向量 // 高斯消元法求解线性方程组 bool Gauss() { for (int i = 0; i < 3; i++) { // 找到一行中绝对值最大的元素所在的行 int r = i; for (int j = i + 1; j < 3; j++) { if (fabs(A[j][i]) > fabs(A[r][i])) { r = j; } } if (fabs(A[r][i]) < eps) { // 系数矩阵中该列所有元素都是 0,无唯一解 return false; } if (r != i) { // 将第 r 行与第 i 行交换 for (int j = i; j <= 3; j++) { swap(A[i][j], A[r][j]); } } // 消元 for (int j = i + 1; j < 3; j++) { double f = A[j][i] / A[i][i]; for (int k = i + 1; k <= 3; k++) { A[j][k] -= f * A[i][k]; } } } // 回带求解 for (int i = 2; i >= 0; i--) { for (int j = i + 1; j < 3; j++) { A[i][3] -= A[i][j] * X[j]; } if (fabs(A[i][i]) < eps) { // 系数矩阵中该列所有元素都是 0,无唯一解 return false; } X[i] = A[i][3] / A[i][i]; } return true; } int main() { cout << "请输入三个点的坐标:" << endl; cin >> p1.x >> p1.y >> p2.x >> p2.y >> p3.x >> p3.y; // 构造系数矩阵 A[0][0] = 2 * (p1.x - p2.x); A[0][1] = 2 * (p1.y - p2.y); A[0][2] = p2.x * p2.x - p1.x * p1.x + p2.y * p2.y - p1.y * p1.y; A[0][3] = p1.x * p1.x - 2 * p1.x * X[0] + X[0] * X[0] + p1.y * p1.y - 2 * p1.y * X[1] + X[1] * X[1]; A[1][0] = 2 * (p2.x - p3.x); A[1][1] = 2 * (p2.y - p3.y); A[1][2] = p3.x * p3.x - p2.x * p2.x + p3.y * p3.y - p2.y * p2.y; A[1][3] = p2.x * p2.x - 2 * p2.x * X[0] + X[0] * X[0] + p2.y * p2.y - 2 * p2.y * X[1] + X[1] * X[1]; A[2][0] = 2 * (p3.x - p1.x); A[2][1] = 2 * (p3.y - p1.y); A[2][2] = p1.x * p1.x - p3.x * p3.x + p1.y * p1.y - p3.y * p3.y; A[2][3] = p3.x * p3.x - 2 * p3.x * X[0] + X[0] * X[0] + p3.y * p3.y - 2 * p3.y * X[1] + X[1] * X[1]; if (Gauss()) { double x0 = X[0], y0 = X[1], r = sqrt(X[2] + x0 * x0 + y0 * y0); cout << "的中心坐标为:" << "(" << x0 << ", " << y0 << ")" << endl; cout << "的半径为:" << r << endl; } else { cout << "无法确定的中心坐标和半径" << endl; } return 0; } ``` 在程序中,我们首先输入三个点的坐标,并构造出线性方程组的系数矩阵 $A$ 和常数向量 $B$。然后使用高斯消元法求解线性方程组 $AX=B$,得到解向量 $X$。最后根据解向量 $X$ 计算的中心坐标和半径,并输出结果。需要注意的是,由于浮点数计算存在误差,我们需要定义一个很小的精度 eps,用于判断浮点数是否为 0。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值