一個多月沒有寫博客了,今天嘗試着動筆寫點。html
緣由不少,最重要的緣由是我轉行了。是的,我離開了開發崗位,走向了開發的天敵-產品經理。雖然名義上是產品經理,可是乾的事情也很雜,除了不寫代碼,其餘的都幹,常常還要加個小班,因此就沒那麼多時間研究技術上的東西,機械鍵盤上已經落下了一層薄薄的灰塵。可是本身確實又愛碼農這一行,上班看着同事暢快的敲着代碼,內心就有點癢,因此下班沒事仍舊本身瞎捉摸,這不就總結出來今天這篇文章。python
關於產品經理和研發的關係我還真得多說一句,雖然兩者是天敵,可是一個懂研發的產品經理很容易和研發打交道,相互之間有不少的共同話題,每次項目來的時候我腦海中大概知道如何解決這件事情,甚至我還要幫項目對接的公司解決開發上的問題。。。json
話很少說,開始今天的主題,今天主要介紹如何將 Shp 文件轉爲 GeoJson,這在 QGIS、ArcGIS 等專業軟件中很容易實現,只須要點個按鈕就好了,本文正是來研究這點個按鈕背後發生的故事。本文是在使用 GeoTrellis 中碰到的,因此仍舊納入此博客集中,固然其中的框架等也都是基於 GeoTrellis 的。框架
其實這個過程邏輯上比較簡單,首先將 Shp 文件讀入內存,再分別讀出空間屬性和普通屬性,將兩者組合起來按照 GeoJson 文件的格式寫入便可。學習
只須要一行代碼便可解決:編碼
val datas = ShapeFileReader.readSimpleFeatures(path)
這是 GeoTrellis 封裝好的讀 Shp文件的方法,可是此種方式存在一個問題,沒法設置讀 Shp 文件時的編碼方式,若是 Shp 文件不是 UTF-8 編碼會存在亂碼的問題,簡單改造一下源碼便可實現:scala
val datas = { val file = new File(path) val shpDataStore = new ShapefileDataStore(path.getFileUrl()) shpDataStore.setCharset(Charset.forName(charsetName)) val ftItr = shpDataStore.getFeatureSource.getFeatures.features try { val simpleFeatures = mutable.ListBuffer[SimpleFeature]() while (ftItr.hasNext) simpleFeatures += ftItr.next() simpleFeatures } finally { ftItr.close shpDataStore.dispose() }
這樣就可以讀出 Shp 文件中的全部內容,空間屬性附帶普通屬性,最終是 SimpleFeature 對象的集合。code
所謂 Feature 其實就是空間屬性和普通屬性的結合。htm
def parseAttribute(sf: SimpleFeature) = { import scala.collection.JavaConversions._ sf.getProperties.drop(1).map { p => val attr = sf.getAttribute(p.getName) p.getName.toString -> (if (attr == null) "" else attr.toString) }.toMap } def getGeometryFromSimpleFeature(sf: SimpleFeature) = { val original = sf.getDefaultGeometryProperty.getValue Geometry(original.asInstanceOf[com.vividsolutions.jts.geom.Geometry]) } def toFeature(sf: SimpleFeature) = { Feature(getGeometryFromSimpleFeature(sf), parseAttribute(sf)) }
以上方法能將單個 SimpleFeature 對象轉爲 Feature 對象,整個集合只須要實現一下 map 方法便可。對象
在上一步中,確定有同窗很好奇,爲何要將從 Shp 中讀出的 SimpleFeature 對象轉爲 Feature 對象,緣由就在於有了 Feature 對象,咱們就能夠很簡單的將其轉爲 GeoJson。GeoTrellis 內置了一個將 Feature 集合轉爲 GeoJson 的隱式方法,以下:
implicit class FeaturesToGeoJson[G <: Geometry, D: JsonWriter](features: Traversable[Feature[G, D]]) { def toGeoJson(): String = { JsonFeatureCollection(features).toJson.compactPrint } }
因此能夠直接將第二步中獲得的 Feature 集合轉爲 GeoJson,以下:
import geotrellis.vector.io.json.Implicits._ val geojson = features.toGeoJson()
最後只須要將 geojson 對象寫入文件便可。
以上代碼看上去輕描淡寫,確實我折騰了好長時間才整出來。此處我又要插一句,有不少同窗經過各類方式諮詢我關於 GeoTrellis 使用的問題,我在這裏要作一下聲明:
首先,我知道的基本都毫無保留的寫在博客裏了,關於技術點問我和看個人博客差很少,我但願與你們一塊兒探討實現思路等方面的問題;
其次,就算問我,你是否是也得把問題描述清楚,有些同窗截幾句代碼就要問我爲何跑不通,對不起,首先我不知道你從哪篇文章中截出的,其次我也不知道你要作什麼事情,因此我真的沒法回答;
第三,文章中的代碼都是針對當時 GeoTrellis 版本而言的,你看到的時候可能已經更新了,可能會存在跑不通的狀況,可是通常不存在,而且幾時存在簡單修改一下應該就能夠,而且無需轉牛角尖的問我相似 1TB Tiff 如何處理的問題,個人文章只提供技術方法,不作科學研究。
固然我很是感謝你們對個人認同和支持,這也是我持續寫此博客集的動力之一(之後可能愈來愈少了,產品。。。都是產品惹的禍)。
言歸正傳,當我用 Scala 折騰了幾天出來以後,一拍腦殼,不由要罵本身幾句,爲何我不直接拿 python 實現此功能呢?趕忙研究了一下,發現幾行代碼就搞定:
from geopandas import * shpdata = GeoDataFrame.from_file(path) features = [shpdata.__geo_interface__] from json import dumps geojson = open("demo.json", "w") geojson.write(dumps({"type": "FeatureCollection", \ "features": features}, indent=2) + "\n") geojson.close()
具體思路同上面分析,此處不具體展開,感興趣的能夠自行研究。
就像前面看到的一篇文章中講到的,強大的不是 python 而是庫,是的,一種語言用的人多了,天然庫也就豐富了,而咱們普通人能夠選擇爲本身喜歡的語言貢獻庫,同時咱們也不能死守一種語言,應該具體問題具體分析,找到最適合解決問題的語言,固然每一件事情都是學習的過程,都不會白費。
本文介紹了兩種語言下實現 Shp 轉爲 GeoJson 的方式,主要是分析解決問題的思路。
Geotrellis系列文章連接地址http://www.cnblogs.com/shoufengwei/p/5619419.html