目錄
前言
一、關于道路相交
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 問題中的強大能力和靈活性,為相關的地理信息開發工作提供了寶貴的實踐經驗和參考案例。
????????未來的展望,在面對復雜多變的道路數據時,本案例可能存在局限性,比如無法充分考慮到不同區域、不同道路類型對容差的差異化要求,容易造成過度簡化或冗余點未被有效排除的問題。也期待更多的朋友一起探討研究。行文倉促,定有不足之處,歡迎各位朋友在評論區批評指正,不勝感激