明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 1213|回复: 8

[【IFoxCAD】] 直线首尾相连-CAD选择版

  [复制链接]
发表于 2024-8-6 12:37:49 | 显示全部楼层 |阅读模式
本帖最后由 wang2006zhi 于 2024-8-27 13:17 编辑

[CommandMethod("tt222")]
public void Tt222()
{
    using var tr = new DBTrans();
    var tol = new Tolerance(5, 50);
    while (true)
    {

        var sw = Stopwatch.StartNew();
        if (!Env.Editor.SelEnt(out Line line))
            return;
        var queue = new Queue<Line>();
        queue.Enqueue(line);
        var sellines = new List<Line>();
        while (queue.Any())
        {
            var temp = queue.Dequeue();



var ptc = temp.GeometricExtents.GetPointCollection();
if (!Env.Editor.SelEnts(out List<Line> sel, ptc, fil: fil))
    return;





            foreach (var item in sel)
            {
                if (temp.Equals(item))
                    continue;
                if (sellines.Contains(item))
                    continue;
                if (IsLink(temp, item))
                {
                    sellines.Add(item);
                    queue.Enqueue(item);
                }
            }
        }

        if (!sellines.Any())
            continue;
        sellines.ForEach(ent =>
        {
            using (ent.ForWrite())
            {
                ent!.ColorIndex = ent.ColorIndex == 1 ? 2 : 1;
                ent.Draw();
            }
        });
        sw.Stop();
        Env.Editor.WriteMessage("\n TT10用时{0}毫秒", sw.Elapsed.TotalMilliseconds);
    }

    //链接条件
bool IsLink(Line lineA, Line lineB)
    {
        if (lineA.StartPoint.IsEqualTo(lineB.StartPoint, tol)
            || lineA.StartPoint.IsEqualTo(lineB.EndPoint, tol)
            || lineA.EndPoint.IsEqualTo(lineB.StartPoint, tol)
            || lineA.EndPoint.IsEqualTo(lineB.EndPoint, tol)
           )
            return true;
        return false;
    }
}



发表于 2024-8-6 14:52:43 | 显示全部楼层
https://gitee.com/inspirefunctio ... Shared/TestCurve.cs

IFOX 封裝了時間監測器,在此測試文件的 57 -61 行里可以看到。

另:
一、 if (!Env.Editor.SelEnt(out Line line)) 中 SelEnt 0.7.1版本的麼看到這個封裝函數,是用的更高版本的 IFOX嗎?

二、temp.StartPoint..GetPointCollection(); 原始APII也麼有這個方法,是自己封裝的嗎?

三、 bool IsLink(Line lineA, Line lineB) 函數的方法建議輸入形參加一個tol,做SDK形式更通用一些。
发表于 2024-8-6 17:29:56 | 显示全部楼层
很好,学习了,要是加上注释就更好了
发表于 2024-8-6 17:46:03 | 显示全部楼层
本帖最后由 你有种再说一遍 于 2024-8-7 02:42 编辑

还得接着优化,考虑使用线程安全邻接表和多线程并行,
因为这样才可以把每次识别一条改为多条,提高吞吐量.

写c#重点是一次性完成全部并且尽可能在一秒内,
而不是像lisp一点一点的处理.

本次的优化建议:
  1. [CommandMethod(nameof(Tt222))]
  2. public void Tt222() {
  3.     using var tr = new DBTrans();
  4.     while (true) {
  5. var sw = Stopwatch.StartNew();
  6. // 链式选择,选择图元对象作为起点种子.
  7. if (!Env.Editor.SelEnt(out ObjectId lineId)) return;
  8. // 创建一个队列用于存储待处理的线段...
  9. 此处储存line有问题,应该改为id,
  10. 一是储存图元的信息熵巨大,Entity和Entity比较会进入内部逻辑而不是id这样的数值比较.
  11. 二是不利于后续删除,
  12. 三是改为多事务的话,Entity跨事务会错乱,甚至有人不小心在跨事务进行写模式.

  13. // 创建一个列表用于存储符合条件的线段
  14. var sellines = new HashSet<LineType>();

  15. var line = lineId.ToEntity();
  16. var lineType=new LineType(
  17. line.ObjectId,line.StartPoint,line.EndPoint);

  18. var queue = new Queue<LineType>();
  19. queue.Enqueue(lineType);

  20. // 只要队列不为空就继续循环
  21. while (queue.Any())  {
  22.     // 不要做无畏的转换,Hash容器可以保证唯一,选择与起点和终点相关的实体加入...按理来说这里用一个ssget就够了...
  23.    HashSet<ObjectId> ids=[];
  24.    var a=Env.Editor.SelEnts(ids);
  25.    if (!a) return;
  26.    var b=Env.Editor.SelEnts(ids);
  27.    if (!b) return;

  28.    // 取出种子线段
  29.    var t = queue.Dequeue();
  30.    foreach (var id in ids) {
  31.       // 当前线段与遍历线段相同则跳过
  32.       if (t.ObjectId==id) continue;
  33.       // 已经添加过该线段则跳过
  34.       var iLine = id.ToEntity();
  35.       var iType=new LineType(
  36. iLine.ObjectId,iLine.StartPoint,iLine.EndPoint);
  37.       if (sellines.Contains(iType)) continue;
  38.       // 有链接关系
  39.       if (t.IsLink(iType)) {
  40.          sellines.Add(iType);
  41.          queue.Enqueue(iType);
  42.       }
  43.     }
  44. }

  45. // 结果列表为空则跳过
  46. if (!sellines.Any()) continue;
  47. // 对结果列表中的每个线段执行操作
  48. sellines.ForEach(id => {
  49.   var ent = id.ToEntity();
  50.   using (ent.ForWrite())  {
  51.   // 切换线段的颜色索引
  52.   ent!.ColorIndex = ent.ColorIndex == 1 ? 2 : 1;
  53.   // 绘制线段
  54.    ent.Draw();
  55. }
  56. });
  57.         // 停止计时
  58.         sw.Stop();
  59.         // 输出操作所用的时间
  60.   Env.Editor.WriteMessage($"\n {nameof(Tt222)}用时{sw.Elapsed.TotalMilliseconds}毫秒");
  61.     }
  62. }
  63. public class LineType {
  64.     public ObjectId ObjectId;
  65.     public Point3d StartPoint;
  66.     public Point3d EndPoint;

  67.     // 构造函数
  68.     public LineType(ObjectId objectId, Point3d startPoint, Point3d endPoint) {
  69.         ObjectId = objectId;
  70.         StartPoint = startPoint;
  71.         EndPoint = endPoint;
  72.     }

  73.     // IsLink方法
  74.     public bool IsLink(LineType lineB, Tolerance? tol = null) {
  75.         if (tol == null) {
  76.             tol = new Tolerance(1, 1); // 默认容差值
  77.         }
  78.         return
  79.          StartPoint.IsEqualTo(lineB.StartPoint, tol) ||
  80.           StartPoint.IsEqualTo(lineB.EndPoint, tol) ||
  81.           EndPoint.IsEqualTo(lineB.StartPoint, tol) ||
  82.           EndPoint.IsEqualTo(lineB.EndPoint, tol);
  83.     }
  84.     // 使用hashset或者dictionary重写下面
  85.     // GetHashCode方法
  86.     public override int GetHashCode() {
  87.       unchecked { // 允许溢出,避免不必要的异常处理
  88.             return ObjectId.GetHashCode()
  89.              ^= StartPoint.GetHashCode()
  90.              ^= EndPoint.GetHashCode();
  91.         }
  92.     }

  93.     // Equals方法
  94.     public override bool Equals(object obj) {
  95.     return obj is LineType other
  96.       && ObjectId.Equals(other.ObjectId)
  97.       && StartPoint.Equals(other.StartPoint)
  98.       && EndPoint.Equals(other.EndPoint);
  99.     }
  100. }
  101. }



发表于 2024-8-7 10:55:22 | 显示全部楼层
好東西,謝謝分享,感謝!!!
 楼主| 发表于 2024-8-7 13:21:47 | 显示全部楼层
本帖最后由 wang2006zhi 于 2024-8-7 14:07 编辑
你有种再说一遍 发表于 2024-8-6 17:46
还得接着优化,考虑使用线程安全邻接表和多线程并行,
因为这样才可以把每次识别一条改为多条,提高吞吐量.
...

非常好的建议,通过构造一个新的类(LineType)用以减少原LINE数据量;但在新建类的时候是否有消耗。。TT21中原直线修改新的类(LineType)测试中用时较之前长。
个人意见  :通过直线起终点(如10范围)构造选择集,可以快速过滤掉需要的可能数据,减少循环判断。
var ptcS = temp.StartPoint.GetPointCollection();
var ptcE = temp.EndPoint.GetPointCollection();
if (!Env.Editor.SelEnts(out List<Line> selS, ptcS) & !Env.Editor.SelEnts(out List<Line> selE, ptcE))
   return;
经过实际测试。10万条乱线。你代码用时较多。。。【T2原四叉树】【TT21原CAD选择】【TT22你优化的代码】
TT2用时2478.1483毫秒
请选择对象:
TT2用时977.6429毫秒
请选择对象:
TT2用时1928.7176毫秒
请选择对象:
命令: tt21
请选择对象:
TT21用时1437.1039毫秒
请选择对象:
TT21用时711.9279毫秒
请选择对象:
TT21用时821.3567毫秒
请选择对象:
TT21用时645.9824毫秒
请选择对象:
命令: tt22
请选择对象:
Tt22用时1531.449毫秒
请选择对象:
Tt22用时1604.1684毫秒
请选择对象:
Tt22用时1427.732毫秒
请选择对象:



优化修改后的
[CommandMethod(nameof(Tt22))]
public void Tt22()
{
    using var tr = new DBTrans();
    while (true)
    {
        var sw = Stopwatch.StartNew();
        // 链式选择,选择图元对象作为起点种子.
        if (!Env.Editor.SelEnt(out Line line))
            return;
        // 此处储存line有问题,应该改为id,一是储存图元的信息熵巨大,EntityEntity比较会进入内部逻辑而不是id这样的数值比较.
        // 二是不利于后续删除,
        // 三是改为多事务的话,Entity跨事务会错乱,甚至有人不小心在跨事务进行写模式.
        // 创建一个队列用于存储待处理的线段...
        // 创建一个列表用于存储符合条件的线段
        var sellines = new HashSet<LineType>();
        var lineType=new LineType(line.ObjectId,line.StartPoint,line.EndPoint);
        var queue = new Queue<LineType>();
        queue.Enqueue(lineType);
        // 只要队列不为空就继续循环
        while (queue.Any())  
        {
            // 不要做无畏的转换,Hash容器可以保证唯一,选择与起点和终点相关的实体加入...按理来说这里用一个ssget就够了...
            var temp = queue.Dequeue();
            var ptcS = temp.StartPoint.GetPointCollection();
            var ptcE = temp.EndPoint.GetPointCollection();
            if (!Env.Editor.SelEnts(out HashSet<ObjectId> selS, ptcS) & !Env.Editor.SelEnts(out HashSet<ObjectId> selE, ptcE))
                return;
            var ids = selS.Union(selE);
            // 取出种子线段
            foreach (var id in ids)
            { // 当前线段与遍历线段相同则跳过
              if (temp.ObjectId==id)
                  continue;   
              // 已经添加过该线段则跳过
              var iLine = id.ToEntity<Line>();   
              var iType=new LineType(iLine.ObjectId,iLine.StartPoint,iLine.EndPoint);  
              if (sellines.Contains(iType))
                  continue;     
              // 有链接关系
              if (temp.IsLink(iType))
              {
                  sellines.Add(iType);      
                  queue.Enqueue(iType);
              }
            }
        }
        // 结果列表为空则跳过
        if (!sellines.Any())
            continue;
        // 对结果列表中的每个线段执行操作
        sellines.ForEach(id =>
        {
            var ent = id.ObjectId.ToEntity();
            using (ent.ForWrite())
            {  // 切换线段的颜色索引
               ent!.ColorIndex = ent.ColorIndex == 1 ? 2 : 1;  
               // 绘制线段
               ent.Draw(); }});      
        // 停止计时
        sw.Stop();        
        // 输出操作所用的时间
        Env.Editor.WriteMessage($"\n {nameof(Tt22)}用时{sw.Elapsed.TotalMilliseconds}毫秒");
    }
}


 楼主| 发表于 2024-8-7 14:01:14 | 显示全部楼层
本帖最后由 wang2006zhi 于 2024-8-7 14:10 编辑

   /// <summary>
    /// 交互模式获取单个实体
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    /// <param name="ed">命令行</param>
    /// <param name="t">实体</param>
    /// <param name="pt">交互点</param>
    /// <param name="msg">提示</param>
    /// <returns>bool</returns>
    public static bool SelEnt<T>(this Editor ed,
        out T t,
        out Point3d pt,
        string msg = "请选择对象:") where T : Entity
    {
        var per = ed.GetEntity("\n " + msg);
        t = null!;
        pt = per.PickedPoint;
        if (per.Status != PromptStatus.OK)
            return false;
        var tr = DBTrans.Top;
        if (tr.GetObject(per.ObjectId) is T result)
        {
            t = result;
            return true;
        }
        return false;
    }

    /// <summary>
    /// 以单点(中心点)构造选择点集
    /// </summary>
    /// <param name="cenpt">中心单点3D</param>
    /// <param name="ex">偏移量</param>
    /// <returns>点集合</returns>
    public static Point3dCollection GetPointCollection(this Point3d cenpt, double ex = 50)
    {
        var pt2d = new Point2d(cenpt.X, cenpt.Y);
        return GetPointCollection(pt2d, ex);
    }

   public static Point3dCollection GetPointCollection(this Point2d cenpt, double ex = 50)
    {
        return new Point3dCollection()
        {
            new Point3d(cenpt.X - 0.5 * ex, cenpt.Y - 0.5 * ex, 0),
            new Point3d(cenpt.X + 0.5 * ex, cenpt.Y - 0.5 * ex, 0),
            new Point3d(cenpt.X + 0.5 * ex, cenpt.Y + 0.5 * ex, 0),
            new Point3d(cenpt.X - 0.5 * ex, cenpt.Y + 0.5 * ex, 0),
        };
    }
      
    此为一个私有函数bool IsLink(Line lineA, Line lineB),并不通用,并且形参中  var tol = new Tolerance(5, 50);无法设置默认值。。


发表于 2024-8-7 16:52:11 | 显示全部楼层
还能优化的,最起码你现在没有用并行,继续努力
 楼主| 发表于 2024-11-1 18:15:07 | 显示全部楼层
            #region 精细选取
            
            // var ptcS = dimtemp.DimLinePoint.GetPointCollection(fuz);
            // var ptcE = dimtemp.DimLinePointN.GetPointCollection(fuz);
            // if (!Env.Editor.SelEnts(out List<Dimension> selS, ptcS, fil) &
            //     !Env.Editor.SelEnts(out List<Dimension> selE, ptcE, fil))
            //     return dimInfos;
            // var sel = selS.Union(selE);

            #endregion

            var ptColl = temp.GetRect().GetPointCollection(fuz);
            if (!Env.Editor.SelEnts(out List<Dimension> sel, ptColl, fil))
                return dimInfos;
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-11-22 20:53 , Processed in 0.165855 second(s), 22 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表