AutoCAD面域转多段线
问题
AutoCAD2014版本没有面域转为多段线的直接方法,需要自己实现。
解决
主要逻辑,通过Brep获取到面域的边界线,再根据边界线重新生成多段线,把曲线(Arc)转为多段线时bulge的计算方法。
这个算法有问题,在边界线的方向不一致时(一部分顺时针绘制,一部分逆时针绘制),计算的边界不对
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/// <summary>
/// 面域转为多段线
/// </summary>
/// <param name="region"></param>
/// <returns></returns>
public static Polyline ToPolylines(this Region region)
{
Polyline pl = new Polyline();
var brep = new Brep(region);
var edges = brep.Edges.ToList();
var list = new List<Curve>();
//获取边界线
foreach (var edge in edges)
{
var eCurve = (ExternalCurve3d)edge.Curve;
if (eCurve.IsCircularArc || eCurve.IsLineSegment)
{
var curve = Polyline.CreateFromGeCurve(eCurve.NativeCurve);
list.Add(curve);
//var angle = arc.EndAngle - arc.StartAngle;
//if (angle < 0)
// angle += Math.PI * 2.0;
//double bulge = Math.Tan(angle / 4.0);
}
}
//获取到的边界可能不是第二条线的起点对应第一条线的终点,而是第一条线的起点对应第二条线的终点,线的顺序是反向,
//这里重新排序,保证边界线是顺序相接的
if (list.Count > 1 && list[0].StartPoint == list[1].EndPoint)
{
list.Reverse();
}
//重新绘制多段线
foreach (var curve in list)
{
if (curve is Line)
{
if (pl.NumberOfVertices == 0)
{
pl.AddVertexAt(pl.NumberOfVertices, curve.StartPoint.ToPoint2d(), 0, 0, 0);
}
pl.AddVertexAt(pl.NumberOfVertices, curve.EndPoint.ToPoint2d(), 0, 0, 0);
}
else if (curve is Arc)
{
var arc = curve as Arc;
var diffAngle = arc.EndAngle - arc.StartAngle;
double bulge;
if (diffAngle < 0)
{
diffAngle += 2 * Math.PI;
bulge = Math.Tan(diffAngle / 4) * -1;
}
else
{
bulge = Math.Tan(diffAngle / 4);
}
//弧线要根据正向或反向弧计算bulge
bulge *= arc.Normal.Z;
if (bulge != 0)
{
if (pl.NumberOfVertices != 0)
{
pl.RemoveVertexAt(pl.NumberOfVertices - 1);
}
pl.AddVertexAt(pl.NumberOfVertices, curve.StartPoint.ToPoint2d(), bulge, 0, 0);
}
pl.AddVertexAt(pl.NumberOfVertices, curve.EndPoint.ToPoint2d(), 0, 0, 0);
}
}
return pl;
}
修正后的算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/// <summary>
/// 面域转为多段线
/// </summary>
/// <param name="region"></param>
/// <returns></returns>
public static Polyline ToPolyline(this Region region)
{
Polyline pl = new Polyline();
var brep = new Brep(region);
var edges = brep.Edges.ToList();
var list = new List<PolylinePoint>();
var curEdge = edges[0];
Point3d? endPoint = curEdge.Curve.StartPoint;
//获取边界线点
do
{
Point3d? startPoint = null;
curEdge = edges.FirstOrDefault(i => endPoint == i.Curve.StartPoint);
//可能出现线段首尾相反的情况,这里做一个标记,如果首尾相反,需要把线段反向,如果是直线可以直接替换起始点,曲线还需要修改法向量相反。
var isReverse = 1;
if (curEdge != null)
{
endPoint = curEdge.Curve.EndPoint;
startPoint = curEdge.Curve.StartPoint;
}
else
{
curEdge = edges.FirstOrDefault(i => i != curEdge && endPoint == i.Curve.EndPoint);
endPoint = curEdge?.Curve.StartPoint;
startPoint = curEdge?.Curve.EndPoint;
isReverse = -1;
}
if (curEdge == null)
{
break;
}
//每次查找到之后剔除边界,否则查找到最后一条后又循环第一条
edges.Remove(curEdge);
double bulge;
var eCurve = (ExternalCurve3d)curEdge.Curve;
//曲线需要计算角度
if (eCurve.IsCircularArc)
{
var arc = Arc.CreateFromGeCurve(eCurve.NativeCurve) as Arc;
bulge = GetBulge(arc) * isReverse;
}
else
{
bulge = 0;
}
if (bulge != 0 || list.Count == 0)
{
if (list.Count != 0)
{
list.RemoveAt(list.Count - 1);
}
list.Add(new PolylinePoint { Point2d = startPoint.Value.ToPoint2d(), Bulge = bulge });
}
list.Add(new PolylinePoint { Point2d = endPoint.Value.ToPoint2d(), Bulge = 0 });
} while (true);
//重新绘制多段线
foreach (var polylinePoint in list)
{
pl.AddVertexAt(pl.NumberOfVertices, polylinePoint.Point2d, polylinePoint.Bulge, 0, 0);
}
pl.Closed = true;
return pl;
}
/// <summary>
/// 获取角度
/// </summary>
/// <param name="arc"></param>
/// <returns></returns>
public static double GetBulge(this Arc arc)
{
var diffAngle = arc.EndAngle - arc.StartAngle;
double bulge;
if (diffAngle < 0)
{
diffAngle += 2 * Math.PI;
bulge = Math.Tan(diffAngle / 4) * -1;
}
else
{
bulge = Math.Tan(diffAngle / 4);
}
//弧线要根据正向或反向弧计算bulge
bulge *= arc.Normal.Z;
return bulge;
}
参考资料
本文会经常更新,请阅读原文: https://dashenxian.github.io/post/AutoCAD%E9%9D%A2%E5%9F%9F%E8%BD%AC%E5%A4%9A%E6%AE%B5%E7%BA%BF ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 小神仙 (包含链接: https://dashenxian.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 (125880321@qq.com) 。