简单BO实现(仅支持直线),deepseek助写
本帖最后由 wang2006zhi 于 2025-2-14 12:41 编辑/// <summary>
/// BO算法实现,仅直线
/// </summary>
/// <param name="pointsOnLine"></param>
/// <param name="targetPoint"></param>
/// <returns></returns>
public static Polyline? GetBPolyCurve(this Dictionary<Line, List<Point3d>> pointsOnLine, Point3d targetPoint)
{
var lines = new List<Line>();
foreach (var item in pointsOnLine)
{
Line line = item.Key;
List<Point3d> points = item.Value;
if (points.Count < 3)
continue;
//线上有多个点,按顺序打断线
var curves = line.GetSplitCurves(points);
//一个line被他上面的点打成多个line后加入列表
foreach (var curve in curves)
{
if (curve is Line line2)
lines.Add(line2);
}
}
//清除线头
List<Line> goodlines = RepairLine(lines);
List<Line> goodlines2 = RecycleLine(goodlines);
if (goodlines2.Count == 0)
return null;
lines.Clear();
lines = goodlines2;
Line firstLine = lines.FindByMin(c => c.GetClosestPointTo(targetPoint, false)
.DistanceTo(targetPoint));
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 - targetPoint;
Vector3d v2 = firstLine.EndPoint - targetPoint;
if (v1.CrossProduct(v2).Z > 0)
polyline.ReverseCurve();
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))
continue;
maxAngle = angle;
bigLine = item;
}
polyline.JoinEntity(bigLine);
lines.Remove(bigLine);
if (polyline.EndPoint == polyline.StartPoint)
break;
}
return polyline;
}
private static List<Line> RepairLine(List<Line> lines)
{
if (lines.Count == 0)
return new List<Line>();
List<Line> goodlines = new List<Line>();
for (int i = 0; i < lines.Count; i++)
{
var leftHandOk = false;
var rightHandOk = false;
for (int j = 0; j < lines.Count; j++)
{
if (i == j)
continue;
if (lines.StartPoint == lines.StartPoint || lines.StartPoint == lines.EndPoint)
leftHandOk = true;
if (lines.EndPoint == lines.StartPoint || lines.EndPoint == lines.EndPoint)
rightHandOk = true;
if (!leftHandOk || !rightHandOk)
continue;
if (!goodlines.Contains(lines))
goodlines.Add(lines);
}
}
return goodlines;
}
private 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;
templine = RepairLine(templine);
tempnum = templine.Count;
}
return templine;
}
public static Dictionary<Line, List<Point3d>> GetPtsOnLineDic(this List<Curve> curves)
{
var lines = new List<Line>();
// 优化多段线分解为线段逻辑
foreach (var item in curves)
{
switch (item)
{
case Line line0:
lines.Add(line0);
break;
case Polyline pl:
AddPolylineSegments(pl,
lines);
break;
}
}
// 预初始化字典并指定容量
var pointsOnLine = new Dictionary<Line, List<Point3d>>(lines.Count);
foreach (var line in lines)
{
pointsOnLine = new List<Point3d>(8) // 预设合理容量
{
line.StartPoint,
line.EndPoint
};
}
// 使用对象池重用集合对象
var posPool = new ObjectPool<Point3dCollection>(() => new Point3dCollection(), Environment.ProcessorCount * 2);
// 并行计算线段交点
Parallel.For(0, lines.Count, i =>
{
var lineI = lines;
for (int j = i + 1; j < lines.Count; j++)
{
var lineJ = lines;
var pos = posPool.Get();
pos.Clear();
lineI.IntersectWith(lineJ,
Intersect.OnBothOperands,
pos,
IntPtr.Zero,
IntPtr.Zero);
if (pos.Count > 0)
{
// 双锁模式保证线程安全
lock (pointsOnLine)
pointsOnLine.AddRange(pos.Cast<Point3d>());
lock (pointsOnLine)
pointsOnLine.AddRange(pos.Cast<Point3d>());
}
posPool.Return(pos);
}
});
// 并行排序
Parallel.ForEach(pointsOnLine, kvp =>
{
var line = kvp.Key;
var points = kvp.Value;
// 使用数组进行高效排序
var arr = points.ToArray();
try
{
Array.Sort(arr, (a, b) => line.GetParameterAtPoint(a).CompareTo(line.GetParameterAtPoint(b)));
}
catch (Exception e)
{
Console.WriteLine(e);
}
kvp.Value.Clear();
kvp.Value.AddRange(arr);
});
return pointsOnLine;
}
// 处理多段线分解
private static void AddPolylineSegments(Polyline pl, List<Line> lines)
{
int count = pl.NumberOfVertices;
if (count < 2)
return;
bool isClosed = pl.Closed;
for (int i = 0;
i < count;
i++)
{
int next = (i == count - 1)
? 0
: i + 1;
if (!isClosed && i == count - 1)
break;
lines.Add(new Line(pl.GetPoint3dAt(i),
pl.GetPoint3dAt(next)));
}
}
// 简单对象池实现
private class ObjectPool<T> where T : new()
{
private readonly ConcurrentBag<T> _objects = new();
private readonly Func<T> _generator;
public ObjectPool(Func<T> generator, int initialCount = 0)
{
_generator = generator;
for (int i = 0; i < initialCount; i++)
_objects.Add(_generator());
}
public T Get() => _objects.TryTake(out T item) ? item : _generator();
public void Return(T item) => _objects.Add(item);
}
public void Tt8()
{
using var tr = new DBTrans();
if (!Env.Editor.GetEnts(out List<Curve> curList))
return;
var dc = curList.GetPtsOnLineDic();
int i = 1;
while (Env.Editor.GetPoint(out var cenpt))
{
if (dc.GetBPolyCurve(cenpt) is not {} pl)
return;
pl.ColorIndex = i++%255;
pl.ConstantWidth = 5;
tr.CurrentSpace.AddEntity(pl);
pl.Redraw(BrightEntity.Draw);
}
} 有代码块不用,非要搞成这么丑的排版 d1742647821 发表于 2025-2-13 15:26
有代码块不用,非要搞成这么丑的排版
之前没注意有那么个按钮:L 本帖最后由 箭头_Row 于 2025-2-17 21:58 编辑
https://www.cnblogs.com/JJBox/p/12571436.html
直接看下這個博客就好了,重點是下面這句:
{
到了Acad2011: 就可以通过以下语句获取
Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor;
ed.TraceBoundary(........);
}
當然不滿意自帶的api,可以按照博客里的思路手搓一個! CAD自带的后台和平面外用不了
页:
[1]