highflybird 发表于 2025-9-23 00:16:26

gzxl 发表于 2025-9-22 21:26
1742669 条直线直接干废了。





楼主的方法的确很好,我的还要进一步优化

gzxl 发表于 2025-9-23 09:38:43

控制了下节点深度,明显速度提升了不少。 收工...

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

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

highflybird 发表于 2025-9-23 21:38:08

本帖最后由 highflybird 于 2025-9-23 23:08 编辑

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




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

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

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

highflybird 发表于 2025-9-24 00:54:04

我在这里把核心代码贴出来
此算法采用了hash_map和DFS


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

TimeCounter tt;
for (int i = 0, k = 0; i < (int)objs.size(); ++i)
{
    AcDbObjectId id = objs;
    AcDbObjectPointer<AcDbCurve> curve(id, AcDb::kForRead);
    es = curve.openStatus();
    if (es != Acad::eOk) continue;
    Point pt1, pt2;
    curve->getStartPoint(pt1);
    curve->getEndPoint(pt2);
    pt1.z = 0; //Z坐标归零
    pt2.z = 0; //Z坐标归零
    pt1.id = id;
    pt2.id = id;
    pt1.index = k++;
    pt2.index = k++;
    points.push_back(pt1);
    points.push_back(pt2);
    if (curve->isClosed() || pt1.distanceTo(pt2) < Point::pointTol)
    {
      points.bClosed = true;
      points.bClosed = true;
    }
}
tt.PrintTime(_T("收集"));

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

for (size_t i =0; i<points.size();++i)
{
    points.pNext = pp;
    points.pNext = pp;
    ++i;
}

//点按照先x后y从小到大排序,然后相同(相近)位置的分为一组
std::sort(pp.begin(),pp.end(),Point_Comp());
hash_map<int, std::vector<Point*> > hashPoints;
std::set<int> allGroups;
for (int i = 0, j = 0; i < (int)pp.size(); ++j)
{
    Point* pt = pp;
    pt->iGroup = j;
    hashPoints.push_back(pt);
    allGroups.insert(j);
    i++;
    for(;i<pp.size();++i)
    {
      if (pp->distanceTo(*pp) > 1e-1)
      {
      break;
      }
      pp->iGroup = j;
      hashPoints.push_back(pp);
    }
}

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

//方法二的子程序
void QT::QuadTree::findConnected(Point* pt, hash_map<int, std::vector<Point*> > & hashPoints, std::vector<AcDbObjectId>& outIds, std::set<int> & allGroups)
{
if (pt->bVisited) return;
std::vector<Point*>& ptSame = hashPoints;
allGroups.erase(pt->iGroup);
for (size_t i = 0; i < ptSame.size(); ++i)
{
    ptSame->bVisited = true;
    if (!ptSame->pNext->bVisited)
    {
      outIds.push_back(ptSame->id);
    }
}

for (size_t i = 0; i < ptSame.size(); ++i)
{
    if (!ptSame->pNext->bVisited)
    {
      findConnected(ptSame->pNext, hashPoints, outIds, allGroups);
    }
}
}

highflybird 发表于 2025-9-24 13:11:56

再次改善了以前的用四叉树的算法,没用到哈希表,也得到不错的速度,


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


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

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

gzxl 发表于 2025-9-24 13:40:26

本帖最后由 gzxl 于 2025-9-24 13:42 编辑

highflybird 发表于 2025-9-24 13:11
再次改善了以前的用四叉树的算法,没用到哈希表,也得到不错的速度,



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

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

highflybird 发表于 2025-9-24 15:20:24


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

gzxl 发表于 2025-9-26 13:03:33

HashTable+DFS 确实比四叉树快了一半以上时间,特别是在大容量数据。

highflybird 发表于 2025-9-26 13:29:24

gzxl 发表于 2025-9-26 13:03
HashTable+DFS 确实比四叉树快了一半以上时间,特别是在大容量数据。
嗯,现在只要是CAD内存支持,估计千万级别的也能跑下来,可惜,不能跑并行。不然会更快

gzxl 发表于 2025-9-26 21:32:19


页: 1 [2] 3
查看完整版本: 四叉树+哈希表应用之:连接直线,运行速度很快