目錄
前言
一、需求場景及分解
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 在道路網絡分析方面功能的一次全面檢驗,更是為實際的地理空間應用提供了一種可操作的解決方案。通過該項目的實施,我們期望能夠提高地理數據處理的自動化水平,為相關領域的專業人士和開發者提供寶貴的經驗和參考,助力其在各自的實際項目中更好地運用地理空間技術,挖掘地理數據的巨大潛力,解決復雜的現實問題,提升工作效率和決策質量。行文倉促,定有不足之處,歡迎各位朋友在評論區批評指正,不勝感激。