基于Geotools的两条道路相交并根据交点形成新路线实战-以OSM数据为例

目录

前言

一、需求场景及分解

1、需求场景

2、需求应用

二、需求实现

1、加载路网数据

2、获取道路信息

3、相交点求解

4、生成新道路

5、结果可视化

三、总结


前言

        在当今数字化迅速发展的时代,地理空间数据的处理与分析已成为众多领域不可或缺的关键技术。从城市规划到智能交通,从环境监测到物流配送,精准且高效的地理数据操作直接影响着决策的科学性和方案的可行性。OpenStreetMap(OSM)作为全球广泛使用的开源地理数据平台,蕴含着海量的道路、建筑、地形等信息,为各类地理空间应用奠定了坚实的数据基础。然而,如何从这些纷繁复杂的 OSM 数据中提取有价值的信息,并进行深入的空间分析,是一个备受关注且极具挑战性的课题。

        道路网络分析作为地理信息系统(GIS)中的核心内容之一,尤其是处理道路相交问题以及基于交点构建新路线的任务,既具有高度的实用性,又蕴含着复杂的空间几何与拓扑关系。在实际场景中,例如交通流量优化、应急救援路径规划、公共交通线路设计等,都需要准确地识别道路相交点,并依据这些交点合理地重组路线,以满足特定的需求和目标。Geotools 作为一款功能强大的开源 GIS 工具库,为 Java 开发者提供了丰富的地理数据处理和空间分析能力。它不仅支持多种地理数据格式的读取与写入,还具备强大的几何运算、空间查询以及拓扑关系构建等功能,为解决复杂的地理空间问题提供了有力的工具。

        本实战项目旨在深入探索如何基于 Geotools,充分利用 OSM 数据的丰富性与开放性,实现两条道路相交的精确检测,并根据相交点构建出符合需求的新路线。这不仅是对 Geotools 在道路网络分析方面功能的一次全面检验,更是为实际的地理空间应用提供了一种可操作的解决方案。通过该项目的实施,我们期望能够提高地理数据处理的自动化水平,为相关领域的专业人士和开发者提供宝贵的经验和参考,助力其在各自的实际项目中更好地运用地理空间技术,挖掘地理数据的巨大潜力,解决复杂的现实问题,提升工作效率和决策质量。

一、需求场景及分解

        本节将从需求场景和应用两个角度来介绍一下道路相交点的一些基本知识。作为业务知识让大家对需求有一定的了解。在生活当中,我们可能对两条道路进行相交求解后,还要求根据交点,求解按照交点连接而成的新路线,因此有必要深入的来讲解一下这些基础知识。

1、需求场景

        在交通规划与管理领域,道路相交求解和合成新路线具有至关重要的作用。随着城市化进程的加速,城市交通网络日益复杂,准确地求解道路相交点并构建合理的新路线,对于优化交通流量、缓解拥堵、提高道路通行效率等方面起着关键的支撑作用。从城市规划的角度来看,新建的道路往往需要与现有的道路网络相连接,这就涉及到确定道路之间的相交点,并基于这些交点合理规划新路线,以确保交通的顺畅衔接。例如,在城市新区的开发中,规划部门需要根据土地利用规划和交通需求预测,设计新的道路布局,并通过道路相交求解和路线合成技术,生成科学合理的道路网络方案,保障居民的出行便利和城市的可持续发展。在智能交通系统中,实时的交通信息采集与处理对道路相交求解和新路线合成有着迫切的需求。通过在道路上安装的传感器和监控设备,能够获取车辆的位置、速度等信息,利用这些数据可以实时判断车辆行驶路线与其它道路的相交情况,进而为车辆提供最优的行驶路线建议,实现交通诱导和路径优化,减少交通事故的发生,提高道路资源的利用率。对于物流配送行业而言,高效的货物运输路线规划离不开道路相交求解和新路线合成技术。物流企业的车辆需要在复杂的道路网络中快速、准确地到达目的地,通过对道路相交点的精确计算和路线的智能合成,可以为物流车辆规划出最短路径、避开拥堵路段,从而降低运输成本,提高配送效率,增强企业的竞争力。

2、需求应用

        在交通工程领域,道路相交求解和新路线合成技术被广泛应用于交通设施的设计与优化。在设计立交桥、交通环岛等交通设施时,准确地确定道路相交点的位置和角度,是确保交通设施合理布局和高效运行的基础。通过合成优化后的路线,可以引导车辆顺畅地通过交通设施,减少车辆的交织和冲突,提高道路的安全性和通行能力。在导航软件的开发中,这一技术的应用更是不可或缺。导航软件需要对大量的道路数据进行处理和分析,快速准确地求解道路相交点,并根据实时的交通状况和用户的出行需求,合成出最佳的行驶路线。例如,高德地图、百度地图等导航软件,正是基于精确的道路相交求解和路线合成算法,为用户提供了一个个准确、实时的导航服务,使用户能够方便快捷地到达目的地,同时也推动了移动互联网应用的快速发展。在应急救援领域,道路相交求解和新路线合成技术发挥着至关重要的作用。在发生自然灾害、交通事故等紧急情况时,救援人员需要迅速到达事故现场。通过对道路相交点的快速判断和路线的合理合成,可以为救援车辆规划出最短、最快的救援路线,争取宝贵的救援时间,提高救援效率,保障人民生命财产安全。此外,在智能驾驶技术的研发中,道路相交求解和新路线合成也是关键的技术环节。智能驾驶车辆需要具备对复杂道路环境的感知和理解能力,能够实时判断与其它道路的相交情况,并根据交通规则和行驶条件,自主地合成出安全、合理的行驶路线,实现自动驾驶功能,这对于推动智能驾驶技术的商业化应用和未来交通运输的智能化发展具有深远的意义。

二、需求实现

        了解了大致的需求之后,接下来我们就围绕着这个需求使用Geotoools来进行实现。要想实现根据道路相交点的打断再生成新路线的需求,需要进行以下的步骤,从路网数据到生成结果基本包含:加载路网、查找道路信息、相交点求解、根据交点生成新道路以及对新道路数据的结果进行可视化。通过这个过程,希望大家对整个技术实现过程有一个完整的理解和掌握。当然如果有兴趣也可以跟着博文来进行重现,如有问题请及时在评论区留言。

        实现需求的基本步骤和技术实现路径如下:

在GeoTools中,基于SHP格式路网数据,求两条道路的相交点,按以下步骤进行:

1. 读取SHP文件,获取道路的FeatureCollection。

2. 从FeatureCollection中提取出两条道路(假设我们通过某个属性或索引选定两条道路)。

3. 将两条道路的几何对象(LineString)进行求交操作。

4. 由于两条线相交可能得到多个交点(例如交叉路口),我们需要获取所有的交点。

注意:两条道路相交,我们期望得到点(Point)或者多点(MultiPoint)。但是,如果两条道路有重叠部分,则可能会返回线(LineString)或多线(MultiLineString)。但通常我们只关心点相交。

使用GeoTools的几何运算工具,可以使用`Intersection`函数,然后判断返回的几何类型。

步骤:

1. 读取SHP文件。

2. 选择两条道路(这里假设我们通过属性选择,或者直接取两个Feature)。

3. 获取两条道路的几何对象(Geometry),这里应该是LineString(或MultiLineString,但通常道路是LineString)。

4. 使用`intersection`方法求交。

5. 检查返回的几何类型:

- 如果是Point,则直接得到交点。

- 如果是MultiPoint,则优先获取第一个(简化操作)。

- 如果是LineString或MultiLineString,则说明有重叠部分,但通常我们不考虑这种情况,或者根据需求处理。但是,注意:两条线相交通常返回的是点,但如果没有相交则返回空几何(Empty Geometry)。另外,由于浮点精度问题,可能需要使用精度模型(PrecisionModel)来确保交点的准确性。

1、加载路网数据

        要想实现对OSM路网数据点的求解,首先我们需要加载整个OSM的shp格式的数据。加载的路网数据的关键代码如下:

// 1. 加载路网数据
File shpFile = new File("F:/vector_data/2024年OSM长沙路网/长沙路网OSM2024.shp");
ShapefileDataStore store = new ShapefileDataStore(shpFile.toURI().toURL());
store.setCharset(Charset.forName("GBK"));//设置中文字符编码7      
SimpleFeatureSource featureSource = store.getFeatureSource();
SimpleFeatureCollection features = featureSource.getFeatures();

2、获取道路信息

        为了实现在很多的OSM路网信息中快速的找到对应的道路线对象,我们需要进行数据的查询,这里将数据查询封装的方法给出源代码(这里是根据道路的OSMID来确定,实际情况下可以根据其它已知的属性来提取,都是可以的),供参考:

// 按属性获取道路几何对象
private static Geometry getRoadGeometry(SimpleFeatureCollection features, String attribute, Object value) {try (SimpleFeatureIterator it = features.features()) {while (it.hasNext()) {SimpleFeature feature = it.next();if (value.equals(feature.getAttribute(attribute))) {return (Geometry) feature.getDefaultGeometry();}}}throw new IllegalArgumentException("未找到指定道路");
}

         在查找源道路的时候,我们使用道路的OSMID作为属性查询的条件,实际情况的查询肯定比这种场景复杂,这里不考虑太复杂的情况。由于需求求解两条路的相交点,因此我们需要找到两条路的OSMID(如果有不会的,可以使用Qgis软件使用属性查看器来进行查找关键的点),查找属性值如下:

// 2. 选择两条要连接的道路(实际应用中可能需要根据ID或其他属性选择)
Geometry road1 = getRoadGeometry(features, "osm_id", "538532552");
Geometry road2 = getRoadGeometry(features, "osm_id", "538532558");

3、相交点求解

        找到两条道路了之后,接下来就需要根据两条道路来求解他们的交点,当然这里需要考虑有多条道路的情况,关于如何处理,大家可以看看之前的博客。这里使用一种粗暴的方法,直接只取第一个。核心处理方法如下:

// 查找两条道路的相交点
private static Point findIntersectionPoint(Geometry road1, Geometry road2) {// 处理可能的拓扑错误double snapTolerance = 0.000001;Geometry [] snappedRoad1 = GeometrySnapper.snap(road1, road2, snapTolerance);// 计算交点 ,这里演示一个,有可能有多个Geometry intersection = snappedRoad1[0].intersection(road2);if (intersection instanceof Point) {return (Point) intersection;} else if (intersection instanceof MultiPoint && intersection.getNumGeometries() > 0) {return (Point) intersection.getGeometryN(0);}throw new IllegalStateException("道路未相交或相交点不是点类型");
}

        可以看到,如果当前的返回点是多个的话,则默认返回相交的第一个点,关键代码如下:

else if (intersection instanceof MultiPoint && intersection.getNumGeometries() > 0) {return (Point) intersection.getGeometryN(0);
}

        传入之前得到的道路信息,进行相交点求解,调用核心方法如下:

// 3. 找到两条道路的相交点
Point intersection = findIntersectionPoint(road1, road2);

4、生成新道路

        有了路线,也经过计算得到相交点之后,下面就可以根据交点和原始的道路来生成新道路。新道路的生成关键就是需要对道路进行切断和拼接。最后就可以生成生成新的道路。关键的处理代码如下:

 // 在相交点处连接两条道路private static LineString connectRoadsAtIntersection(Geometry road1, Geometry road2, Point intersection) {// 创建索引线以便分割道路MultiLineString mline1 = (MultiLineString)road1;MultiLineString mline2 = (MultiLineString)road2;LengthIndexedLine indexedRoad1 = new LengthIndexedLine((LineString) mline1.getGeometryN(0));LengthIndexedLine indexedRoad2 = new LengthIndexedLine((LineString) mline2.getGeometryN(0));// 获取相交点在两条道路上的位置double position1 = indexedRoad1.project(intersection.getCoordinate());double position2 = indexedRoad2.project(intersection.getCoordinate());// 从道路1的起点到相交点Geometry road1Part = indexedRoad1.extractLine(0, position1);// 从相交点到道路2的终点Geometry road2Part = indexedRoad2.extractLine(position2, indexedRoad2.getEndIndex());// 合并两个部分形成新道路Coordinate[] coords1 = road1Part.getCoordinates();Coordinate[] coords2 = road2Part.getCoordinates(); // 创建新坐标数组(跳过重复的相交点)Coordinate[] newCoords = new Coordinate[coords1.length + coords2.length - 1];System.arraycopy(coords1, 0, newCoords, 0, coords1.length);System.arraycopy(coords2, 1, newCoords, coords1.length, coords2.length - 1);// 确保连接点精确使用相交点坐标newCoords[coords1.length - 1] = intersection.getCoordinate(); return new GeometryFactory().createLineString(newCoords);
}

        调用代码如下:

// 4. 在相交点处连接两条道路
LineString newRoad = connectRoadsAtIntersection(road1, road2, intersection);

5、结果可视化

        已知原始的路网数据,然后也根据道路信息求解出相交点和连接新交点的道路。那么接下来就是把生成的结果进行可视化。想要实现OSM路网数据和新道路的展示效果,这里采用原生自带的Swing方式即可。在对结果进行可视化之前,还需要创建道路的临时样式才能展示。首先第一步是创建一个内存图层layer,关键代码如下:

// 创建内存图层
private static Layer createMemoryLayer(Geometry geometry, String name, Color color, float width) {SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();typeBuilder.setName("GeometryFeature");typeBuilder.add("geometry", geometry.getClass());SimpleFeatureType featureType = typeBuilder.buildFeatureType();SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);DefaultFeatureCollection featureCollection = new DefaultFeatureCollection();featureBuilder.add(geometry);SimpleFeature feature = featureBuilder.buildFeature(null);featureCollection.add(feature); Style style = SLD.createLineStyle(color, width);if (geometry instanceof Point) {style = SLD.createPointStyle("Circle", color, color, 1.0f, width);}return new FeatureLayer(featureCollection, style);
}

        然后对前面的道路、相交点和新连接数据进行可视化,核心方法如下:

// 可视化结果
private static void visualizeResults(SimpleFeatureSource roads, Geometry road1, Geometry road2,Point intersection, LineString newRoad) {// 创建地图内容MapContent map = new MapContent();map.setTitle("道路连接结果");// 添加原始路网SLD的方式Style roadStyle = null;try {roadStyle = createStyleFromSld("D:/road_intersection.sld");} catch (Exception e) {}map.addLayer(new FeatureLayer(roads, roadStyle));// 添加第一条道路(蓝色)Layer layer1 = createMemoryLayer(road1, "道路1", Color.BLUE, 3.0f);map.addLayer(layer1);// 添加第二条道路(绿色)Layer layer2 = createMemoryLayer(road2, "道路2", Color.GREEN, 3.0f);map.addLayer(layer2);// 添加相交点(红色)Layer intersectionLayer = createMemoryLayer(intersection, "相交点", Color.RED, 8.0f);map.addLayer(intersectionLayer);// 添加新道路(紫色粗线)Layer newRoadLayer = createMemoryLayer(newRoad, "新道路", new Color(128, 0, 128), 4.0f);map.addLayer(newRoadLayer);// 显示地图JMapFrame.showMap(map);}

        调用渲染展示的代码如下,在最后调用了store的disponse方法进行资源的释放:

// 5. 可视化结果
visualizeResults(featureSource, road1, road2, intersection, newRoad); 
store.dispose();

         经过以上的步骤,就可以运行程序,成功运行后可以看到以下界面,默认的界面如下:

        为了展示得更直观,我们来持续放大地图,可以比较清晰的看到相交点和新的连线信息,放大后的窗口效果如下:

        经过以上步骤,基本达到我们的预期和需求。 

三、总结

        以上就是本文的主要内容,本实战项目旨在深入探索如何基于 Geotools,充分利用 OSM 数据的丰富性与开放性,实现两条道路相交的精确检测,并根据相交点构建出符合需求的新路线。这不仅是对 Geotools 在道路网络分析方面功能的一次全面检验,更是为实际的地理空间应用提供了一种可操作的解决方案。通过该项目的实施,我们期望能够提高地理数据处理的自动化水平,为相关领域的专业人士和开发者提供宝贵的经验和参考,助力其在各自的实际项目中更好地运用地理空间技术,挖掘地理数据的巨大潜力,解决复杂的现实问题,提升工作效率和决策质量。行文仓促,定有不足之处,欢迎各位朋友在评论区批评指正,不胜感激。

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

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

相关文章

goland有基础速通(需要其它编程语言基础)

tip: 无论是变量、方法还是struct的访问权限控制都是通过命名控制的,命名的首字母是大写就相当于java中的public,小写的话就是private,(private只有本包可以访问) 1 go的变量声明 普通变量 特点: 变量类…

量化面试绿皮书:19. 相关系数

文中内容仅限技术学习与代码实践参考,市场存在不确定性,技术分析需谨慎验证,不构成任何投资建议。 19. 相关系数 假设有三个随机变量x、y和z。 x与y之间的相关系数为0.8,x与z之间的相关系数也是0.8。 Q: 那么y与z之间的最大相关…

新生活的开启:从 Trae AI 离开后的三个月

很久没有写文章了,想借着入职新公司一个月的机会,和大家唠唠嗑。 离职 今年2月份我从字节离职了,结束了四年的经历,当时离开的核心原因是觉得加班时间太长了,平均每天都要工作15,16个小时,周末…

LLM部署之vllm vs deepspeed

部署大语言模型(如 Qwen/LLaMA 等)时,vLLM 与 DeepSpeed 是当前主流的两种高性能推理引擎。它们各自专注于不同方向,部署流程也有明显区别。 vLLM 提供极致吞吐、低延迟的推理服务,适用于在线部署;DeepSpeed 更侧重训练与推理混合优化,支持模型并行,适用于推理 + 微调/…

Git(二):基本操作

文章目录 Git(二):基本操作添加文件修改文件版本回退撤销修改情况一:工作区的代码还没有 add情况⼆:已经 add 但没有 commit情况三:已经 add 并且也 commit 删除文件 Git(二):基本操作 添加文件 首先我们先来学习一个…

nginx + ffmpeg 实现 rtsp视频实时播放和历史播放

nginx和ffmpeg 的安装请参考我的另一篇文章 Nginxrtmpffmpeg搭建视频转码服务_nginx-rtmp-module-master-CSDN博客 目录 1、整体方案设计如图 2、nginx下目录创建和配置文件创建 3、创建视频流生成脚本 4、修改nginx配置 5、管理界面 (video.html) 6、ffmpeg后台启动 …

全国产!瑞芯微 RK3576 ARM 八核 2.2GHz 工业核心板—硬件说明书

前 言 本文为创龙科技 SOM-TL3576 工业核心板硬件说明书,主要提供 SOM-TL3576 工业 核心板的产品功能特点、技术参数、引脚定义等内容,以及为用户提供相关电路设计指导。 为便于阅读,下表对文档出现的部分术语进行解释;对于广泛认同释义的术语,在此不做注释。 硬件参考…

web3 浏览器注入 (如 MetaMask)

以下是关于 浏览器注入方式(如 MetaMask) 的完整详解,包括原理、使用方法、安全注意事项及常见问题解决方案: 1. 核心原理 当用户安装 MetaMask 等以太坊钱包扩展时,钱包会向浏览器的 window 对象注入一个全局变量 window.ethereum,这个对象遵循 EIP-1193 标准,提供与区…

解密提示词工程师:AI 时代的新兴职业

大家好!在人工智能飞速发展的当下,有一个新兴职业正悄然崛起——提示词工程师。他们虽不如数据科学家般广为人知,却在 AI 应用领域发挥着独特且关键的作用。 何为提示词工程师? 提示词工程师专注于设计和优化与 AI 模型进行交互的提示词&…

linux 下 jenkins 构建 uniapp node-sass 报错

背景: jenkins 中构建 uniapp 应用 配置: 1. 将windows HbuilderX 插件目录下的 uniapp-cli 文件夹复制到 服务器 /var/jenkins_home/uniapp-cli 2. jenkins 构建步骤增加 执行 shell ,内容如下 echo ">> 构建中..."# 打包前端 export LANGen_US.UTF-8…

QT常见问题(1)

QT常见问题(1) 1.问题描述 Qt在编译器中直接运行没有任何问题,但是进入exe生成目录直接双击运行就报错:文件无法定位程序输入点_zn10qarraydata10deallocateepsyy于动态链接库。 2.问题原因 这个错误通常是由于程序运行时找不…

『大模型笔记』第2篇:并发请求中的 Prefill 与 Decode:优化大语言模型性能

『大模型笔记』并发请求中的 Prefill 与 Decode:优化大语言模型性能 文章目录 一. Token 生成的两个阶段:Prefill 和 Decode1.1. 指标分析1.2. 资源利用率分析二. 并发处理机制2.1. 静态批处理 vs 持续批处理(Static Batching vs. Continuous Batching)2.2. Prefill 优先策略…

JVM(7)——详解标记-整理算法

核心思想 标记-整理算法同样分为两个主要阶段,但第二个阶段有所不同: 标记阶段: 与标记-清除算法完全一致。遍历所有可达对象(从 GC Roots 开始),标记它们为“存活”。 整理阶段: 不再简单地清…

进程虚拟地址空间

1. 程序地址空间回顾 我们在学习语言层面时,会了解到这样的空间布局图,我们先对他进行分区了解: 如果以静态static修饰的变量就会当成已初始化全局变量来看待,存放在已初始化数据区和未初始化数据区之前。 如果不用static修饰test…

C语言学习day17-----位运算

目录 1.位运算 1.1基础知识 1.1.1定义 1.1.2用途 1.1.3软件控制硬件 1.2运算符 1.2.1与 & 1.2.2或 | 1.2.3非 ~ 1.2.4异或 ^ 1.2.5左移 << 1.2.6右移 >> 1.2.7代码实现 1.2.8置0 1.2.9置1 1.2.10不借助第三方变量&#xff0c;实现两个数的交换…

【linux】简单的shell脚本练习

简单易学 解释性语言&#xff0c;不需要编译即可执行 对于一个合格的系统管理员来说&#xff0c;学习和掌握Shell编程是非常重要的&#xff0c;通过shell程序&#xff0c;可以在很大程度上简化日常的维护工作&#xff0c;使得管理员从简单的重复劳动中解脱出来 用户输入任意两…

机构运动分析系统开发(Python实现)

机构运动分析系统开发(Python实现) 一、引言 机构运动分析是机械工程的核心内容,涉及位置、速度和加速度分析。本系统基于Python开发,实现了平面连杆机构的完整运动学分析,包含数学建模、数值计算和可视化功能。 二、系统架构设计 #mermaid-svg-bT8TPKQ98UU9ERet {font…

工程师生活:清除电热水壶(锅)水垢方法

清除电热水壶&#xff08;锅&#xff09;水垢方法 水垢是水加热时自然形成的钙质沉淀物&#xff0c;常粘附在水壶内壁及发热盘上。它不仅影响水的品质&#xff0c;还会缩短水壶的使用寿命&#xff0c;因此需要定期清除。建议根据各地水质不同&#xff0c;每年除垢 2 至 4 次。…

[分布式并行策略] 数据并行 DP/DDP/FSDP/ZeRO

上篇文章【[论文品鉴] DeepSeek V3 最新论文 之 DeepEP】 介绍了分布式并行策略中的EP&#xff0c;简单的提到了其他几种并行策略&#xff0c;但碍于精力和篇幅限制决定将内容分几期&#xff0c;本期首先介绍DP&#xff0c;但并不是因为DP简单&#xff0c;相反DP的水也很深&…

LeeCode144二叉树的前序遍历

项目场景&#xff1a; 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3] 解释&#xff1a; 示例 2&#xff1a; 输入&#xff1a;root [1,2,3,4,5,null,8,null,null,6,7…