我的開源GIS解決方案之路

GIS兵器庫發表於2021-03-31

好久沒更新了,因為我在--憋--大--招--,對,就是今天這篇。

今天跟大家分享一下我的開源GIS解決方案經歷。

--額-- 考慮到單聊技術解決方案你可能會很快睡著,所以我今天會把重點放在我封裝地圖API這個事情上,以封裝地圖API的經歷為線索,穿插著講一些當時用到的開源GIS架構。

文章稍微有點長,如果你只是想了解一下最新的開源GIS架構,可以直接跳過前面,去看第五版和最後的總結,但我建議你還是從第一版開始看,因為沒有前面的 4 個版本就不會有第五版,只看總結就和讀名言警句效果一樣,看的時候覺得有道理,過後就忘了,因為不能感同身受。

緣起

我一直在傳統IT行業的公司工作,公司都是以做政府專案為主,俗稱toG業務。

這種公司裡,GIS在其中的應用通常為兩種,一種是GIS結合公司的業務形成一個xx地理資訊系統,或是xx一張圖系統,另一種是結合公司業務封裝一套地圖API,為公司的其它業務系統提供地圖技術支撐,類似於高德地圖API、百度地圖API。地圖API的背後通常有一套GIS解決方案作為支撐

今天我們就來聊一聊封裝地圖API這點事。

從我封裝的第一個地圖API版本誕生到現在,已經過去了7年時間,中間經歷了 3 家公司,迭代了 5 個版本。5 個版本中,第 1 個版本使用的ArcGIS,後面 4 個版本主要使用的開源GIS。

第一版 2014年

背景

公司做環保業務,業務系統主要用C#開發,業務系統中涉及地圖的部分使用ArcGIS Flex API開發,由GIS開發人員負責。那個年代,地圖還主要是用Flex開發,因為Flex在那時給人感覺是很炫酷。

隨著專案的增加,發現很多業務功能在專案裡是通用的,再後來發現,如果把業務功能和地圖功能分離,再把Flex編寫的地圖功能封裝一套面向JS的介面,C#開發人員就可以自己完成地圖相關的工作,不用受Flex語言的限制了。

於是我們準備封裝一套用Felx編寫的,面向C#開發人員的JS地圖API。

技術架構

  1. 前臺使用ArcGIS Flex API開發地圖功能,Flex支援和JS互動,利用這一特性將Flex開發的地圖功能,封裝成面向JS的介面。
  2. 地圖後臺使用 ArcGIS Server,空間分析使用 GP 服務。
  3. 空間資料庫使用 Arc SDE。
  4. 開發了一個簡單的幫助網站,提供前臺JS介面的呼叫示例和使用說明。

經驗總結

地圖API釋出後,在做技術支援的過程中發現一個有趣的現象,關於地圖API的使用,完全不懂GIS的初級C#開發人員覺得好用,原因是能幫他們解決問題,有困難時可以隨時找我們技術支援。

瞭解一點GIS的中級C#開發人員覺得不好用,他們會拿我們的地圖API和ArcGIS JS API對比,覺得後者更好用,但由於ArcGIS JS API的地圖偏醜,我們也不提供技術支援,需要他們自己去研究,最終還是選擇用我們的地圖API。

瞭解一點GIS的高階C#開發人員基本不用,其中有兩個同事的反應令我印象深刻,一個同事說:”你們自己開發的東西,自己都不用“。言外之意是,你們自己都不用的東西不會好用。但我們的想法是,把Flex封裝一套JS的地圖介面是因為Flex入門有門檻,我們GIS開發人員既然都會Flex了,而且我們開發的地理資訊系統,整個都是用Flex開發的,那肯定是直接用ArcGIS Flex API會更靈活,所以不用。

還有一個同事更牛,他直接去研究Flex,不會的就問我們,入門後直接封裝了一套地圖介面自己用。我們研究過他封裝的介面,雖然功能簡單了些,但定義介面時的出發點感覺明顯和我們不一樣,我們是站在功能的角度封裝,儘量保證介面的複用度高,比如新增點,新增線,緩衝等功能。他是站在使用者的角度封裝,比如從資料庫查出來一堆資料,把這堆資料直接丟給介面,就在地圖上展示出來了。總體而言,他的介面封裝度更高,更貼近他的實際使用習慣,而我們的介面更像是把ArcGIS的Flex介面翻譯了一套JS的。

還注意到一個現象,經常有使用我們介面的業務開發人員跑過來問,為什麼我的地圖不顯示?經歷的多了,發現通常有兩種原因,一種是地圖服務的地址不對,當時的地圖服務都是用ArcGIS server釋出的,ArcGIS server地圖服務的rest地址是個網頁,這個網頁開啟後,有很多級的連結地址,業務人員不知道應該拷貝哪一級的地址,經常拷錯,所以地圖出不來。另一種是,新增多個地圖時,地圖間的座標不一致,導致新增的地圖不顯示。

想想也是,地圖服務和地圖座標這些知識對於不懂GIS的開發人員來說還是挺難的。

雖然第一版有這樣那樣的問題,但在當時還是提升了部門的整體工作效率。不光是C#開發人員可以自己去開發地圖功能了,GIS組內部也通過這種形式,把分散在各個專案中的技術成果收集了起來,並不斷的積累完善。

第二版 2016年

背景

換公司了,新公司做網安業務,有海量定位資料,GIS在其中的作用是,對定位資料進行提取、分析、展示,從而幫助客戶解決業務問題。

公司的所有系統必須部署在客戶內網,客戶的內網是無法訪問網際網路的,而地圖使用的又是網際網路地圖,這就需要把網際網路地圖瓦片下載下來,拷貝到客戶內網釋出。

公司有一個GIS應用系統,和GIS強關聯的業務功會能放在這裡。另外,其它部門有地圖功能需求時,也會找到我們GIS部門,這個場景和上家公司很像。

所以,二話不說,第二版地圖API走起。

技術架構

  1. 這一版開始使用開源GIS。GIS前臺選擇了openlayers,有了第一版的經驗,這一版重點解決了地圖資源問題,和地圖座標問題。
    1. 解決地圖資源問題。統一管理底圖資源,提供多種網際網路地圖,包括高德地圖、谷歌地圖、天地圖等,每種地圖有個id,初始化地圖時,根據id使用不同的底圖。
    2. 解決地圖座標問題。對外統一使用wgs84座標,地圖API內部負責將wgs84座標轉換為和底圖匹配的座標,包括gcj02座標、bd09座標等。
  2. GIS後臺方面,因為定位資料都存放在大資料框架的資料庫中,後臺只有網際網路離線地圖瓦片需要釋出,所以直接使用了tomcat釋出瓦片,再在openlayers中寫一個載入本地瓦片的功能,這就算GIS後臺了。
  3. 沒有使用空間資料庫,空間分析使用ArcGIS Engine開發控制檯程式,再用Java後臺呼叫控制檯程式。
  4. 介面寫了詳細的說明文件和呼叫示例。沒有做包裝,直接是word文件+html示例檔案。

經驗總結

  1. 解決地圖資源和座標問題,可以大大提升使用者體驗。
  2. 關於地圖下載器,雖然大家都有能力自己寫一個出來,但真的挺不划算的,最好的解決方案就是花公司的錢去買一個許可,站在公司的角度這都沒幾塊錢。
  3. ArcGIS Engine的版本,C#版的比較穩定,Java版的超級難用,非常不穩定,動不動就死給你看,更不要嘗試去把它部署到Linux伺服器,不要問我是怎麼知道的。我當時為了在linux上部署,先開發了一版java的,部署後一天崩潰好幾次,動不動就記憶體溢位,根本沒法用,沒辦法只能重新寫了一版C#的部署在windows伺服器上。

第三版 2017年

背景

換公司了,新公司做管網業務,相比前面兩家,業務和GIS的相關性更強一些,業務中需要對管網GIS資料進行編輯、儲存、釋出和應用。公司之前地圖都是使用ArcGIS開發的,正在準備轉開源GIS,於是我到公司後就順理成章的開始了第三版地圖API的開發。

在開發之前,我先仔細研究了高德和百度地圖API,並問了自己兩個問題:

一、為什麼非GIS開發人員,能夠用高德、百度地圖API解決問題,卻用不了ArcGIS,openlayers,leaflet?

二、非GIS開發人員在用網際網路地圖API時遇到了哪些問題?

下面是我自己的理解:

第一個問題是因為:1、非GIS開發人員不需要自己釋出地圖資料,地圖都是官方提供的,只管用就行。2、網際網路地圖API的幫助文件和示例都是中文的。

第二個問題,我自己嘗試使用後發現:1、網際網路地圖API的離線使用是個問題,它們都只能線上使用,如果遇到不能訪問網際網路的情況,就無法使用了,這問題在toG業務中還是挺常見的。2、網際網路地圖API只能用官方提供的地圖座標,不能整合其它座標的地圖資源。

從這一版起,我們開始嘗試在使用者體驗上對標高德、百度地圖API,學習對方的優點,避免對方的問題。

技術選型

GIS前臺沒有再繼續使用openlayers,而是轉向了更為輕巧的leaflet,當時的考慮是:

  1. leaflet很小巧,核心程式碼結構簡單容易理解,可塑性強,適合拿來改造為自己的API。
  2. leaflet可以同時相容web端和移動端。
  3. 有esri維護的leaflet外掛,能更好的相容公司之前釋出的ArcGIS地圖服務。

GIS後臺選擇了geoserver。因為geoserver的資料比較豐富,能同時支援postGIS和SDE空間資料庫。

GIS空間資料庫選擇了 postGIS,空間分析也主要使用 postGIS 的空間分析函式實現。

桌面端開發繼續使用ArcGIS Engine,沒有去嘗試QGIS,主要原因是,公司之前在ArcGIS Engine上有大量的技術積累,已經形成了成熟的產品,轉換成本會很高。

技術架構

在leaflet的基礎上封裝了一層自己的介面,原生leaflet介面不對外,當時的考慮是:

  1. 和上一版一樣,封裝後容易解決網際網路地圖偏移的問題,對外統一使用wgs84座標,內部根據不同的底圖將資料轉換為對應的座標。
  2. 可以實現類似JQuery那樣的扁平化介面,簡單易用。
  3. leaflet中點的寫法是[緯度,經度],而我們通常更習慣使用[經度,緯度]的寫法,可以通過封裝順便解決這個問題。

當需要複雜的GIS空間分析時,編寫geoserver的擴充套件外掛,外掛連線PostGIS資料庫,通過使用PostGIS空間分析功能,自己編寫函式完成空間分析工作。

基於geoserver的rest介面實現地圖服務的自動釋出。在ArcGIS Engine開發的桌面軟體中,先將GIS資料匯入到空間資料庫,再呼叫geoserver的rest介面釋出地圖,最終實現的效果和ArcGIS釋出地圖的體驗相同。

搭建一個入口網站,內容包括幫助文件、地圖資源、更新說明等,幫助文件以介面為線索,介面內部有介面說明和呼叫事例。地圖資源中提供可以使用的所有地圖,包括網際網路地圖和自己釋出的業務地圖,每個地圖有個id,根據id就可以在API中輕鬆載入地圖,不需要關心地圖服務是如何釋出的。

將PostGIS、geoserver、tomcat全部修改為綠色版本,方便專案部署。

經驗總結

  1. 可以使用SLDEditor軟體解決geoserver不容易配圖的問題。geoserver的配圖不好用,嘗試了在QGIS上配圖,然後釋出到geoserver上,發現QGIS上配圖後生成的sld樣式檔案格式,有很多geoserver都不支援,也不知道是版本沒對應上還是其它原因,最後找了個開源工具SLDEditor來編輯樣式檔案,完美解決問題,但整體的使用體驗跟ArcGIS差很多。
  2. PostGIS的空間分析功能很好用、很強大。所以空間分析功能,我們就主要用PostGIS來實現了,比如之前分享過的圖形緩衝功能
  3. geoserver擴充套件更適合開發和生成地圖服務相關的功能。GIS的空間分析功能一開始通過geoserver擴充套件外掛實現,後來發現擴充套件外掛的後臺程式主要作用是資料傳輸,最主要的分析環節是在空間資料庫PostGIS中實現的,而geoserver的擴充套件開發環境比較複雜,不如自己寫的java後臺好維護。geoserver擴充套件的優勢是可以直接呼叫geoserver的資源和功能,它更適合開發和生成地圖服務相關的功能。

第四版 2019年

背景

開發出第三版後,在部門中使用了一年多,整體反應良好,有一部分懂GIS的同事,之前使用的ArcGIS JS API,用了leaflet封裝的上一版地圖API後,他們的第一反應是這個好輕便,比ArcGIS JS API 小了好多,載入很快。

上一版釋出後,我們留意了使用者的使用習慣,大家的使用習慣基本都是先看示例,找到示例後,會直接把程式碼拷走使用,當示例不完全滿足要求時,再去翻看API說明,最好的情況就是示例程式碼註釋完善,一眼就能看懂,拷過來就能用。

當然在使用的過程中,也慢慢發現了一些問題。

懂GIS的同事反饋最強烈的是,能不能把原生介面放開。有個同事,每次都會先自己在網上找leaflet程式碼,確認能實現了再來找我們,讓我們新增這個功能,甚至把資料連結都發過來了,整的我們都挺不好意思的。如果能把leaflet原生介面放開,有很多工作他自己就能解決了。

然後是我自己,當我需要研究一個新功能時,我的第一反應不是去用我自己封裝的地圖API,而是更願意使用原生leaflet去寫,因為是我覺得自己封裝的地圖API用起來不夠靈活。

天吶!!!

這不就和第一版時,同事說:”你們自己開發的東西,自己都不用”,是一樣一樣的嘛,如果說第一版時還有Flex語言的因素,那這第三版從內到外都是JS寫的,沒什麼好解釋的,就是讓人家說中了。

我們平時的工作,除了封裝地圖API,我們還有其它工作要做,上一版中,感覺我們很大一部分精力被消耗在了封裝基礎功能這件事上,導致沒有時間去研究高階地圖功能。如果能把原始介面放開,基礎功能就可以直接使用原生介面,我們就有更多時間去研究高階地圖功能。

能不能放開原生介面?

要放開原生介面面臨幾個問題:

  1. 地圖座標偏移問題。
    之前通過封裝,在對外介面和地圖之間構建了一個座標適配層,解決了座標偏移問題。如果放開原生介面,就沒有辦法再使用這方式,需要想其它辦法。
  2. 使用者使用習慣問題。
    不懂GIS的使用者會不會習慣了扁平化介面,放開後覺得原生介面不好理解?leaflet中點的寫法是[緯度,經度],和平時使用的[經度,緯度]不同,會不會有人適應不了?
  3. 版本向前相容問題。
    上一個版本中為了追求介面的極簡性,簡化了很多資料格式型別,如果放開原生介面後,還要相容這些格式將會產生很大的工作量,而且後續每增加一個功能都要考慮相容這類資料的問題。

解決方案:

  1. 針對座標偏移問題。

    有兩個方案,一是給使用者提供一個座標轉換的介面,使用者自己來轉換座標,但這樣對使用者不友好。二是對網際網路地圖瓦片進行糾偏,讓地圖統一座標,不再偏移,這是最理想的,但有技術難點。不過,我們最終還是攻克了技術難點,採用了第二種解決方案,詳見:leaflet中如何優雅的解決百度、高德地圖的偏移問題

  2. 針對使用者習慣問題。

    為什麼百度、高德的地圖API並沒有使用扁平化介面,大家也沒有覺得它們難用?我們研究後得出的結論是:在介面沒有特別複雜的前提下,地圖API如果能做到:能解決使用者問題,bug少,示例豐富,說明文件清晰,大家就會覺得好用。介面是否是扁平化其實不怎麼重要。而且,leaflet的原生介面本身就已經非常簡潔了,單從簡潔性考慮的話,沒必要再封裝。

  3. 針對版本向前相容問題。
    我們決定不對上一個版本相容,讓兩個版本同時保留,慢慢過渡,新專案新產品推薦大家用這一版,老專案我們繼續提供技術支援,但不再做功能升級。這樣經過1、2年後,就能慢慢切換過來。事實證明這個決定是對的,現在已經過去2年多時間,部門裡大部分系統都已經切換都了新版本。

技術架構

技術架構在上一版的基礎上做如下調整:

  1. 放開leaflet原生介面,不再對介面進行封裝,改為以外掛形式進行功能擴充套件。
  2. 整合多種網際網路地圖資源,通過對瓦片糾偏的方式解決它們的座標偏移問題,對外統一使用wgs84座標。
  3. 幫助文件由介面為線索改成以示例為線索,示例中的註釋保證完善清晰,將示例程式碼中用到的方法給出類參考連結。
  4. 將leaflet的類參考文件進行翻譯,放到平臺中。
  5. 當有新的功能需求時,簡單的功能不封裝,直接給出示例,複雜的功能再考慮封裝到外掛中。
  6. 和geoserver相關性不強的地圖分析功能,遷移到java後臺,geoserver中只保留和製圖相關的功能。

經驗總結

  1. leaflet類參考的翻譯工作沒做好,一共沒翻譯幾頁,但奇怪的是大家從來沒有抱怨過這個問題。後來觀察發現,使用者基本不看文件,更多的是看示例,示例沒有的,會直接問我們,文件其實只有我們在看(捂臉)。
  2. 有人問問題時,儘量以示例的方式記錄下來,後續大家在示例中能找到這個問題就不會再問了。
  3. 呼叫示例的名稱目前是文字列表形式,文字畢竟有表達上的侷限性,對比高德、百度地圖API,他們在示例列表的前一步,用動圖的方式直接展示示例的最終效果,這樣更加直觀容易理解。
  4. 要儘量通過工具,讓平臺的維護變得簡單,太複雜自己就不愛維護,最後平臺容易廢掉。

第五版 2021年

背景

這一版還沒有完成,年前剛做完技術預研工作,這裡先把整體的思路簡單和大家分享一下。

總的來說,上一版已經很好用了,現在已經很少有來自使用者的負面反饋。產品還曾在大專案中作為技術中臺,提供給其他公司使用,同樣效果很好。

但我們自己還是有追求的,和高德、百度地圖API相比,我們在下面幾點上還需要改進:

  1. 地圖美觀度問題。
    地圖的底圖目前都是使用網際網路地圖瓦片,疊加上業務資料後,會遮蓋底圖中的註記,業務資料間的註記也不容易實現自動避讓,再加上沒有好用的地圖配圖工具,導致地圖在展示多樣資料時就會顯得很亂、很醜。
  2. 展示效能問題。
    地圖有時需要一些動畫效果,比如用動畫效果表達管網中水的流動方向和快慢,在資料量較大時會出現明顯的卡頓。
  3. 地圖配圖問題。
    geoserver配圖不好用,這個問題前面已經提到過,雖然使用SLDEditor可以生成配色檔案,但一次只能生成一個圖層,沒有辦法整體預覽,效率太低,體驗太差。高德、百度地圖的自定義地圖配圖工具就很好用,美工可以直接上手,眼饞很久了。

這一版的目標是解決上面3個問題,並繼續優化使用者體驗。

技術選型

前臺改為使用mapboxgl,不再使用leaflet,原因有兩個:

  1. 效能。leaflet的上限在10萬左右(詳見:leaflet如何載入10萬資料),而mapboxgl基於webgl技術開發,最大資料量取決於顯示卡效能和網路傳輸速度,理想情況下可以輕鬆達到百萬級別。
  2. 美觀度。mapboxgl對向量瓦片支援特別好,再結合maputnik可以輕鬆實現高德、百度地圖的自定義地圖功能。

地圖配圖使用maputnik,業務資料使用geoserver釋出向量瓦片,正常maputnik是不支援geoserver釋出的向量瓦片的,不過我們已經把這個問題解決了,詳見:如何讓向量瓦片配圖神器maputnik支援 geoserver

底圖資料有兩種方案:

  1. 繼續使用網際網路地圖柵格瓦片,適合對底圖資料準確性要求較高的情況。
  2. 在本地釋出OSM向量瓦片地圖,目前網上沒有可以直接使用的免費向量瓦片資源,只能自己把OSM資料下載到本地自己釋出。OSM地圖在國內的資料質量比較差,如果你的業務對底圖資料的準確性要求不高,對樣式要求比較高,比如大屏展示系統,可以選用這個方案。具體方法詳見: 如何實現OSM地圖本地釋出並自定義配圖

地圖視覺化效果使用deck.gl、L7來實現。

經驗總結

  1. 使用maputnik同時載入geoserver釋出的業務圖層和本地釋出的OSM底圖,可以實現業務資料和底圖的深度融合,比如把業務資料中的河流放到底圖道路圖層的下方,並實現標籤的自動避讓功能,類似這樣的體驗還是非常爽的。
  2. OSM地圖的合規性存疑,建議自行將中國的國界線校準一遍再用。

後續展望

  1. 解決OSM地圖資料量少的問題。

    第五版解決方案有一點不完美的地方是,OSM地圖在國內的資料量較少,這也是在我年初的Flag中,想要通過機器學習自動提取建築物輪廓的起因。

  2. 研究三維GIS。

    之前的工作一直是二維GIS,三維GIS的業務比較少,也研究了cesium、ArcGIS js API 4.x、three.js 等,並在專案上有過使用,但對三維GIS的整體理解還是不像二維GIS那樣通透,不能像二維GIS那樣信心十足的給出一個自己滿意的開源解決方案,所以在這塊兒需要繼續努力。

總結

關於地圖API

在toG業務的公司中,想要通過開源GIS,打造一套在易用性上比肩高德、百度地圖的API,需要注意以下幾點:

  1. 解決地圖資源問題。把網上的地圖資源整理好,把專案上的業務地圖資源整理好,對外讓使用者可以直接使用。
  2. 解決地圖座標系問題。要搞定網際網路地圖的偏移問題,和多種地圖座標間的轉換問題,對外讓使用者只使用一種座標。
  3. 基礎地圖功能通過使用者教育的方式實現,也就是提供完善的呼叫示例和說明文件。高階地圖功能通過封裝外掛的方式實現,這樣可以避免隨著時間的推延,核心API越來越冗餘。
  4. 場景豐富的、可以直接使用的呼叫示例,比介面是否簡介、文件是否詳細更重要。
  5. 使用者覺得地圖API是否好用的影像因素,從高到低排序:能不能解決問題、有沒有bug、有沒有豐富的示例、技術支援是否到位、文件是否清晰。
  6. 己所不欲勿施於人。找一個真實的業務場景去使用自己的API,並不斷的從中發現問題,解決問題,完善功能,直到自己覺得非常好用為止,這樣可以強迫自己站在使用者的角度去思考問題。如果自己都不願意去用,那就肯定是不好用,最終不會走的長遠。
  7. 要做好技術支援工作。開發地圖API需要一個長期的、持續迭代的過程,這個過程中難免有這樣那樣的問題,如果你的使用者支援好,它能幫你彌補那些問題給使用者帶來的不好體驗。
  8. 學會通過工具提高平臺維護效率。多去想想平臺維護的過程中,哪些環節可以通過自動化或半自動的方式完成,比如生成文件環節、更新部署環節等,節省了時間好去研究更深層次的東西。

關於開源GIS解決方案

下面是我推薦的兩種組合方案,其實都是前面提到過的,這裡彙總一下。

輕量版:leaflet + geoserver + postGIS

這個組合網上的資料多,軟體簡單易用,普適性強,能滿足絕大多數人對二維GIS的需求。

向量瓦片版:mapboxgl + maputnik + geoserver + postGIS + openmaptiles + three.js

這個組合可以搭建出一套類似高德、百度地圖的自定義地圖,也可以實現白模三維地圖,如果你比較看重地圖視覺化效果,那麼推薦你使用這一套。



好了,就到這裡吧。如果覺得對你有幫助,可以通過持續關注和多多分享來支援我們。


原文地址:http://gisarmory.xyz/blog/index.html?blog=GISerSolution

關注《GIS兵器庫》, 第一時間獲得更多高質量GIS文章。

本文章採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名《GIS兵器庫》(包含連結:  http://gisarmory.xyz/blog/),不得用於商業目的,基於本文修改後的作品務必以相同的許可釋出。

相關文章