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