news 2026/9/6 1:54:47

线吸附算法实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
线吸附算法实现

本文提出的线线吸附算法的核心思路是:以参考线为基准,将待吸附线的线段投影到参考线上,并截取对应长度的一段作为结果

具体流程如下:

  1. 数据预处理与坐标统一:将所有输入图层统一转换到EPSG:4498,该坐标系是上海地区常用的投影坐标系,能有效控制长度变形。

  2. 多部件几何体合并与拆分:将图层中所有要素的几何部件提取出来,合并到一个MultiLineString中,再通过mergeLines()将首尾相连的线段合并为完整的线,最后拆分为单部件LineString集合。

  3. 空间索引构建:为参考线创建20米缓冲区和空间索引(R-tree),加速空间查询。

  4. 候选参考线筛选:通过空间索引快速找出与待吸附线相交(缓冲区相交)的候选参考线,再通过精确的intersects()判断筛选出真正相交的参考线。

  5. 最佳匹配选择:选择与待吸附线交叠长度最长且超过待吸附线长度60%的参考线作为匹配目标。

  6. 线段吸附

    • 计算待吸附线的中点

    • 将中点投影到选定的参考线上,得到投影位置

    • 以待吸附线长度的一半为半径,在参考线上截取对应长度的线段

    • 截取结果即为吸附后的几何体

#include "qgsmultilineString.h" QVector<QgsGeometry> mergeLayerFeatures(QgsVectorLayer* inputLayer) { QgsCoordinateReferenceSystem srcCrs = inputLayer->crs(); //上海常用4498 auto destCrs = QgsCoordinateReferenceSystem("EPSG:4498"); QgsCoordinateTransform transform(srcCrs, destCrs, QgsProject::instance()); auto refFeatureIter = inputLayer->getFeatures(); std::unique_ptr<QgsMultiLineString> multiLineString(new QgsMultiLineString()); QgsFeature refFeature; while (refFeatureIter.nextFeature(refFeature)) { if (!refFeature.hasGeometry()) { continue; } auto refFeatureGeo = refFeature.geometry(); if (refFeatureGeo.isEmpty() || !refFeatureGeo.isGeosValid()) { continue; } refFeatureGeo.transform(transform); auto refFeatureGeoParts = refFeatureGeo.constParts(); while (refFeatureGeoParts.hasNext()) { multiLineString->addGeometry(refFeatureGeoParts.next()->clone()); } } if (multiLineString->isEmpty()) { return QVector<QgsGeometry>();; } const QgsGeometry in(multiLineString.release()); //拆成QgsLineString集合 return in.mergeLines().asGeometryCollection(); } void lineAdsorption(QgsVectorLayer* adsLayer, QgsVectorLayer* refLayer) { auto adsGeos = mergeLayerFeatures(adsLayer); auto refGeos = mergeLayerFeatures(refLayer); QVector<QgsGeometry> adsResultGeos; QVector<QgsGeometry> halfPtGeos; adsResultGeos.resize(adsGeos.size()); halfPtGeos.resize(adsGeos.size()); for (int i = 0; i < adsGeos.size();i++) { adsResultGeos[i] = adsGeos[i]; halfPtGeos[i] = adsGeos[i].interpolate(adsGeos[i].length() / 2); } //吸附阈值 double adsThreshold = 20; QgsSpatialIndex refSpatialIndex; QVector<QgsGeometry> refBufferGeos; for (int i = 0; i < refGeos.size(); i++) { auto refBufferGeo = refGeos[i].buffer(adsThreshold, 20); refBufferGeos.append(refBufferGeo); refSpatialIndex.addFeature(i, refBufferGeo.boundingBox()); } #pragma omp parallel for for (int i = 0; i < adsGeos.size(); i++) { QList<QgsFeatureId> candidateIds = refSpatialIndex.intersects(adsGeos[i].boundingBox()); if (candidateIds.size() == 0) { continue; } int intersectIndex = -1; double intersectLen = -1.0; for (auto& candidateId: candidateIds) { if (!adsGeos[i].intersects(refBufferGeos[candidateId])) { continue; } auto intersectGeo = adsGeos[i].intersection(refBufferGeos[candidateId]); if (intersectGeo.length() > (adsGeos[i].length() * 0.6) && intersectGeo.length() > intersectLen) { intersectLen = intersectGeo.length(); intersectIndex = candidateId; } } if (intersectLen < 0) { continue; } //根据中点向两边延伸 auto resLocate = refGeos[intersectIndex].lineLocatePoint(refGeos[intersectIndex].nearestPoint(halfPtGeos[i])); auto sD = std::max(0.0, resLocate - adsGeos[i].length()/2); auto eD = std::min(refGeos[intersectIndex].length(), resLocate + adsGeos[i].length() / 2); const QgsLineString* lineString = qgsgeometry_cast<const QgsLineString*>(refGeos[intersectIndex].constGet()); adsResultGeos[i] = QgsGeometry(lineString->curveSubstring(sD, eD)->clone()); } //adsResultGeos[i]为吸附后结果 }

本文代码在逻辑层面进行了完整的推演与验证。由于开发环境的限制,代码尚未在完整数据集上进行系统性测试。文中提供的算法流程和代码实现可作为技术参考,读者在实际部署时请根据具体业务场景进行适配和充分测试。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 1:54:30

从语音交互到AI Agent:300美元AI设备背后的技术架构与应用边界

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 1:54:05

YOLOv8+PyQt5非机动车头盔检测系统设计:从模型训练到GUI部署全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 1:48:06

纯 C OCR 又补齐 Java 生态了!lw.PPOCR.C v0.1.0-preview.7 发布

目录 一、普通 Java/JVM 现在可以直接调用 lw.PPOCR.C 二、Windows DLL、Linux SO 已经直接放进 Release 三、Android 也补上了完整 Java 接入 四、单文件 HTML 现在可以直接 CtrlV 粘贴截图 五、为什么粘贴后没有自动 OCR&#xff1f; 六、一个 HTML&#xff0c;依然完全…

作者头像 李华
网站建设 2026/9/6 1:46:38

代理SC证,找什么公司才能不走弯路

代理SC证&#xff0c;找什么公司才能不走弯路&#xff1f;你公司的食品生产许可证&#xff08;SC证&#xff09;快到期了&#xff0c;或者新项目要投产&#xff0c;但对着厚厚一摞法规文件头疼不已。想找代理机构&#xff0c;却发现市面上的咨询公司五花八门——有的声称“包过…

作者头像 李华
网站建设 2026/9/6 1:46:14

AI安装CERN ROOT GEANT4 RADWARE GASPWARE

WSL 核物理工具链安装提示词&#xff08;脱敏可复用版&#xff09; 请作为一名熟悉 Linux、WSL2、CMake、GTK/Qt 和核物理数据分析软件的系统工程师&#xff0c;帮助我在一台全新的 WSL2 Ubuntu 环境中安装并配置以下四套软件&#xff1a; CERN ROOTGeant4&#xff08;简称 G4&…

作者头像 李华