- 积分
- 1412
- 明经币
- 个
- 注册时间
- 2023-2-2
- 在线时间
- 小时
- 威望
-
- 金钱
- 个
- 贡献
-
- 激情
-
|
本帖最后由 箭头_Row 于 2024-8-8 23:29 编辑
功能介紹:優化多段線中重複點
優化方向:感覺首尾那段單獨弄出來的就為了做索引號好笨的方法,想考慮用其它方法替代。
- namespace ArrowTools;
- public class P_PolylineTest
- {
- [CommandMethod("P`")]
- public void P_Polyline()
- {
- var p1 = new Point2d(5, 0);
- var p2 = new Point2d(10, 0);
- var p3 = new Point2d(15, 0);
- var bu1 = PointEx.GetArcBulge(p1, p2, p3);
- Env.Print(bu1);
- p3 = new Point2d(0, 0);
- var bu2 = p1.GetArcBulge(p2, p3);
- // 備註:此處如果形參點順序不同剛輸出結果不同。
- Env.Print(bu2);
- Env.Print(MathEx.ConvertRadToDeg(bu2));
- }
- [CommandMethod("P1")]
- public void P_Polyline_02()
- {
- using DBTrans tr = new();
- var ents = Env.Editor.SSGet()?.Value?.GetEntities<Polyline>();
- if (ents == null)
- return;
- foreach (var pl in ents)
- {
- Env.Printl($"顶点个数:{pl.NumberOfVertices}");
- var deleteNum = SimplifyPolylineDemo(pl);
- Env.Printl($"优化点个数:{deleteNum}");
- }
- }
- [CommandMethod("P3")]
- public void P_Polyline_03()
- {
- using DBTrans tr = new();
- var ents = Env.Editor.SSGet()?.Value?.GetEntities<Polyline>();
- if (ents == null)
- return;
- foreach (var pl in ents)
- {
- Env.Printl($"顶点个数:{pl.NumberOfVertices}");
- #if Debug
- for (int i = pl.NumberOfVertices - 1; i >= 0; i--)
- {
- var type = pl.GetSegmentType(i);
- Env.Printl(type.GetType().Name + ":" + type.ToString());
- }
- #endif
- #if true
- var deleteNum_Coincident = SimplifyPolyline_Coincident(pl);
- Env.Printl($"优化点个数_Coincident: {deleteNum_Coincident} ");
- #endif
- #if true
- var deleteNum_Line = SimplifyPolyline_Line(pl);
- Env.Printl($"优化点个数_Line: {deleteNum_Line}");
- #endif
- #if true
- var deleteNum_Arc = SimplifyPolyline_Arc(pl);
- Env.Printl($"优化点个数_Arc: {deleteNum_Arc}");
- #endif
- }
- }
- [CommandMethod("P5")]
- public void P_Polyline_05()
- {
- using DBTrans tr = new();
- var ents = Env.Editor.SSGet()?.Value?.GetEntities<Polyline>();
- if (ents == null)
- return;
- foreach (var pl in ents)
- {
- Env.Printl($"顶点个数:{pl.NumberOfVertices}");
- for (var i = pl.NumberOfVertices - 1; i >= 0; i--)
- {
- var type = pl.GetSegmentType(i);
- if (type == SegmentType.Arc)
- Env.Printl(pl.GetBulgeAt(i));
- }
- }
- }
- [CommandMethod("P7")]
- public void P_Polyline_07()
- {
- using DBTrans tr = new();
- var ents = Env.Editor.SSGet()?.Value?.GetEntities<Polyline>();
- if (ents == null)
- return;
- foreach (var pl in ents)
- {
- Env.Printl($"顶点个数:{pl.NumberOfVertices}");
- var deleteNum = SimplifyPolyline(pl);
- Env.Printl($"优化端点个数: {deleteNum}");
- }
- }
- /// <summary>
- /// 優化多段線中重複點:清理多余端點
- /// </summary>
- /// <param name="pl">多段線</param>
- /// <param name="tol">容差值</param>
- /// <returns>清理的端點數量</returns>
- private static int SimplifyPolyline(Polyline pl, double tol = 1e-6)
- {
- if (pl.NumberOfVertices < 3)
- return 0;
- int num = pl.NumberOfVertices;
- SimplifyPolyline_Coincident(pl);
- SimplifyPolyline_Line(pl, tol);
- SimplifyPolyline_Arc(pl, tol);
- return num - pl.NumberOfVertices;
- }
- /// <summary>
- /// 優化多段線中重複點:清理相同點的端點
- /// </summary>
- /// <param name="pl">多段線</param>
- /// <returns>清理的端點數量</returns>
- private static int SimplifyPolyline_Coincident(Polyline pl, double tol = 1e-6)
- {
- if (pl.NumberOfVertices < 3)
- return 0;
- int num = pl.NumberOfVertices;
- using (pl.ForWrite())
- {
- for (var i = pl.NumberOfVertices - 1; i >= 0; i--)
- {
- if (pl.NumberOfVertices < 3)
- break;
- // 優化多段線:頂點去重
- var type = pl.GetSegmentType(i);
- if (type == SegmentType.Coincident)
- pl.RemoveVertexAt(i);
- }
- }
- return num - pl.NumberOfVertices;
- }
- /// <summary>
- /// 優化多段線中重複點:清理共線的多余端點
- /// </summary>
- /// <param name="pl">多段線</param>
- /// <param name="tol">容差值</param>
- /// <returns>清理的端點數量</returns>
- private static int SimplifyPolyline_Line(Polyline pl, double tol = 1e-6)
- {
- if (pl.NumberOfVertices < 3)
- return 0;
- int num = pl.NumberOfVertices;
- using (pl.ForWrite())
- {
- var p1 = Point2d.Origin;
- var p2 = Point2d.Origin;
- var p3 = Point2d.Origin;
- double bu = default;
- for (var i = pl.NumberOfVertices - 1; i >= 2; i--)
- {
- if (pl.NumberOfVertices < 3)
- break;
- // 優化多段線:頂點去重,非直線跳過
- var type01 = pl.GetSegmentType(i);
- if (i != pl.NumberOfVertices - 1)
- if (type01 != SegmentType.Line)
- continue;
- var type02 = pl.GetSegmentType(i - 1);
- if (type02 != SegmentType.Line)
- continue;
- // 獲取相鄰三点
- p1 = pl.GetPoint2dAt(i);
- p2 = pl.GetPoint2dAt(i - 1);
- p3 = pl.GetPoint2dAt(i - 2);
- // 優化第1點至 第2點、第3點 向量.Normal相等時
- bu = p1.GetArcBulge(p2, p3, tol);
- if (bu == 0)
- pl.RemoveVertexAt(index: i - 1); // 移除第2点
- }
- // 判斷首尾如果閉合的部份
- if (pl.Closed && pl.NumberOfVertices > 2)
- {
- // 從結束-1點往前比對
- p1 = pl.GetPoint2dAt(pl.NumberOfVertices - 2);
- p2 = pl.GetPoint2dAt(pl.NumberOfVertices - 1);
- p3 = pl.GetPoint2dAt(0);
- bu = p1.GetArcBulge(p2, p3, tol);
- if (bu == 0)
- pl.RemoveVertexAt(index: pl.NumberOfVertices - 1); // 移除第2点
- // 從起始+1點往后比對
- p1 = pl.GetPoint2dAt(1);
- p2 = pl.GetPoint2dAt(0);
- p3 = pl.GetPoint2dAt(pl.NumberOfVertices - 1);
- bu = p1.GetArcBulge(p2, p3, tol);
- if (bu == 0)
- pl.RemoveVertexAt(index: 0); // 移除第2点
- }
- }
- return num - pl.NumberOfVertices;
- }
- /// <summary>
- /// 優化多段線中重複點:清理共圓弧的多余端點
- /// </summary>
- /// <param name="pl">多段線</param>
- /// <param name="tol">容差值</param>
- /// <returns>清理的端點數量</returns>
- // AutoCAD 中凸度(bulge)的概念:
- // https://www.cnblogs.com/BensonLaur/p/16189673.html
- private static int SimplifyPolyline_Arc(Polyline pl, double tol = 1e-6)
- {
- if (pl.NumberOfVertices < 3)
- return 0;
- int num = pl.NumberOfVertices;
- using (pl.ForWrite())
- {
- double bulge = default;
- double bulge02 = default;
- double angle = default;
- double angle02 = default;
- double radius = default;
- double radius02 = default;
- var p1 = Point2d.Origin;
- var p2 = Point2d.Origin;
- var p3 = Point2d.Origin;
- var center = Point2d.Origin;
- var center02 = Point2d.Origin;
- double b = default;
- double x = default;
- double y = default;
- for (var i = pl.NumberOfVertices - 1; i >= 2; i--)
- {
- if (pl.NumberOfVertices < 3)
- break;
- // 優化多段線:頂點去重,非Arc跳過
- var type01 = pl.GetSegmentType(i);
- if (i != pl.NumberOfVertices - 1)
- if (type01 != SegmentType.Arc)
- continue;
- var type02 = pl.GetSegmentType(i - 1);
- if (type02 != SegmentType.Arc)
- continue;
- // 獲取相鄰三点
- p1 = pl.GetPoint2dAt(i);
- p2 = pl.GetPoint2dAt(i - 1);
- p3 = pl.GetPoint2dAt(i - 2);
- bulge = pl.GetBulgeAt(i - 1);
- angle = 4 * Math.Atan(bulge); // 計算出角度值
- radius = (p1.GetDistanceTo(p2) / 2) / Math.Sin(angle / 2); // 計算出半徑值
- b = (1 / bulge - bulge) / 2;
- x = 0.5 * ((p1.X + p2.X) - b * (p1.Y - p2.Y));
- y = 0.5 * ((p1.Y + p2.Y) + b * (p1.X - p2.X));
- center = new Point2d(x, y);
- bulge02 = pl.GetBulgeAt(i - 2);
- angle02 = 4 * Math.Atan(bulge02); // 計算出角度值
- radius02 = (p2.GetDistanceTo(p3) / 2) / Math.Sin(angle02 / 2); // 計算出半徑值
- b = (1 / bulge02 - bulge02) / 2;
- x = 0.5 * ((p2.X + p3.X) - b * (p2.Y - p3.Y));
- y = 0.5 * ((p2.Y + p3.Y) + b * (p2.X - p3.X));
- center02 = new Point2d(x, y);
- #if Debug
- Env.Printl($"before 半徑01 {radius} ,{bulge} ,{center}");
- Env.Printl($"before 半徑02 {radius02} ,{bulge02} ,{center02}");
- #endif
- // 比對半徑及圓心座標值
- if (Math.Abs(radius - radius02) < tol && center.GetDistanceTo(center02) < tol)
- {
- pl.RemoveVertexAt(index: i - 1); // 移除第2点
- angle += angle02; // 計算出角度值
- bulge = Math.Tan(angle / 4);
- pl.SetBulgeAt(i - 2, bulge);
- #if Debug
- Env.Printl($"after 半徑{radius} ,{bulge}");
- #endif
- }
- }
- // 判斷首尾如果閉合的部份
- if (pl.Closed && pl.NumberOfVertices > 2)
- {
- // 從結束-1點往前比對
- p1 = pl.GetPoint2dAt(pl.NumberOfVertices - 2);
- p2 = pl.GetPoint2dAt(pl.NumberOfVertices - 1);
- p3 = pl.GetPoint2dAt(0);
- bulge = pl.GetBulgeAt(pl.NumberOfVertices - 1);
- angle = 4 * Math.Atan(bulge); // 計算出角度值
- radius = (p1.GetDistanceTo(p2) / 2) / Math.Sin(angle / 2); // 計算出半徑值
- b = (1 / bulge - bulge) / 2;
- x = 0.5 * ((p1.X + p2.X) - b * (p1.Y - p2.Y));
- y = 0.5 * ((p1.Y + p2.Y) + b * (p1.X - p2.X));
- center = new Point2d(x, y);
- bulge02 = pl.GetBulgeAt(0);
- angle02 = 4 * Math.Atan(bulge02); // 計算出角度值
- radius02 = (p2.GetDistanceTo(p3) / 2) / Math.Sin(angle02 / 2); // 計算出半徑值
- b = (1 / bulge02 - bulge02) / 2;
- x = 0.5 * ((p2.X + p3.X) - b * (p2.Y - p3.Y));
- y = 0.5 * ((p2.Y + p3.Y) + b * (p2.X - p3.X));
- center02 = new Point2d(x, y);
- // 比對半徑及圓心座標值
- if (Math.Abs(radius - radius02) < tol && center.GetDistanceTo(center02) < tol)
- {
- pl.RemoveVertexAt(pl.NumberOfVertices - 1); // 移除第2点
- angle += angle02; // 計算出角度值
- bulge = Math.Tan(angle / 4);
- pl.SetBulgeAt(0, bulge);
- #if Debug
- Env.Printl($"after 半徑{radius} ,{bulge}");
- #endif
- }
- // 從起始+1點往后比對
- p1 = pl.GetPoint2dAt(1);
- p2 = pl.GetPoint2dAt(0);
- p3 = pl.GetPoint2dAt(pl.NumberOfVertices - 1);
- bulge = pl.GetBulgeAt(0);
- angle = 4 * Math.Atan(bulge); // 計算出角度值
- radius = (p1.GetDistanceTo(p2) / 2) / Math.Sin(angle / 2); // 計算出半徑值
- b = (1 / bulge - bulge) / 2;
- x = 0.5 * ((p1.X + p2.X) - b * (p1.Y - p2.Y));
- y = 0.5 * ((p1.Y + p2.Y) + b * (p1.X - p2.X));
- center = new Point2d(x, y);
- bulge02 = pl.GetBulgeAt(pl.NumberOfVertices - 1);
- angle02 = 4 * Math.Atan(bulge02); // 計算出角度值
- radius02 = (p2.GetDistanceTo(p3) / 2) / Math.Sin(angle02 / 2); // 計算出半徑值
- b = (1 / bulge02 - bulge02) / 2;
- x = 0.5 * ((p2.X + p3.X) - b * (p2.Y - p3.Y));
- y = 0.5 * ((p2.Y + p3.Y) + b * (p2.X - p3.X));
- center02 = new Point2d(x, y);
- // 比對半徑及圓心座標值
- if (Math.Abs(radius - radius02) < tol && center.GetDistanceTo(center02) < tol)
- {
- pl.RemoveVertexAt(0); // 移除第2点
- angle += angle02; // 計算出角度值
- bulge = Math.Tan(angle / 4);
- pl.SetBulgeAt(pl.NumberOfVertices - 1, bulge);
- #if Debug
- Env.Printl($"after 半徑{radius} ,{bulge}");
- #endif
- }
- }
- }
- return num - pl.NumberOfVertices;
- }
- private static int SimplifyPolylineDemo(Polyline pl, double tol = 1e-6)
- {
- int num = pl.NumberOfVertices;
- using (pl.ForWrite())
- {
- if (pl.NumberOfVertices < 3)
- return 0;
- // 優化多段線相鄰兩點共點時
- for (var i = 0; i < pl.NumberOfVertices; i++)
- {
- var type = pl.GetSegmentType(i);
- if (type == SegmentType.Coincident)
- pl.RemoveVertexAt(i);
- }
- for (var i = pl.NumberOfVertices - 1; i >= 2; i--)
- {
- var type = pl.GetSegmentType(i);
- Env.Printl(type.GetType().Name + " " + type.ToString());
- // 優化多段線相鄰兩點共點時
- if (type == SegmentType.Coincident)
- {
- pl.RemoveVertexAt(i); // 移除第1点
- continue;
- }
- // 跳过非线段部分
- if (type != SegmentType.Line)
- continue;
- var type2 = pl.GetSegmentType(index: i - 1);
- Env.Printl(type2.GetType().Name + " " + type2.ToString());
- if (type2 != SegmentType.Line)
- continue;
- // 獲取相鄰三点
- var p1 = pl.GetPoint2dAt(i);
- var p2 = pl.GetPoint2dAt(i - 1);
- var p3 = pl.GetPoint2dAt(i - 2);
- // 優化第1點至 第2點、第3點 向量.Normal相等時
- var bu = p1.GetArcBulge(p2, p3, tol);
- if (bu != 0)
- continue; //不共线跳过
- pl.SetPointAt(index: i - 1, p3); // 第2点移到第3点位置
- pl.RemoveVertexAt(index: i - 2); // 移除第3点
- }
- }
- return num - pl.NumberOfVertices;
- }
- }
備註: 感謝 小叶 Moy 的Demo!!!!
|
|