目录
前言
一、关于道路相交
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、冗余距离计算
这里介绍一种基于冗余距离的计算方法,将四个交点合并成一个交点信息。基于冗余距离的计算方法可以描述为如下文字:
假设道路在同一个交叉点有四个交点:
第一个点被添加到结果集和空间索引
后续三个点距离第一个点很近(< 阈值)
每个后续点都会与第一个点进行距离比较
距离小于阈值,被视为重复点而跳过
最终结果集中只保留第一个点
使用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 问题中的强大能力和灵活性,为相关的地理信息开发工作提供了宝贵的实践经验和参考案例。
未来的展望,在面对复杂多变的道路数据时,本案例可能存在局限性,比如无法充分考虑到不同区域、不同道路类型对容差的差异化要求,容易造成过度简化或冗余点未被有效排除的问题。也期待更多的朋友一起探讨研究。行文仓促,定有不足之处,欢迎各位朋友在评论区批评指正,不胜感激