根据起点、终点、半径、优弧、劣弧、顺时针和逆时针等要求,线性方程解圆心(C语言)。
在求解过程当中,可能会求得两个圆心(一元二次方程解),这时候就需要判断是那个圆心,按照条件,总共也就以下4种情况:
话不多说,直接列代码
判断半径法求圆心参数的正确性:
/*
* 函数功能:判断半径法求圆心参数的正确性
* 函数类型:立即函数,调用后立即生效。
* 函数形参:
* double x1:圆弧当中的一点,通常为起点位置的X坐标
* double y1:圆弧当中的一点,通常为起点位置的Y坐标
* double x2:圆弧当中的一点,通常为终点位置的X坐标
* double y2:圆弧当中的一点,通常为终点位置的Y坐标
* double dRadius:圆弧半径
* 返 回 值:
* false:参数有问题
* true:参数没有问题
* 其他:
* 1.
* 2.
* 3.
*/
bool Data_Validation(double x1, double y1, double x2, double y2, double dRadius)
{
/* 1:变量定义 */
double dDistance = 0.0; //两点间距离
/* 2:变量赋值 */
dDistance = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
/* 3:结果判断 */
if (dDistance == 0.0) //距离为0
{
return false; //参数有问题:输入了相同的点
}
if ((2 * dRadius) >= dDistance) //判断两点间距离小于直径
{
return true;
}
else
{
return false; //参数有问题:两点间距离大于直径
}
}
通过直线上一点和斜率,求得容易X下对应的Y的坐标值:
/*
* 函数功能:通过直线上一点和斜率,求得容易X下对应的Y的坐标值。
* 函数类型:立即函数,调用后立即生效。
* 函数形参:
* double x:直线上的一点的X坐标(圆弧两点的中点坐标)
* double y:直线上的一点的Y坐标(圆弧两点的中点坐标)
* double k:直线斜率(垂直于圆弧上两点的直线斜率)
* double x0:直线上的一点的X坐标(圆心的X坐标)
* 返 回 值:
* 其他:
* 1.
* 2.
* 3.
*/
double Y_Coordinates(double x, double y, double k, double x0)
{
return k * x0 - k * x + y;
}
半径法通过线性方程求得圆心,并根据劣弧和优弧、顺时针和逆时针的要求返回正确圆心:
/*
* 函数功能:半径法通过线性方程求得圆心,并根据劣弧和优弧、顺时针和逆时针的要求返回正确圆心
* 函数类型:立即函数,调用后立即生效。
* 函数形参:
* float x1:圆弧当中的一点,通常为起点位置的X坐标
* float y1:圆弧当中的一点,通常为起点位置的Y坐标
* float x2:圆弧当中的一点,通常为终点位置的X坐标
* float y2:圆弧当中的一点,通常为终点位置的Y坐标
* double dRadius:圆弧半径(正数为劣弧,负数为优弧)
* short circleDir:0:顺时针圆弧。1:逆时针圆弧。
* float* center_x:满足条件的圆心的X坐标
* float* center_y:满足条件的圆心的Y坐标
* 返 回 值:
* 其他:
* 1.本函数暂时没有对参数进行判断,比如 circleDir 可能不是0或者1(本工程在上层调用函数进行了判断。)
* 2.也可以通过勾股定理求解
* 3.
*/
void Circle_Center(float x1, float y1, float x2, float y2, double dRadius, short circleDir, float* center_x, float* center_y)
{
/* 1:变量定义 */
double k = 0.0, k_verticle = 0.0; //圆弧上两点(起点和终点)线段的斜率 和 垂直于线段的斜率(圆心所在直线的斜率)
double mid_x = 0.0, mid_y = 0.0; //圆弧上两点(起点和终点)线段的中心位置坐标
double a = 1.0; //一元二次方程二次项系数(求解圆心坐标的一元二次方程)
double b = 1.0; //一元二次方程一次项系数(求解圆心坐标的一元二次方程)
double c = 1.0; //一元二次方程常数项系数(求解圆心坐标的一元二次方程)
double center_x1, center_y1, center_x2, center_y2;
if (y2 == y1) //斜率为零,说明圆弧上两点(起点和终点)在同一水平线上面,
{
center_x1 = ((double)x1 + x2) / 2.0; //圆心x坐标为X之间中点
center_x2 = ((double)x1 + x2) / 2.0; //圆心x坐标为X之间中点
center_y1 = y1 + sqrt(dRadius * dRadius - ((double)x1 - x2) * ((double)x1 - x2) / 4.0); //圆心y坐标
center_y2 = y2 - sqrt(dRadius * dRadius - ((double)x1 - x2) * ((double)x1 - x2) / 4.0); //圆心y坐标
}
else if (x2 == x1) //斜率无穷大,说明圆弧上两点(起点和终点)在同一垂直线上面,
{
center_x1 = x1 + sqrt(dRadius * dRadius - ((double)y1 - y2) * ((double)y1 - y2) / 4.0); //圆心x坐标
center_x2 = x2 - sqrt(dRadius * dRadius - ((double)y1 - y2) * ((double)y1 - y2) / 4.0); //圆心x坐标
center_y1 = ((double)y1 + y2) / 2.0; //圆心y坐标为Y之间中点
center_y2 = ((double)y1 + y2) / 2.0; //圆心y坐标为Y之间中点
}
else
{
k = (y2 - y1) / (x2 - x1); //圆弧上两点(起点和终点)线段斜率
k_verticle = -1.0 / k; //垂直于线段的斜率(圆心所在直线的斜率)
mid_x = ((double)x1 + x2) / 2.0; //线段中心坐标X
mid_y = ((double)y1 + y2) / 2.0; //线段中心坐标Y
a = 1.0 + k_verticle * k_verticle; //一元二次方程二次项系数(求解圆心坐标的一元二次方程)
b = -2 * mid_x - k_verticle * k_verticle * ((double)x1 + x2); //一元二次方程一次项系数(求解圆心坐标的一元二次方程)
c = mid_x * mid_x + k_verticle * k_verticle * ((double)x1 + x2) * ((double)x1 + x2) / 4.0 -
(dRadius * dRadius - ((mid_x - x1) * (mid_x - x1) + (mid_y - y1) * (mid_y - y1))); //一元二次方程常数项系数(求解圆心坐标的一元二次方程)
center_x1 = (-1.0 * b + sqrt(b * b - 4 * a * c)) / (2 * a); //求得坐标x(右上角)
center_x2 = (-1.0 * b - sqrt(b * b - 4 * a * c)) / (2 * a); //求得坐标x(左下角)
center_y1 = Y_Coordinates(mid_x, mid_y, k_verticle, center_x1); //求得坐标y(右上角)
center_y2 = Y_Coordinates(mid_x, mid_y, k_verticle, center_x2); //求得坐标y(左下角)
}
//可以看出圆心坐标O1:(center_x1,center_y1)一定在圆心坐标O2:(center_x2,center_y2)右侧。
//返回圆心O1:如果起点在终点上面:顺时针为大圆弧,逆时针为小圆弧。如果起点在终点下面:顺时针为小圆弧,逆时针为大圆弧。
if (((y1 >= y2) && (((circleDir == 0) && (dRadius < 0)) || ((circleDir == 1) && (dRadius > 0)))) ||
((y1 < y2) && (((circleDir == 0) && (dRadius > 0)) || ((circleDir == 1) && (dRadius < 0)))))
{
*center_x = center_x1; //(右上角)
*center_y = center_y1; //(右上角)
}
//返回圆心O2:如果起点在终点上面:顺时针为小圆弧,逆时针为大圆弧。如果起点在终点下面:顺时针为大圆弧,逆时针为小圆弧。
else if(((y1 >= y2) && (((circleDir == 0) && (dRadius > 0)) || ((circleDir == 1) && (dRadius < 0)))) ||
((y1 < y2) && (((circleDir == 0) && (dRadius < 0)) || ((circleDir == 1) && (dRadius > 0)))))
{
*center_x = center_x2; //(左下角)
*center_y = center_y2; //(左下角)
}
else
{
//如果 circleDir 可能不是0或者1,应该 return 返回?
}
}