基于GeoTools的道路相交多个点容差冗余计算实战

目录

前言

一、关于道路相交

1、相交四个点

2、点更多的情况

二、基于距离的相交点去重

1、冗余距离计算

2、调用过程

3、去重后的结果

三、总结


前言

        在地理信息系统(GIS)领域,道路网络数据的处理与分析一直是关键课题。随着城市化进程的加速,日益复杂的道路网络对数据精度和处理效率提出了更高要求。而道路相交多个点容差冗余计算,作为道路网络分析中的基础且重要环节,关乎着后续诸多应用的准确性和可靠性。在之前的博客中,我们介绍了基于道路的名称来进行两条道路的相交点计算。原文地址:基于GeoTools和OSM路网求解两条道路相交点-以长沙市为例。

        在实际场景中,使用这种处理办法时往往会出现道路相交处存在多个相近点的情况。这些冗余点不仅增加了数据量,还会对诸如路径分析、网络建模等操作产生干扰。例如,在构建道路连通性模型时,过多的冗余点可能导致错误的连通性判断,进而影响整个模型的准确性。那么如何解决这种问题呢?这里使用一种基于容差的处理方法,即设定固定距离阈值进行点的删除或合并。而借助 GeoTools,我们可以通过灵活运用其几何处理工具,结合不同的数据结构和算法,实现更具针对性和适应性的容差冗余计算。通过深入研究其几何对象的操作方法,如点、线几何关系的判定,能够精准地定位道路相交处的冗余点。同时,利用 GeoTools 的数据结构优势,可对道路数据进行高效组织和遍历,从而快速地进行容差范围内的点对比和甄别。

        本次实战将从 GeoTools 的环境搭建入手,详细阐述如何导入和读取道路数据,展示如何对道路几何对象进行解析和操作。接着,重点介绍容差冗余计算的核心算法实现,包括如何设定合理的容差参数,以及如何根据几何计算结果对冗余点进行处理。通过对基于 GeoTools 的道路相交多个点容差冗余计算的实战研究,不仅可以提升道路数据的质量和可用性,还能为后续的地理数据分析和应用奠定坚实的基础。同时,这一过程也展示了 GeoTools 在解决实际 GIS 问题中的强大能力和灵活性,为相关的地理信息开发工作提供了宝贵的实践经验和参考案例。接下来,我们将逐步深入到具体的实现细节中,一同探索这一关键问题的有效解决方案。

一、关于道路相交

        在之前的博文中留了两个问题给朋友们,这两个问题就是:1、表示经过我们的计算,为什么两条道路(金星北路和岳麓大道)的相交点是四个?2、会不会有更多的情况?这里就这两个问题来进行详细的答疑。

1、相交四个点

        首先来回答第一个问题,为什么是相交四个点?关于这个问题,其实大家可以结合生活的常识进行判断。这里为了方便将不同的道路类型在地图上进行展示,这里我们根据道路级别将道路的宽度进行不同的设置。设置的方法为,在对道路进行标绘时,选择分类标绘,界面如下图所示:

        根据分类列表信息,点击更多的分类,使用鼠标双击分类,打开当前选择分类的样式设置,管理界面如下:

         完成后,点击Ok进行应用,可以看到以下的最终结果:

        为了方便更加直观地查看两条道路的相交,我们将数据进一步的放大,能更直观的显示道路相交信息。这里选取骑龙路和枫林三路为例,如下所示:

         相信通过上面的图,大家应该很直观的就能看到根据两条路来求解相交是会有A、B、C、D四个相交点的。到这里就详细的说明了为什么存在多个交点的问题。

2、点更多的情况

        在上一小节中,我们使用QGIS软件来介绍了如何根据道路的名称对道路进行相交求解,并且回答了上一篇博客中提到的两条路相交,为什么有四个点的原因。之前还留了一个小问题,即除了上述的四个点的情况之外,还有没有其它更多的相交点的时候呢?答案是一定的。确实会存在,同上而言,我们的道路一般是上面的这种连接关系,或者是下面的连接关系:

        还有一种情况需要大家考虑,就是其中有一条道路是一个环形或者可以类似的S型,这里使用画图软件来表示:

        上面是一个简单的示意图,道路2是一条曲折蜿蜒的路,而道路1是一条直线,在道路的A和B出分别有前面描述的点相交的情况。共八个点,同理,如果两条路更加蜿蜒曲折,那么可以知道的是两条路势必有更多的交点。 可能在城市道路中这种道路不多见。通过本例也回答了相交点是否存在更多的问题。以长沙为例,城市环岛道路就会有这种情况,以中山路和黄兴路环岛为例:

二、基于距离的相交点去重

        在知晓了道路相交计算的几种结果情况之后,接下来我们来讲讲如何基于距离的计算将道路的相交点保留一个,在一些路口的计算当中,保留一个点比保留四个点更加容易理解。当然,是否需要这么处理,请根据自身的业务和需求来确定。

1、冗余距离计算

        这里介绍一种基于冗余距离的计算方法,将四个交点合并成一个交点信息。基于冗余距离的计算方法可以描述为如下文字:

假设道路在同一个交叉点有四个交点:

  1. 第一个点被添加到结果集和空间索引

  2. 后续三个点距离第一个点很近(< 阈值)

  3. 每个后续点都会与第一个点进行距离比较

  4. 距离小于阈值,被视为重复点而跳过

  5. 最终结果集中只保留第一个点

        使用Geotools来求解上述过程的关键代码如下:

//近似计算
private static final BigDecimal DISTANCE_TOLERANCE =  new BigDecimal(0.00003) ; // 不同坐标系下需要处理单位,4326单位为度,3米以视为同一个点private static void addUniquePointSimple(Point point,Set<Point> output,Set<String> uniqueKeys,String pointName) {for (Point np : output) {BigDecimal distance = new BigDecimal(point.distance(np));System.out.println(distance);if ( DISTANCE_TOLERANCE.compareTo(distance) < 0 ) {System.out.println("存在容差");// 在容差范围内,跳过return;}}output.add(point);
}

2、调用过程

        那么基于上面的距离来进行冗余点计算,与之前的生成逻辑相比。这里需要增加一步,即将根据Geotools求解的四个相交点进行容差计算,最后保留容差阈值外的点位置信息。调用过程关键代码如下:

/*** -两条道路集合的所有交点(简单实现,带名称属性且空间唯一)* * @param road1 第一条道路要素集合* @param road2 第二条道路要素集合* @param road1Name 第一条道路名称(用于属性)* @param road2Name 第二条道路名称(用于属性)* @return 带名称属性的相交点集合(空间唯一)*/
private static Set<Point> findUniqueIntersectionsSimple(SimpleFeatureCollection road1,SimpleFeatureCollection road2,String road1Name,String road2Name) {// 1. 使用组合名称final String pointName = road1Name + " & " + road2Name + " 交叉点";// 2. 使用坐标键值进行去重Set<String> uniqueKeys = new HashSet<>();Set<Point> uniquePoints = new HashSet<>();try (SimpleFeatureIterator iter1 = road1.features()) {while (iter1.hasNext()) {SimpleFeature f1 = iter1.next();Geometry geom1 = (Geometry) f1.getDefaultGeometry();if (geom1 == null || geom1.isEmpty()) continue;try (SimpleFeatureIterator iter2 = road2.features()) {while (iter2.hasNext()) {SimpleFeature f2 = iter2.next();Geometry geom2 = (Geometry) f2.getDefaultGeometry();if (geom2 == null || geom2.isEmpty()) continue;// 3. 计算交点Geometry result = OverlayNGRobust.overlay(geom1, geom2, OverlayNG.INTERSECTION);// 4. 处理结果并添加唯一点processIntersectionsSimple(result,uniquePoints,uniqueKeys,pointName);}}}}return uniquePoints;
}
/*** -处理交点结果(简单实现)*/
private static void processIntersectionsSimple(Geometry geom,Set<Point> output,Set<String> uniqueKeys,String pointName) {if (geom == null || geom.isEmpty()) return;if (geom instanceof Point) {addUniquePointSimple((Point) geom, output, uniqueKeys, pointName);} else if (geom instanceof MultiPoint) {for (int i = 0; i < geom.getNumGeometries(); i++) {Geometry g = geom.getGeometryN(i);if (g instanceof Point) {addUniquePointSimple((Point) g, output, uniqueKeys, pointName);}}} else if (geom instanceof GeometryCollection) {for (int i = 0; i < geom.getNumGeometries(); i++) {processIntersectionsSimple(geom.getGeometryN(i), output,uniqueKeys, pointName);}}
}

3、去重后的结果

        最后来调用一下去重之后的道路相交点代码,并返回最后的计算结果信息。主要的去重调用代码如下:

public static void main(String[] args) throws Exception {// 1. 加载OSM道路shp文件File shpFile = new File("F:/vector_data/2024年OSM长沙路网/长沙路网OSM2024.shp");SimpleFeatureSource featureSource = loadShapefile(shpFile);// 2. 输入两条道路名称String roadName1 = "听雨路";String roadName2 = "赏月路";// 3. 获取两条道路的所有几何线SimpleFeatureCollection road1Features = filterRoadsByName(featureSource, roadName1);SimpleFeatureCollection road2Features = filterRoadsByName(featureSource, roadName2);// 4. 计算所有相交点Set<Point> intersections = findIntersections(road1Features, road2Features);// 5. 输出结果System.out.println("Found " + intersections.size() + " intersections:");for (Point p : intersections) {System.out.printf("POINT (%.6f %.6f)\n", p.getX(), p.getY());}System.out.println("*******************************");System.out.println("执行冗余计算");//6、去掉可以清理的冗余点intersections = findUniqueIntersectionsSimple(road1Features, road2Features,roadName1,roadName2);System.out.println("Found " + intersections.size() + " intersections:");for (Point p : intersections) {System.out.printf("POINT (%.6f %.6f)\n", p.getX(), p.getY());}
}

        这里对比了执行冗余计算前后的两种相交点的求解,并且将点的经纬度信息进行了打印输入,在IDE中执行完上述代码,可以看到以下的输出:

        可以直观的看到,经过我们的计算之后,最后的相交点就是1个,即第一个点。 输出信息如下:

六月 12, 2025 10:02:58 下午 org.geotools.image.ImageWorker <clinit>
信息: Warp/affine reduction enabled: true
Found 4 intersections:
POINT (112.867947 28.194721)
POINT (112.867948 28.194679)
POINT (112.867790 28.194655)
POINT (112.867791 28.194618)
*******************************
执行冗余计算
0.00017015393031127507331677628510391286908998154103755950927734375
存在容差
0.0000412077662565200070611363958317241440454381518065929412841796875
存在容差
0.00018686000107234120048461945007289841669262386858463287353515625
存在容差
Found 1 intersections:
POINT (112.867947 28.194721)

        基本以上输出是符合我们的预期的,也符合冗余计算的结果要求。 

三、总结

        以上就是本文的主要内容。本次实战将从 GeoTools 的环境搭建入手,详细阐述如何导入和读取道路数据,展示如何对道路几何对象进行解析和操作。接着,重点介绍容差冗余计算的核心算法实现,包括如何设定合理的容差参数,以及如何根据几何计算结果对冗余点进行处理。通过对基于 GeoTools 的道路相交多个点容差冗余计算的实战研究,不仅可以提升道路数据的质量和可用性,还能为后续的地理数据分析和应用奠定坚实的基础。同时,这一过程也展示了 GeoTools 在解决实际 GIS 问题中的强大能力和灵活性,为相关的地理信息开发工作提供了宝贵的实践经验和参考案例。

        未来的展望,在面对复杂多变的道路数据时,本案例可能存在局限性,比如无法充分考虑到不同区域、不同道路类型对容差的差异化要求,容易造成过度简化或冗余点未被有效排除的问题。也期待更多的朋友一起探讨研究。行文仓促,定有不足之处,欢迎各位朋友在评论区批评指正,不胜感激

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/84687.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

android:foregroundServiceType详解

在 Android 中&#xff0c;foregroundServiceType 是用于声明前台服务类型的属性&#xff0c;主要从 Android 10&#xff08;API 29&#xff09;开始引入&#xff0c;并在 Android 11&#xff08;API 30&#xff09;及更高版本 中进一步细化。以下是所有可用的 foregroundServi…

React+Taro 微信小程序做一个页面,背景图需贴手机屏幕最上边覆盖展示

话不多说 直接上图 第一步 import { getSystemInfoSync } from tarojs/taro;第二步 render() {const cardBanner getImageUrlByGlobal(member-merge-bg.png);const { safeArea, statusBarHeight } getSystemInfoSync();const NAV_BAR_HEIGHT 44;const navBarHeight NAV…

从零开始的云计算生活——番外,实战脚本。

目录 题目一&#xff1a;系统信息收集脚本 题目二&#xff1a;用户管理配置脚本 题目三&#xff1a;磁盘空间管理脚本 题目四&#xff1a;网络配置检查脚本 题目五&#xff1a;系统日志分析脚本 题目一&#xff1a;系统信息收集脚本 编写一个脚本名为 collect_system_info…

MySQL基础知识(DDL、DML)

什么是数据库&#xff1f; 数据库&#xff1a;英文为 DataBase&#xff0c;简称DB&#xff0c;它是存储和管理数据的仓库。 注释&#xff1a; 单行注释&#xff1a;-- 注释内容 或 # 注释内容(MySQL特有)多行注释&#xff1a; /* 注释内容 */ 分类 SQL语句根据其功能被分为…

用volatile修饰数组代表什么意思,Java

文章目录 volatile 修饰数组引用的含义volatile 对数组元素无效总结 如何让数组元素也具有 volatile 特性&#xff1f; 当用 volatile 关键字修饰一个数组时&#xff0c;它只保证数组引用的可见性和部分原子性&#xff0c;而不保证数组元素的可见性和原子性。 换句话说&#x…

Ubuntu 24.04 LTS 长期支持版发布:对服务器用户意味着什么?新特性、升级建议与性能影响初探

更多云服务器知识&#xff0c;尽在hostol.com 在服务器运维的广阔世界里&#xff0c;每一次主流操作系统长期支持&#xff08;LTS&#xff09;版本的发布&#xff0c;都无异于一次重要的“时代交替”。它不仅带来了一系列令人瞩目的技术革新&#xff0c;更重要的是&#xff0c…

题目 3241: 蓝桥杯2024年第十五届省赛真题-挖矿

题目 3241: 蓝桥杯2024年第十五届省赛真题-挖矿 时间限制: 3s 内存限制: 512MB 提交: 1267 解决: 224 题目描述 小蓝正在数轴上挖矿&#xff0c;数轴上一共有 n 个矿洞&#xff0c;第 i 个矿洞的坐标为 ai 。小蓝从 0 出发&#xff0c;每次可以向左或向右移动 1 的距离&#xf…

vue3+ts+vite创建的后台管理系统笔记

Vue3+ Vite + Element-Plus + TypeScript 从0到1搭建企业级后台管理系统(前后端开源):参考有来科技学习搭建项目 创建项目bug汇总,知识点src 路径别名配置和tsconfig.json文件报错【这个不配置好,会引起其他页面引用时报错:见--整合 Pinia】:整合 Pinia 【参考-- src 路径…

指针01 day13

十三&#xff1a;指针变量 一&#xff1a;数据类型 ​ 指针类型---------对应处理的数据是指针 (地址)这种数据 ​ 整型类型---------对应处理的数据是整数这种类型 二&#xff1a;定义指针类型的变量 ​ 语法&#xff1a; 基类型&#xff08;1&#xff09; *&#xff08;…

基于深度学习的智能文本生成:从模型到应用

前言 随着人工智能技术的飞速发展&#xff0c;自然语言处理&#xff08;NLP&#xff09;领域取得了显著的进展。其中&#xff0c;智能文本生成技术尤其引人注目。从聊天机器人到内容创作&#xff0c;智能文本生成不仅能够提高效率&#xff0c;还能创造出令人惊叹的内容。本文将…

Oracle业务用户的存储过程个数及行数统计

Oracle业务用户的存储过程个数及行数统计 统计所有业务用户存储过程的个数独立定义的存储过程定义在包里的存储过程统计所有业务用户存储过程的总行数独立定义的存储过程定义在包里的存储过程通过DBA_SOURCE统计类型个数和代码行数📖 对存储过程进行统计主要用到以下三个系统…

多线程安全:核心解决方案全解析

在多线程环境下保证共享变量的线程安全,需解决原子性、可见性、有序性三大问题。以下是核心解决方案及适用场景: 一、同步锁机制(互斥访问) synchronized 关键字 原理:通过 JVM 监视器锁(Monitor)确保同一时间仅一个线程访问临界区。示例:public class Counter {privat…

2025-06-01-Hive 技术及应用介绍

Hive 技术及应用介绍 参考资料 Hive 技术原理Hive 架构及应用介绍Hive - 小海哥哥 de - 博客园https://cwiki.apache.org/confluence/display/Hive/Home(官方文档) Apache Hive 是基于 Hadoop 构建的数据仓库工具&#xff0c;它为海量结构化数据提供类 SQL 的查询能力&#xf…

Python爬虫(52)Scrapy-Redis分布式爬虫架构实战:IP代理池深度集成与跨地域数据采集

目录 一、引言&#xff1a;当爬虫遭遇"地域封锁"二、背景解析&#xff1a;分布式爬虫的两大技术挑战1. 传统Scrapy架构的局限性2. 地域限制的三种典型表现 三、架构设计&#xff1a;Scrapy-Redis 代理池的协同机制1. 分布式架构拓扑图2. 核心组件协同流程 四、技术实…

HashMap真面目

背景 今天数据采集项目碰到一个性能问题&#xff0c;3000多个采集点&#xff0c;每一个采集点每秒送一个数据&#xff0c;接收到数据之后首先需要内存中做缓存&#xff0c;之后有一系列的业务分析处理&#xff0c;所以&#xff0c;对系统性能要求比较高。 最近几天发现服务器…

STM32CubeMX-H7-19-ESP8266通信(中)--单片机控制ESP8266实现TCP地址通信

前言 上篇文章我们已经能够使用串口助手实现esp8266的几种通信&#xff0c;接下来我们使用单片机控制实现。这篇文章会附带教程&#xff0c;增加.c和,.h&#xff0c;把串口和定时器放到对应的编号&#xff0c;然后调用初始化就可以使用了。 先讲解&#xff0c;然后末尾再放源码…

欧盟RED网络安全标准EN 18031-2的要求

欧盟RED网络安全标准EN 18031-2的要求 欧盟RED网络安全标准EN 18031-2的要求 ​ 适用产品范围&#xff1a; 能够处理个人隐私数据的可联网无线电设备。 不具备联网能力的三类无线电设备&#xff1a;玩具、儿童护理类设备、可穿戴类设备。 主要测试与评估内容&#xff1a; EN…

一起了解--CAST函数

CAST函数在SQL中用途广泛&#xff0c;不仅可以转换为数值类型&#xff0c;还可以在多种场景下用于数据类型转换。以下是一些常见的用途和示例&#xff1a; 类型转换 使用CAST函数可以在查询数据库时根据需要调整数据格式或类型 CAST(expression AS target_type) expression …

(50)课71:查看指定 query_id 的 SQL 语句的执行各个阶段的耗时情况 show profile for query query_id;

&#xff08;137&#xff09;查看指定 query_id 的 SQL 语句的执行各个阶段的耗时情况 show profile for query query_id &#xff1a; &#xff08;138&#xff09; 谢谢

AWS中国云的定时任务(AWS EventBridge+AWS Lambda)

问题 最近有一个每天在凌程定时同步数据给第三方系统的需求。需要使用AWS EventBridge和AWS Lambda结合的方式来同步数据给第三方系统。 思路 使用Python的ORM框架(例如&#xff1a;SQLAlchemy)查询到需要同步的数据&#xff0c;然后&#xff0c;使用http客户端&#xff08;…