wang2006zhi 发表于 2025-2-12 22:33:18

简单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);
}

wang2006zhi 发表于 2025-2-12 22:40:31


    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:13

有代码块不用,非要搞成这么丑的排版

wang2006zhi 发表于 2025-2-14 11:55:19

d1742647821 发表于 2025-2-13 15:26
有代码块不用,非要搞成这么丑的排版

之前没注意有那么个按钮:L

箭头_Row 发表于 2025-2-17 21:54:34

本帖最后由 箭头_Row 于 2025-2-17 21:58 编辑

https://www.cnblogs.com/JJBox/p/12571436.html

直接看下這個博客就好了,重點是下面這句:
{
到了Acad2011: 就可以通过以下语句获取

Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor;
ed.TraceBoundary(........);
}

當然不滿意自帶的api,可以按照博客里的思路手搓一個!

wang2006zhi 发表于 2025-2-18 23:01:32

CAD自带的后台和平面外用不了
页: [1]
查看完整版本: 简单BO实现(仅支持直线),deepseek助写