多段线里的圆弧段:它的中点计算思路是
1)获得NumberOfSegments顶点数量
2)然后通过(polyline.GetSegmentType(i) == SegmentType.Arc判断是否为圆弧段
3)是的话,通过拿到它的CircularArc2d对象
4)通过CircularArc2d对象计算它的中点
cs
for (int i = 0; i < polyline.NumberOfSegments; i++)
{
if (polyline.GetSegmentType(i) == SegmentType.Arc)
{
Point2d arcStartPt = polyline.GetPoint2dAt(i);
Point2d arcEndPt = polyline.GetPoint2dAt(i + 1);
CircularArc2d circArc = polyline.GetArcSegmentAt(i) as CircularArc2d;
if (circArc == null)
{
ed.WriteMessage($"\n第{i+1}段圆弧转换失败!");
continue;
}
// 调用最终修正版函数
Point2d midPoint = CalculatePolylineArcMidpoint(circArc, arcStartPt, arcEndPt);
ed.WriteMessage($"\n=== 第{i+1}段圆弧 ===");
ed.WriteMessage($"\n起点: ({arcStartPt.X:F2},{arcStartPt.Y:F2})");
ed.WriteMessage($"\n终点: ({arcEndPt.X:F2},{arcEndPt.Y:F2})");
ed.WriteMessage($"\n中点: ({midPoint.X:F2},{midPoint.Y:F2})");
midPoints.Add(midPoint);
}
}
通过CircularArc2d对象计算它的中点,看似可以通过圆弧的几个参数进行计算,但是它有个大坑。就是拿到的起点角度一直都是0. 这也说明这是一个局部坐标系。
使用豆包进行分析,给出函数如下:
cs
/// <summary>
/// 最终修正版:适配多段线圆弧段(起点切线为局部0角度)的中点计算
/// </summary>
/// <param name="circArc">CircularArc2d对象</param>
/// <param name="arcStartPt">圆弧段起点(全局)</param>
/// <param name="arcEndPt">圆弧段终点(全局)</param>
/// <returns>正确的圆弧中点(全局坐标)</returns>
private Point2d CalculatePolylineArcMidpoint(CircularArc2d circArc, Point2d arcStartPt, Point2d arcEndPt)
{
// 步骤1:计算圆弧的弦向量(起点→终点)
Vector2d chordVec = arcEndPt - arcStartPt;
// 步骤2:计算起点处的法线向量(指向圆心)并单位化
Vector2d normalVec = circArc.Center - arcStartPt;
normalVec = normalVec.GetNormal();
// 步骤3:计算起点切线方向(局部0角度)
double tangentAngle = normalVec.Angle + Math.PI / 2; // 逆时针圆弧:法线逆时针转90°=切线
if (circArc.IsClockWise)
{
tangentAngle = normalVec.Angle - Math.PI / 2; // 顺时针圆弧:法线顺时针转90°=切线
}
// 步骤4:转换局部角度到全局角度
double globalStartAngle = tangentAngle + circArc.StartAngle;
double globalEndAngle = tangentAngle + circArc.EndAngle;
// 步骤5:处理角度跨边界
if (circArc.IsClockWise && globalStartAngle < globalEndAngle)
{
globalStartAngle += 2 * Math.PI;
}
else if (!circArc.IsClockWise && globalEndAngle < globalStartAngle)
{
globalEndAngle += 2 * Math.PI;
}
// 步骤6:计算中点角度(归一化)
double midAngle = (globalStartAngle + globalEndAngle) / 2;
midAngle = midAngle % (2 * Math.PI);
if (midAngle < 0) midAngle += 2 * Math.PI;
// 步骤7:计算中点坐标(X/Y均正确)
double midX = circArc.Center.X + circArc.Radius * Math.Cos(midAngle);
double midY = circArc.Center.Y + circArc.Radius * Math.Sin(midAngle);
return new Point2d(midX, midY);
}
部分场景有计算错误的地方,实在没办法,还是找了cursor进行算法分析,一步到位就解决了。贴出正解:
cs
/// <summary>
/// 最终修正版:适配多段线圆弧段(起点切线为局部0角度)的中点计算
/// </summary>
/// <param name="circArc">CircularArc2d对象</param>
/// <param name="arcStartPt">圆弧段起点(全局)</param>
/// <param name="arcEndPt">圆弧段终点(全局)</param>
/// <returns>正确的圆弧中点(全局坐标)</returns>
static public Point2d CalculatePolylineArcMidpoint(CircularArc2d circArc, Point2d arcStartPt, Point2d arcEndPt)
{
// 问题分析:对于多段线的圆弧段,CircularArc2d.StartAngle 始终是0度(相对于局部坐标系),
// 因此不能直接使用 StartAngle 和 EndAngle 来计算全局角度。
// 正确的做法:直接通过起点和终点的全局坐标来计算它们在全局坐标系下的角度。
// 步骤1:计算起点和终点相对于圆心的向量
Vector2d startVec = arcStartPt - circArc.Center;
Vector2d endVec = arcEndPt - circArc.Center;
// 步骤2:计算起点和终点的全局角度(相对于圆心)
double globalStartAngle = startVec.Angle;
double globalEndAngle = endVec.Angle;
// 步骤3:处理角度跨边界(确保角度区间正确)
// 对于逆时针圆弧,起点角度应该小于终点角度
// 对于顺时针圆弧,起点角度应该大于终点角度
if (circArc.IsClockWise)
{
// 顺时针圆弧:起点角度 > 终点角度
if (globalStartAngle < globalEndAngle)
{
globalStartAngle += 2 * Math.PI;
}
}
else
{
// 逆时针圆弧:起点角度 < 终点角度
if (globalEndAngle < globalStartAngle)
{
globalEndAngle += 2 * Math.PI;
}
}
// 步骤4:计算中点角度(归一化)
double midAngle = (globalStartAngle + globalEndAngle) / 2;
// 归一化角度到 [0, 2π) 范围
midAngle = midAngle % (2 * Math.PI);
if (midAngle < 0) midAngle += 2 * Math.PI;
// 步骤5:计算中点坐标(使用全局坐标系)
double midX = circArc.Center.X + circArc.Radius * Math.Cos(midAngle);
double midY = circArc.Center.Y + circArc.Radius * Math.Sin(midAngle);
return new Point2d(midX, midY);
}