031集——获取外轮廓(只支持线段多段线)(CAD—C#二次开发入门)
此版本跟007集相比,增加了个识别断线头的功能,即原始图形中线段可不闭合。
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace AcTools
{
public static class Outershape
{
public static void Demo()
{
try
{
if (!Z.db.GetEntities(out List<Curve> curve, "框选识别外轮廓的图像") )return;
List<Line> lines = new List<Line>();
foreach (var item in curve)//多段线炸开成线段
{
if (item is Line) lines.Add(item as Line);
else if (item is Polyline pl)
{
List<Curve> cus = Z.ed.ExplodePolyLine(pl);
foreach (var cu in cus)
{
if (cu is Line) lines.Add(cu as Line);
}
}
}
//lines.ForEach(line => line.ColorIndex = 1);
//foreach (var item in lines)
//{
// db.AddEntityToModeSpace(item);
//}
//return;
Dictionary<Line, List<Point3d>> pointsOnLine = new Dictionary<Line, List<Point3d>>();
foreach (var item in lines)//创建线和对应点组成的字典
{
pointsOnLine.Add(item, new List<Point3d>());
}
for (int i = 0; i < lines.Count - 1; i++)
{
for (int j = i + 1; j < lines.Count; j++)
{
Point3dCollection pos = new Point3dCollection();//创建点集合
lines[i].IntersectWith(lines[j], Intersect.OnBothOperands, pos, IntPtr.Zero, IntPtr.Zero);
if (pos.Count > 0)
{
foreach (Point3d item in pos)
{
pointsOnLine[lines[i]].Add(item);
pointsOnLine[lines[j]].Add(item);//获取线段交点的坐标存入字典
}
}
}
}
lines.Clear();
foreach (var item in pointsOnLine)//清理线
{
Line line = item.Key;
List<Point3d> points = item.Value;
//if (points.Count == 0)
//{
// //lines.Add(line);
//}
//else
//{
if (points.Count > 1)
{
points = points.OrderBy(x => line.GetParameterAtPoint(x)).ToList();//点排序
Point3dCollection pos = new Point3dCollection();
points.ForEach(x => pos.Add(x));//点集合加点
DBObjectCollection dbs = line.GetSplitCurves(pos);//线上有多个点,按顺序打断线
foreach (var dbobject in dbs)
{
if (dbobject is Line) lines.Add(dbobject as Line);//一个line被他上面的点打成多个line后加入列表
}
}
}
//}
List<Line> goodlines = Outershape.RepairLine(lines);//清除线头
List<Line> goodlines2 = Outershape.RecycleLine(goodlines);
if (goodlines2.Count == 0) return;
//foreach (var item in goodlines2)
//{
// item.ChangeEntityColor(2);
//}
//Z.db.AddEntityToModeSpace(goodlines2.ToArray());
//return;
lines.Clear();
lines = goodlines2;
// if (!PmPolyLineMethod.GetPoint(out Point3d point, "请选择外面一点")) return;
if (! Z.ed.GetPoint(out Point3d point, "请选择外面一点"))return;
Line firstLine = lines.OrderBy(x => x.GetClosestPointTo(point, false).DistanceTo(point)).First();
//firstLine.ColorIndex = 5;
//Z.db.AddEntityToModeSpace(firstLine);
//return;
lines.Remove(firstLine);
Polyline polyline = new Polyline();
polyline.AddVertexAt(0, firstLine.StartPoint.Convert2d(new Plane()), 0, 0, 0);
polyline.AddVertexAt(1, firstLine.EndPoint.Convert2d(new Plane()), 0, 0, 0);
Vector3d v1 = firstLine.StartPoint - point;
Vector3d v2 = firstLine.EndPoint - point;
if (v1.CrossProduct(v2).Z > 0) polyline.ReverseCurve();
//polyline.ColorIndex = 1;
//db.AddEntityToModeSpace(polyline);
//return;
while (true)
{
List<Line> tmps = new List<Line>();
foreach (var item in lines)
{
if (item.StartPoint == polyline.EndPoint)
{
tmps.Add(item);
}
else if (item.EndPoint == polyline.EndPoint)
{
item.ReverseCurve();
tmps.Add(item);
}
}
if (tmps.Count == 0) break;
Vector3d vector = -polyline.GetFirstDerivative(polyline.EndPoint);//顺时针
double maxAngle = 0;
Line bigLine = new Line();
foreach (var item in tmps)//
{
double angle = vector.GetAngleTo(item.Delta, -Vector3d.ZAxis);
if (angle > maxAngle)
{
maxAngle = angle;
bigLine = item;
}
}
polyline.JoinEntity(bigLine);
lines.Remove(bigLine);
if (polyline.EndPoint == polyline.StartPoint) break;
}
polyline.ColorIndex = 1;
Z.db.AddEntityToModeSpace(polyline);
return;
}
catch (System.Exception)
{
throw;
}
}
public static List<Line> RepairLine(List<Line> lines)
{
if (lines.Count == 0 ) return new List<Line>();
bool leftHandOk = false;
bool rightHandOk = false;
List<Line> goodlines = new List<Line>();
for (int i = 0; i < lines.Count; i++)
{ leftHandOk = false;
rightHandOk = false;
//if (i == 6) Debugger.Break();
Point3d point = new Point3d((lines[i].StartPoint.X + lines[i].EndPoint.X) / 2, (lines[i].StartPoint.Y + lines[i].EndPoint.Y) / 2, 0);
DBText text = new DBText() { Position = point, TextString = $"{i}:", Height = 1 };
Z.db.AddEntityToModeSpace(text);
for (int j = 0; j < lines.Count; j++)
{
if (i == j) continue;
if ((lines[i].StartPoint == lines[j].StartPoint)|| (lines[i].StartPoint == lines[j].EndPoint))
{
leftHandOk = true;
}
if ((lines[i].EndPoint == lines[j].StartPoint) || (lines[i].EndPoint == lines[j].EndPoint))
{
rightHandOk = true;
}
if (leftHandOk && rightHandOk)
{
if (!goodlines.Contains(lines[i]))
{
goodlines.Add(lines[i]);
}
}
}
}
return goodlines;
}
public static List<Line> RecycleLine(List<Line> lines)
{
if (lines.Count == 0) return new List<Line>();
List<Line> templine = lines;
int tempnum = lines.Count;
while (true)
{
if (RepairLine(templine).Count == tempnum)
{
break;
}
else
{
templine = RepairLine(templine);
tempnum = templine.Count;
}
}
return templine;
}
}
}