GDAL能夠支持將KML做爲矢量文件文件讀取,可是須要在編譯的時候添加第三方庫的支持,不然默認的編譯結果是仍是會不識別這種格式。git
查閱官方文檔發現有兩種驅動能夠支持KML:一種驅動名稱是KML,須要Expat庫的支持,這是一個解析XML格式的庫;另外一種驅動名稱是LIBKML,須要LibKML庫的支持,這是google本身的KML讀寫庫。第二種方式支持的功能更多,而且LibKML自己也須要Expat庫的支持。若是兩種驅動都存在,那麼在讀取的時候第二種會覆蓋第一種,也就是採用LIBKML的方式讀取KML。我這裏就是順手把兩種驅動都添加進去了。github
閱讀這篇文章以前須要預先知道GDAL是如何編譯的,可參看《Win64下編譯集成GEOS和Proj4的GDAL》。shell
LibKML的源碼託管在GitHub(可點擊點擊進入)。下載解壓後可在其根目錄找到libkml.sln這個文件,經過這個文件能夠在visual studio中打開,而後直接編譯就能夠了。總結下在編譯過程當中我遇到的問題:app
LibKML的源碼文件夾中已經自帶了其須要的第三方庫,以下圖所示:
dom
LibKML這個靜態庫挺奇怪,只須要包含第三方對應的頭文件便可編譯了,因此若是編譯的時候提示找不到頭文件,能夠本身把包含目錄從新設置一下,以下圖所示。這種問題通常都是包含目錄的相對路徑出錯或者缺失形成的。
ide
在編譯libkmlbase這個庫的file_win32.cc這個文件的時候,提示這段代碼出錯:函數
// Internal to the win32 file class. We need a conversion from string to // LPCWSTR. static std::wstring Str2Wstr(const string& str) { std::wstring wstr(str.length(), L''); std::copy(str.begin(), str.end(), wstr.begin()); return wstr; } // Internal to the win32 file class. We need a conversion from std::wstring to // string. string Wstr2Str(const std::wstring& wstr) { size_t s = wstr.size(); string str(static_cast<int>(s+1), 0); WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), static_cast<int>(s), &str[0], static_cast<int>(s), NULL, NULL); return str; }
出錯的地方在std::wstring wstr(str.length(), L'')這一行,錯誤提示是「error C2137: 空字符常量」。其實就是C/C++沒有定義「空字符常量」,L''這種寫法不太標準,將其改爲L' '就能夠了。同時這段代碼還存在另外一個問題:這段代碼的意思是字符串wstring和字符串string互相轉換,可是很明顯這種寫法是不支持中文字符的。我這裏就將這段代碼替換爲:ui
//改動: //str 與 wstr 的互轉 static std::wstring Str2Wstr(const string& str) { size_t i; std::string curLocale = setlocale(LC_ALL, NULL); setlocale(LC_ALL, "chs"); const char* _source = str.c_str(); size_t _dsize = str.size() + 1; wchar_t* _dest = new wchar_t[_dsize]; wmemset(_dest, 0x0, _dsize); mbstowcs_s(&i, _dest, _dsize, _source, _dsize); std::wstring result = _dest; delete[] _dest; setlocale(LC_ALL, curLocale.c_str()); return result; } string Wstr2Str(const std::wstring& wstr) { size_t i; std::string curLocale = setlocale(LC_ALL, NULL); setlocale(LC_ALL, "chs"); const wchar_t* _source = wstr.c_str(); size_t _dsize = 2 * wstr.size() + 1; char* _dest = new char[_dsize]; memset(_dest, 0x0, _dsize); wcstombs_s(&i, _dest, _dsize, _source, _dsize); std::string result = _dest; delete[] _dest; setlocale(LC_ALL, curLocale.c_str()); return result; }
修改GDAL的編譯配置文件nmake.opt,找到LibKML部分,修改成:google
# Uncomment out the following lines to enable LibKML support. #LIBKML_DIR = C:/Dev/libkml #LIBKML_INCLUDE = -I$(LIBKML_DIR)/src -I$(LIBKML_DIR)/third_party/boost_1_34_1 #LIBKML_LIBRARY = $(LIBKML_DIR)/msvc/Release #LIBKML_LIBS = $(LIBKML_LIBRARY)/libkmlbase.lib \ # $(LIBKML_LIBRARY)/libkmlconvenience.lib \ # $(LIBKML_LIBRARY)/libkmldom.lib \ # $(LIBKML_LIBRARY)/libkmlengine.lib \ # $(LIBKML_LIBRARY)/libkmlregionator.lib \ # $(LIBKML_LIBRARY)/libkmlxsd.lib \ # $(LIBKML_LIBRARY)/minizip_static.lib \ # $(LIBKML_DIR)/third_party\expat.win32/libexpat.lib \ # $(LIBKML_DIR)/third_party\uriparser-0.7.5.win32/release/uriparser.lib \ # $(LIBKML_DIR)/third_party\zlib-1.2.3.win32/lib/minizip.lib \ # $(LIBKML_DIR)/third_party\zlib-1.2.3.win32/lib/zlib.lib LIBKML_DIR = C:/Work/GDALBuild/libkml-master LIBKML_INCLUDE = -I$(LIBKML_DIR)/src -I$(LIBKML_DIR)/third_party/boost_1_34_1 LIBKML_LIBRARY = $(LIBKML_DIR)/x64/Release LIBKML_LIBS = $(LIBKML_LIBRARY)/libkmlbase.lib \ $(LIBKML_LIBRARY)/libkmlconvenience.lib \ $(LIBKML_LIBRARY)/libkmldom.lib \ $(LIBKML_LIBRARY)/libkmlengine.lib \ $(LIBKML_LIBRARY)/libkmlregionator.lib \ $(LIBKML_LIBRARY)/libkmlxsd.lib \ $(LIBKML_DIR)/third_party/zlib-1.2.3/contrib/minizip/x64/Release/minizip_static.lib \ $(EXPAT_DIR)/build/Release/libexpat.lib \ $(LIBKML_DIR)/third_party/uriparser-0.7.5/win32/uriparser.lib \ $(LIBKML_DIR)/third_party\zlib-1.2.3.win32/lib/minizip.lib \ $(LIBKML_DIR)/third_party\zlib-1.2.3.win32/lib/zlib.lib
這裏的目錄設置可能每一個人有點不太同樣,注意不要硬抄根據實際狀況修改下。具體來講LIBKML_DIR定義的一個根目錄,經過這個目錄依次找到:LIBKML_INCLUDE包含的頭文件目錄;LIBKML_LIBRARY依賴的庫文件目錄;LIBKML_LIBS具體的每個lib。
minizip_static.lib這個文件可能沒有直接提供,可是是有源代碼的,能夠本身編譯一下:
libexpat.lib文件也有點不一樣,宏(EXPAT_DIR)來自於Expat部分:
# Uncomment for Expat support (required for KML, GPX and GeoRSS read support). #EXPAT_DIR = "C:\Program Files\Expat 2.0.1" #EXPAT_INCLUDE = -I$(EXPAT_DIR)/source/lib #EXPAT_LIB = $(EXPAT_DIR)/bin/libexpat.lib EXPAT_DIR = "C:\Work\GDALBuild\libexpat-master" EXPAT_INCLUDE = -I$(EXPAT_DIR)/expat/lib EXPAT_LIB = $(EXPAT_DIR)/build/Release/libexpat.lib
這個Expat部分理論上是能夠用third_party中已經編譯好的頭文件和lib的,可是我這裏並無詳細求證,由於我是先配置好Expat再配置LibKML的,Expat是本身編譯的。
在編譯連接GDAL的過程當中,出現了形如「沒法解析的外部符號「這種類型的錯誤,以下所示:
這是因爲LibKML默認工程中包含的文件不全,GDAL在編譯連接的時候找不到實現形成的。只須要搜索沒法解析的函數所在的文件,將其加入到LibKML的工程中,從新編譯LibKML和GDAL就能夠了。我這裏缺失的文件有:
[1] gdal集成kml庫的作法
[2] 解決gdal集成libkml的連接錯誤
[2] std::wstring