zoukankan      html  css  js  c++  java
  • GDAL集成对KML文件的支持

    1. 正文

    GDAL可以支持将KML作为矢量文件文件读取,但是需要在编译的时候添加第三方库的支持,否则默认的编译结果是还是会不识别这种格式。

    查阅官方文档发现有两种驱动可以支持KML:一种驱动名称是KML,需要Expat库的支持,这是一个解析XML格式的库;另一种驱动名称是LIBKML,需要LibKML库的支持,这是google自己的KML读写库。第二种方式支持的功能更多,并且LibKML本身也需要Expat库的支持。如果两种驱动都存在,那么在读取的时候第二种会覆盖第一种,也就是采用LIBKML的方式读取KML。我这里就是顺手把两种驱动都添加进去了。

    阅读这篇文章之前需要预先知道GDAL是如何编译的,可参看《Win64下编译集成GEOS和Proj4的GDAL》

    1.1. 编译LibKML

    LibKML的源码托管在GitHub(可点击点击进入)。下载解压后可在其根目录找到libkml.sln这个文件,通过这个文件可以在visual studio中打开,然后直接编译就可以了。总结下在编译过程中我遇到的问题:

    1.1.1. 第三方库支持

    LibKML的源码文件夹中已经自带了其需要的第三方库,如下图所示:
    image

    LibKML这个静态库挺奇怪,只需要包含第三方对应的头文件即可编译了,所以如果编译的时候提示找不到头文件,可以自己把包含目录重新设置一下,如下图所示。这种问题一般都是包含目录的相对路径出错或者缺失造成的。
    image

    1.1.2. 编译错误

    在编译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互相转换,但是很明显这种写法是不支持中文字符的。我这里就将这段代码替换为:

    //改动:
    //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;
    }
    

    1.2. 配置GDAL

    修改GDAL的编译配置文件nmake.opt,找到LibKML部分,修改为:

    # 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_partyexpat.win32/libexpat.lib 
    #		$(LIBKML_DIR)/third_partyuriparser-0.7.5.win32/release/uriparser.lib 
    #		$(LIBKML_DIR)/third_partyzlib-1.2.3.win32/lib/minizip.lib 
    #		$(LIBKML_DIR)/third_partyzlib-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_partyzlib-1.2.3.win32/lib/minizip.lib 
    		$(LIBKML_DIR)/third_partyzlib-1.2.3.win32/lib/zlib.lib
    

    这里的目录设置可能每个人有点不太一样,注意不要硬抄根据实际情况修改下。具体来说LIBKML_DIR定义的一个根目录,通过这个目录依次找到:LIBKML_INCLUDE包含的头文件目录;LIBKML_LIBRARY依赖的库文件目录;LIBKML_LIBS具体的每一个lib。

    minizip_static.lib这个文件可能没有直接提供,但是是有源代码的,可以自己编译一下:
    image

    libexpat.lib文件也有点不同,宏(EXPAT_DIR)来自于Expat部分:

    # Uncomment for Expat support (required for KML, GPX and GeoRSS read support).
    #EXPAT_DIR = "C:Program FilesExpat 2.0.1"
    #EXPAT_INCLUDE = -I$(EXPAT_DIR)/source/lib
    #EXPAT_LIB = $(EXPAT_DIR)/bin/libexpat.lib
    EXPAT_DIR = "C:WorkGDALBuildlibexpat-master"
    EXPAT_INCLUDE = -I$(EXPAT_DIR)/expat/lib
    EXPAT_LIB = $(EXPAT_DIR)/build/Release/libexpat.lib
    

    这个Expat部分理论上是可以用third_party中已经编译好的头文件和lib的,但是我这里并没有详细求证,因为我是先配置好Expat再配置LibKML的,Expat是自己编译的。

    1.3. 链接问题

    在编译链接GDAL的过程中,出现了形如“无法解析的外部符号“这种类型的错误,如下所示:
    image

    这是由于LibKML默认工程中包含的文件不全,GDAL在编译链接的时候找不到实现造成的。只需要搜索无法解析的函数所在的文件,将其加入到LibKML的工程中,重新编译LibKML和GDAL就可以了。我这里缺失的文件有:

    1. libkmldom工程:xal.h、xal.cc、gx_timeprimitive.h、gx_timeprimitive.cc、gx_tour.h、gx_tour.cc
    2. libkmlbase工程: zip_file.h、zip_file.cc、uri_parser.cc、xml_namespaces.h、xml_namespaces.cc
    3. libkmlengine工程:id_mapper.h、id_mapper.cc、find_xml_namespaces.h、find_xml_namespaces.cc

    2. 参考

    [1] gdal集成kml库的做法
    [2] 解决gdal集成libkml的链接错误
    [2] std::wstring

  • 相关阅读:
    Android记事本05
    Android记事本开发04
    Android记事本开发03
    Android记事本开发02
    Android记事本开发01
    项目目标文档
    利益相关者描述案例
    《软件需求》阅读笔记03
    《软件需求》阅读笔记02
    《软件需求》阅读笔记01
  • 原文地址:https://www.cnblogs.com/charlee44/p/11734920.html
Copyright © 2011-2022 走看看