明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
12
返回列表 发新帖
楼主: gzxl

四叉树+哈希表应用之:连接直线,运行速度很快

  [复制链接]
发表于 4 天前 | 显示全部楼层
gzxl 发表于 2025-9-22 21:26
1742669 条直线直接干废了。


楼主的方法的确很好,我的还要进一步优化
回复 支持 反对

使用道具 举报

 楼主| 发表于 4 天前 | 显示全部楼层
控制了下节点深度,明显速度提升了不少。 收工...

输入直线连接容差<0.001>:0.001
指定对角点: 找到 130537 个
曲线连接用时 266 毫秒
绘制多段线共 2838 条,用时 16 毫秒

输入直线连接容差<0.001>:0.001
指定对角点: 找到 1742669 个
曲线连接用时 11109 毫秒
绘制多段线共 10154 条,用时 156 毫秒
回复 支持 反对

使用道具 举报

发表于 4 天前 | 显示全部楼层
本帖最后由 highflybird 于 2025-9-23 23:08 编辑

优化了算法,不用四叉树,只是采用了哈希表。速度得到极大提升。




命令: LJ
选择对象: 指定对角点: 找到 130537 个
选择对象:
收集 用时: 0.032852 秒.  ---收集是指的采集线段的两个端点
连接 用时: 0.128950 秒.  ---连接是把相连的线段(包括曲线)连接起来。
找到了2509条相连的曲线。

和楼主同样的容差 ,最后合并的线条数更少。

容差设置为0.1的时候,合并的线条数我这边运行的结果是:2478

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x

评分

参与人数 1明经币 +1 收起 理由
gzxl + 1 赞一个!

查看全部评分

回复 支持 反对

使用道具 举报

发表于 3 天前 | 显示全部楼层
我在这里把核心代码贴出来
此算法采用了hash_map和DFS


  1. //方法二:采用hash_map
  2. void QT::QuadTree::findConnected(const std::vector<AcDbObjectId>& objs, std::vector<std::vector<AcDbObjectId> > & out)
  3. {
  4.   Acad::ErrorStatus es;
  5.   AcDbExtents exts;
  6.   std::vector<Point> points;
  7.   if (objs.empty()) return;

  8.   TimeCounter tt;
  9.   for (int i = 0, k = 0; i < (int)objs.size(); ++i)
  10.   {
  11.     AcDbObjectId id = objs;
  12.     AcDbObjectPointer<AcDbCurve> curve(id, AcDb::kForRead);
  13.     es = curve.openStatus();
  14.     if (es != Acad::eOk) continue;
  15.     Point pt1, pt2;
  16.     curve->getStartPoint(pt1);
  17.     curve->getEndPoint(pt2);
  18.     pt1.z = 0; //Z坐标归零
  19.     pt2.z = 0; //Z坐标归零
  20.     pt1.id = id;
  21.     pt2.id = id;
  22.     pt1.index = k++;
  23.     pt2.index = k++;
  24.     points.push_back(pt1);
  25.     points.push_back(pt2);
  26.     if (curve->isClosed() || pt1.distanceTo(pt2) < Point::pointTol)
  27.     {
  28.       points[k - 1].bClosed = true;
  29.       points[k - 2].bClosed = true;
  30.     }
  31.   }
  32.   tt.PrintTime(_T("收集"));

  33.   std::vector<Point*> pp(points.size());
  34.   for (size_t i =0; i<points.size();++i)
  35.   {
  36.     pp = & points;
  37.   }

  38.   for (size_t i =0; i<points.size();++i)
  39.   {
  40.     points.pNext = pp[i+1];
  41.     points[i+1].pNext = pp;
  42.     ++i;
  43.   }

  44.   //点按照先x后y从小到大排序,然后相同(相近)位置的分为一组
  45.   std::sort(pp.begin(),pp.end(),Point_Comp());
  46.   hash_map<int, std::vector<Point*> > hashPoints;
  47.   std::set<int> allGroups;
  48.   for (int i = 0, j = 0; i < (int)pp.size(); ++j)
  49.   {
  50.     Point* pt = pp;
  51.     pt->iGroup = j;
  52.     hashPoints[j].push_back(pt);
  53.     allGroups.insert(j);
  54.     i++;
  55.     for(;i<pp.size();++i)
  56.     {
  57.       if (pp->distanceTo(*pp[i-1]) > 1e-1)
  58.       {
  59.         break;
  60.       }
  61.       pp->iGroup = j;
  62.       hashPoints[j].push_back(pp);
  63.     }
  64.   }

  65.   //DFS 算法得出相连的线段
  66.   while (!allGroups.empty())
  67.   {
  68.     int i =  *allGroups.begin();
  69.     Point* pt = *(hashPoints.begin());
  70.     std::vector<AcDbObjectId> Ids;
  71.     findConnected(pt, hashPoints, Ids, allGroups);
  72.     out.push_back(Ids);
  73.   }
  74.   tt.PrintTime(_T("连接"));
  75. }

  76. //方法二的子程序
  77. void QT::QuadTree::findConnected(Point* pt, hash_map<int, std::vector<Point*> > & hashPoints, std::vector<AcDbObjectId>& outIds, std::set<int> & allGroups)
  78. {
  79.   if (pt->bVisited) return;
  80.   std::vector<Point*>& ptSame = hashPoints[pt->iGroup];
  81.   allGroups.erase(pt->iGroup);
  82.   for (size_t i = 0; i < ptSame.size(); ++i)
  83.   {
  84.     ptSame->bVisited = true;
  85.     if (!ptSame->pNext->bVisited)
  86.     {
  87.       outIds.push_back(ptSame->id);
  88.     }
  89.   }

  90.   for (size_t i = 0; i < ptSame.size(); ++i)
  91.   {
  92.     if (!ptSame->pNext->bVisited)
  93.     {
  94.       findConnected(ptSame->pNext, hashPoints, outIds, allGroups);
  95.     }
  96.   }
  97. }


评分

参与人数 1明经币 +1 收起 理由
gzxl + 1 神马都是浮云

查看全部评分

回复 支持 反对

使用道具 举报

发表于 3 天前 | 显示全部楼层
再次改善了以前的用四叉树的算法,没用到哈希表,也得到不错的速度,


命令: LJ
选择对象: 指定对角点: 找到 130537 个
选择对象:
收集 用时: 0.040853 秒.
连接 用时: 0.583467 秒.
找到了2377条相连的曲线。


四叉树似乎更准确 ,在0.1的误差(或者间隙)范围内,可以相连在一起的,是2377条。
对于楼主这个图,0.1这个数值比较合理。

两种方法比较:哈希表+DFS,速度更快,四叉树+DFS准确度更高。
我再想办法提高哈希表的准确度。

回复 支持 反对

使用道具 举报

 楼主| 发表于 3 天前 | 显示全部楼层
本帖最后由 gzxl 于 2025-9-24 13:42 编辑
highflybird 发表于 2025-9-24 13:11
再次改善了以前的用四叉树的算法,没用到哈希表,也得到不错的速度,

0.1 允许容差,不知道我哪里代码出 bug了,整出了 11957 条

输入直线连接容差<0.001>:0.1
请框选需要连接的直线
指定对角点: 找到 130537 个
直线连接用时 312 毫秒
绘制多段线共 11957 条,用时 125 毫秒(应该是绘制越少,越证明连接成功)
回复 支持 反对

使用道具 举报

发表于 3 天前 | 显示全部楼层

这个是0.1间隙下的可连接线段图,用各种不同颜色以使得能看清楚哪些线段是连在一起的。
连接到一起的部分我没处理了,但是那部分程序我已经做了。那部分处理的时间较短。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 13:03 | 显示全部楼层
HashTable+DFS 确实比四叉树快了一半以上时间,特别是在大容量数据。
回复 支持 反对

使用道具 举报

发表于 昨天 13:29 | 显示全部楼层
gzxl 发表于 2025-9-26 13:03
HashTable+DFS 确实比四叉树快了一半以上时间,特别是在大容量数据。

嗯,现在只要是CAD内存支持,估计千万级别的也能跑下来,可惜,不能跑并行。不然会更快
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 21:32 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2025-9-27 03:14 , Processed in 0.187851 second(s), 19 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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