DXF文件的LWPOLYLINE类型记录的圆弧数据为凸度和两端点坐标,而实际应用中存储的圆弧多为三点圆弧,所以本文通过圆弧凸度和两端点坐标计算出圆弧中点坐标,从而可以用三点确定圆弧。
/*
*功能:xy圆弧的两个端点和凸度计算这段圆弧的中点坐标
* 1.计算出圆心坐标,半径
* 2.通过圆心与端点坐标分别计算出开始点的弧度和结束点的弧度
* 3.通过开始点和结束点弧度计算中点弧度
* 4.中点弧度与圆心、半径计算圆弧中点坐标
*/
#include <stdio.h>
#include <math.h>
#ifndef PI
#define PI 3.1415926535898
#endif
typedef struct
{
double x;
double y;
double z;
}COORD_T;
COORD_T calculateArcCenter(double startX, double startY, double endX, double endY, double bulge)
{
COORD_T centerPoint = { 0 };
double tangentRatio;
if (bulge > 0.000000001 || bulge < -0.000000001)
{
tangentRatio = 0.5 * (1 / bulge - bulge);
centerPoint.x = 0.5 * ((startX + endX) - tangentRatio * (endY - startY));
centerPoint.y = 0.5 * ((startY + endY) + tangentRatio * (endX - startX));
centerPoint.z = 0.0; // 平面圆弧计算,z坐标设为0
}
return centerPoint;
}
/*
*功能:xy圆弧的两个端点和凸度计算这段圆弧的中点坐标
* 1.计算出圆心坐标,半径
* 2.通过圆心与端点坐标分别计算出开始点的弧度和结束点的弧度
* 3.通过开始点和结束点弧度计算中点弧度
* 4.中点弧度与圆心、半径计算圆弧中点坐标
*/
COORD_T calculateArcMidPoint(double startX, double startY, double endX, double endY, double bulge)
{
COORD_T midPoint = { 0 }, centerPoint;
double startAngle, endAngle, midAngle;//以圆心为原点(0,0),startAngle开始角度,endAngle结束点角度,midAngle圆弧中点角度
double arcRadius, chordLength, includedAngle;
const double EPSILON = 0.000000001;
if (bulge > EPSILON || bulge < -EPSILON)
{
centerPoint = calculateArcCenter(startX, startY, endX, endY, bulge);
startAngle = atan2((startY - centerPoint.y), (startX - centerPoint.x));//(-π,π];
endAngle = atan2((endY - centerPoint.y), (endX - centerPoint.x)); //(-π,π];
//计算顶点角度
includedAngle = atan(bulge) * 4; //弧度,atan(dBulge)*4 的范围是 (-π/2, π/2)*4;dBulge为0时dRadian为0
/*计算半径*/
chordLength = sqrt((startX - endX) * (startX - endX) +
(startY - endY) * (startY - endY));
arcRadius = (chordLength / 2) / sin(includedAngle / 2);
if (arcRadius < 0)
arcRadius = -arcRadius;
if (startAngle < 0)
startAngle += 2 * PI;
if (endAngle < 0)
endAngle += 2 * PI;
if (bulge < 0)
{//点1到点2顺时针转
if (startAngle < endAngle)
startAngle += 2 * PI;
}
else
{//点1到点2逆时针转
if (endAngle < startAngle)
{
//穿过第四、第一象限
endAngle += 2 * PI;
}
}
midAngle = (startAngle + endAngle) / 2;
if (midAngle > PI)
midAngle -= 2 * PI;
midPoint.x = centerPoint.x + arcRadius * cos(midAngle);
midPoint.y = centerPoint.y + arcRadius * sin(midAngle);
midPoint.z = 0.0; // 平面圆弧计算,z坐标设为0
}
else
{
midPoint.x = (startX + endX) / 2;
midPoint.y = (startY + endY) / 2;
midPoint.z = 0.0;
}
return midPoint;
}
int main()
{
// 测试用例2:180度圆弧
{
double startX = -5.0, startY = 0.0; // 起点 (-5,0)
double endX = 5.0, endY = 0.0; // 终点 (5,0)
double bulge = 1.0; // bulge=1.0 表示180度圆弧
COORD_T midPoint = calculateArcMidPoint(startX, startY, endX, endY, bulge);
printf("Test Case 2 (180° Arc):\n");
printf("Start Point: (%.3f, %.3f)\n", startX, startY);
printf("End Point: (%.3f, %.3f)\n", endX, endY);
printf("Bulge: %.3f\n", bulge);
printf("Mid Point: (%.3f, %.3f, %.3f)\n\n", midPoint.x, midPoint.y, midPoint.z);
}
// 测试用例3:直线(bulge = 0)
{
double startX = 0.0, startY = 0.0; // 起点 (0,0)
double endX = 10.0, endY = 10.0; // 终点 (10,10)
double bulge = 0.0; // bulge=0 表示直线
COORD_T midPoint = calculateArcMidPoint(startX, startY, endX, endY, bulge);
printf("Test Case 3 (Straight Line):\n");
printf("Start Point: (%.3f, %.3f)\n", startX, startY);
printf("End Point: (%.3f, %.3f)\n", endX, endY);
printf("Bulge: %.3f\n", bulge);
printf("Mid Point: (%.3f, %.3f, %.3f)\n\n", midPoint.x, midPoint.y, midPoint.z);
}
// 测试用例4:负bulge值(顺时针圆弧)
{
double startX = 0.0, startY = 0.0; // 起点 (0,0)
double endX = 10.0, endY = 0.0; // 终点 (10,0)
double bulge = -1.0; // 负bulge表示顺时针方向
COORD_T midPoint = calculateArcMidPoint(startX, startY, endX, endY, bulge);
printf("Test Case 4 (Clockwise Arc):\n");
printf("Start Point: (%.3f, %.3f)\n", startX, startY);
printf("End Point: (%.3f, %.3f)\n", endX, endY);
printf("Bulge: %.3f\n", bulge);
printf("Mid Point: (%.3f, %.3f, %.3f)\n", midPoint.x, midPoint.y, midPoint.z);
}
return 0;
}