ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

QGIS 3.6.1二次开发实战:从环境配置到地图瓦片与PyQGIS脚本

QGIS 3.6.1二次开发实战:从环境配置到地图瓦片与PyQGIS脚本 简介面向需要在QGIS 3.6.1基础上构建插件或集成应用的中高级C开发者这份二次开发包省去自行编译的繁琐流程直接提供可调用的预编译库文件、C头文件、API文档、示例代码与CMake构建脚本并附带PDB调试符号方便在Windows 10 Visual Studio 2015支持C14环境下进行源码级调试。压缩包总大小约69.99MB当前文件总数信息显示为0实际内容以DLL/LIB库文件、.h头文件、示例工程、技术文档及.pdb符号文件为主可按开发流程快速定位所需模块。已有699人学习下载适合已掌握Qt基础、希望深入QGIS二次开发的读者。通过该开发包可快速上手地图渲染、几何操作、空间分析等API结合VS2015调试工具追踪代码执行步骤有效定位错误提升插件或集成项目的开发效率。1. 项目概述QGIS 3.6.1二次开发包到底能拿来做什么1.1 别搞混了这不是安装包是SDK很多人一听二次开发包就以为是双击安装就能用的软件这个认知得先纠正。QGIS 3.6.1二次开发包SDK是一整套用于构建自定义GIS应用的库、头文件、插件框架和脚本接口的集合。你写代码时链接它编译后调用它最终交付的是你完全可控的自研GIS工具而不是一个换了皮肤的QGIS。我见过不少团队在这个环节栽跟头——拿着安装版QGIS就想做二次开发结果连头文件和导入库都找不到。正常做法是要么从源码编译出开发环境要么直接下载官方发布的QGIS SDK或OSGeo4W开发套件。这个包解决了三件事第一把QGIS底层的地理数据读取、坐标转换、渲染引擎封装成可调用的C接口第二提供PyQGIS这样的Python绑定让脚本化处理成为可能第三把插件框架完整暴露出来你可以像给QGIS加器官一样插入自己的功能模块。1.2 为什么拿3.6.1这个版本说事3.6.1发布于2019年初属于3.6系列的一个修订版。按QGIS的发布节奏3.6不是LTR版本3.4才是但在实际开发场景中3.6.1有它特殊的价值它对应的Qt版本是5.11编译标准是C17Python绑定是3.7这几个技术栈组合非常成熟稳定。很多企业至今还在用3.6.x或3.10.x作为内部工具的基础版本因为新版本虽然功能多但API变动频繁。更重要的是3.6.x的API文档和社区沉淀非常完整。无论你现在用C写插件还是用PyQGIS跑脚本踩到坑时搜qgis 3.6 开发基本都有答案。不像最新版本问题刚提出来可能还没人回复。所以用3.6.1做二次开发包来学习、搭框架是一个务实的选择。这个系列适合谁打算给部门做内部GIS工具的开发人员准备用PyQGIS批量处理地理数据的工程师以及想基于QGIS框架构建行业应用水利、规划、农业等的开发者。纯业务用户看完可能会觉得太硬核但你至少能知道原来QGIS还有开发接口这回事。2. 开发包的环境配置与工程搭建2.1 开发包目录结构拿到手先认识这几个文件夹如果你使用OSGeo4W的SDK安装方式或者从源码编译了开发包通常会得到这样一套目录结构bin/存放QGIS.exe、qgis_core.dll、qgis_gui.dll、qgis_analysis.dll等运行时库和可执行文件。这些DLL是二次开发绕不开的底层依赖运行时Path必须指到这里。include/qgis_core.h、qgis_gui.h等头文件。你在代码里写#include qgsapplication.h编译器就是去这里找的。lib/导入库文件。Windows下是qgis_core.lib、qgis_gui.lib等链接阶段需要它们。share/资源文件、插件示例、i18n翻译文件等。配置开发环境时我习惯先建立一个全局环境变量QGIS_PREFIX指向这个根目录后续写CMakeLists.txt会省很多事。2.2 CMake工程配置三步搞定编译环境QGIS的C二次开发基本都走CMake。以下是一个最简可用的CMakeLists.txt适用Windows Visual Studio 2017 Qt 5.11的组合cmake_minimum_required(VERSION 3.10) project(MyQgisPlugin) set(CMAKE_CXX_STANDARD 17) set(QGIS_PREFIX D:/qgis_3_6_1 CACHE PATH QGIS installation prefix) set(QGIS_INCLUDE_DIR ${QGIS_PREFIX}/include) set(QGIS_LIB_DIR ${QGIS_PREFIX}/lib) include_directories(${QGIS_INCLUDE_DIR}) link_directories(${QGIS_LIB_DIR}) find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets) find_package(Qt5 REQUIRED COMPONENTS Xml Concurrent) add_executable(${PROJECT_NAME} main.cpp) target_link_libraries(${PROJECT_NAME} qgis_core qgis_gui qgis_analysis Qt5::Core Qt5::Gui Qt5::Widgets )三个注意点必须把QGIS_PREFIX下面的bin目录加入系统Path否则运行时会提示找不到qgis_core.dll。编译器和Qt编译器版本必须一致。QGIS 3.6.1的MSVC版本是2015/2017你拿2019的编译器去编很可能会因为ABI不兼容炸掉。如果要用到Python插件则要保证Python版本是3.7别用3.8不然PyQGIS的库加载会报版本错。提示这里再补充一个容易忽略的点——Release和Debug必须分开配置不要混用。QGIS官方的开发包大多只发布Release版如果你的程序要用Debug调试推荐装一个Debugs版本的依赖库或者直接用外部进程调试的方式让插件进程中加载你的代码。2.3 验证环境跑一个最基础的QgsApplication写一个最简单的main.cpp验证环境是否通#include QApplication #include QgsApplication int main(int argc, char *argv[]) { QgsApplication app(argc, argv, true); app.setPrefixPath(D:/qgis_3_6_1, true); app.initQgis(); qDebug() QGIS version: QgsApplication::version(); app.exitQgis(); return 0; }这串代码的核心逻辑是创建QgsApplication实例设置前缀路径指向开发包根目录然后初始化GIS环境。如果控制台能正常打印出版本号恭喜你二次开发环境已经通了。3. 核心实战用C开发包加载高德、腾讯、百度地图瓦片3.1 XYZ瓦片图层的底层逻辑现在很多项目都需要在自有GIS工具里叠加互联网底图这就绕不开XYZ Tiles。高德、腾讯、百度等地图厂商的底图本质上都是XYZ瓦片服务——把地图切成256×256的小图块按照层级Zoom、行Y、列X三个参数来拼接。QGIS里加载这种图层的原生方式是XyzLayer在开发包中对应的就是QgsXyzLayer类3.6版本中还有QgsRasterLayer配合providerxyz的方式。理解这个机制的实用价值在于你用二次开发包写一次代码就能同时适配高德、腾讯等多套瓦片源因为它们的URL模板基本是一个套路只是坐标系有差异。3.2 代码实操程序启动就加载高德底图在QGIS二次开发中最常用的方式是通过QgsRasterLayer指定XYZ服务。代码如下#include QgsRasterLayer #include QgsProject void addGaodeMap() { // 高德底图 URL 模板web墨卡托坐标系 QString url http://webrd0{s}.is.autonavi.com/appmaptile? langzh_cnsize1scale1style8 x{x}y{y}z{z}; Q_NOWARN_UNUSED(url); // 占位实际用标准化模板 QString urlTmpl QStringLiteral(https://webrd0{t}.is.autonavi.com/appmaptile?langzh_cnsize1scale1style8x{x}y{y}z{z}); QgsRasterLayer* layer new QgsRasterLayer( QStringLiteral(typexyzurl%1).arg(urlTmpl), QStringLiteral(高德底图), QStringLiteral(wms) // 实际应使用 xyz ); ... }等等我上面的写法有点绕3.6.1实际更推荐直接用xyzprovider#include QgsRasterLayer #include QgsProject #include QStringLiteral void addTianMapLayer() { // 腾讯天地图风格瓦片 QString url https://rt{s}.map.gtimg.com/tile?z{z}x{x}y{y}styleid1; QgsRasterLayer *layer new QgsRasterLayer( typexyzurl url, QStringLiteral(腾讯底图), QStringLiteral(xyz) ); if (layer layer-isValid()) { QgsProject::instance()-addMapLayer(layer); } else { qWarning() 加载失败请检查网络或URL模板; } }这里有几个关键点URL模板中的{s}、{z}、{x}、{y}是占位符QGIS会按规则拉取瓦片。多个子域名可以用{s}随机切换绕开QPS限制。腾讯和高德的瓦片与WGS84经纬度存在偏移。国内厂商的底图用的是加密坐标系你需要在地图加载后设置一个正确的图层CRS或者用在线投影工具做配准。这是二次开发地图叠加项目中最常见的图对不上问题根源。百度地图的坐标是BD09而且切片规则与通用XYZ不同直接用xyz模板会显示错位。正确处理方式有两个一是让百度瓦片叠加在BD09坐标系的工程下QGIS的CRS列表里有EPSG:2385?其实没有需要自定义二是在开发包中写一个URL转换和坐标纠偏算法。这是专门的技术话题本篇不展开但要明确不是QGIS不支持百度而是坐标系协议不同。提示在Windows下跑这个demo时记得开启OpenSSL相关依赖libssl等。因为高德、腾讯的瓦片地址是HTTPS屏蔽或缺少证书会出现加载不出图、控制台报TLS错误的情况。3.3 多源瓦片统一管理做个简单的底图切换器实际项目中你不会只加载一家地图。做一个底图切换菜单是二次开发的入门练习——本质上就是维护一个名称→URL模板映射表切换时移除旧图层、添加新图层。大致逻辑QMapQString, QString tileSources; tileSources[高德] https://webrd0{t}.is.autonavi.com/appmaptile?langzh_cnsize1scale1style8x{x}y{y}z{z}; tileSources[腾讯] https://rt{s}.map.gtimg.com/tile?z{z}x{x}y{y}styleid1; tileSources[天地图] https://t{s}.tianditu.gov.cn/vec_w/wmts?SERVICEWMTSREQUESTGetTileVERSION1.0.0LAYERvecSTYLEdefaultTILEMATRIXSETwFORMATtilesTILEMATRIX{z}TILEROW{y}TILECOL{x}tkYOUR_KEY;这里有个容易被坑的地方天地图和腾讯、高德的瓦片规则略有不同天地图是WMTS切片坐标轴排序是行列与经纬度顺序问题需要开发者先在浏览器里手动验证一个瓦片URL能不能打开再写进代码。4. PyQGIS脚本开发栅格重分类与Shp导出最简方案4.1 开发包里的Python利器QGIS开发包不仅支持C还集成了PyQGIS——一套基于SIP生成的Python绑定。对很多数据处理场景PyQGIS开发效率远高于C。你不必编译直接用系统Python解释器引入qgis.core模块就能调用开发包里的功能import sys from qgis.core import QgsApplication # 3.6.1对应的Python是3.7 QgsApplication.setPrefixPath(D:/qgis_3_6_1, True) qgs QgsApplication([], False) qgs.initQgis()完成这两行初始化你的Python脚本就具备了完整的QGIS计算能力。注意第二个参数传False代表非GUI模式适合服务器端批处理。4.2 栅格重分类从连续值到分级显示栅格重分类是遥感、地形分析中经常要做的操作。比如把DEM高程分成低、中、高三档。QGIS里有现成的栅格计算器和SAGA算法但写脚本时直接用QgsRasterLayer配合QgsRasterCalculator更直观from qgis.core import ( QgsRasterLayer, QgsRasterCalculator, QgsRasterCalculatorEntry ) layer QgsRasterLayer(dem.tif, DEM) entries [] # 假设要把高程按三档划分输出值为1、2、3 formula (DEM1 100) * 1 ((DEM1 100) AND (DEM1 200)) * 2 (DEM1 200) * 3 calc QgsRasterCalculator( formula, dem_reclass.tif, GTiff, layer.extent(), layer.width(), layer.height(), entries ) calc.processCalculation()这段代码写的表达式利用了Python/布尔代数在栅格计算器中转为0和1的特性遇到True就是1遇到False就是0所以能通过叠加多个布尔表达式实现多级分类。实际项目里我一般建议把阈值放到一个配置文件或列表里用循环生成表达式避免硬编码。另外栅格重分类前先确认输入栅格的CRS和范围一致否则计算范围截断会意外报错。4.3 导出Shp文件的最简一条命令很多用户在QGIS界面上点导出要素觉得很简单但在开发场景中你要在脚本里批量导出几百个图层。PyQGIS里最干净的写法是使用QgsVectorFileWriterfrom qgis.core import QgsVectorLayer, QgsVectorFileWriter layer QgsVectorLayer(your_layer.shp, demo, ogr) if layer.isValid(): error QgsVectorFileWriter.writeAsVectorFormatV2( layer, output.shp, layer.transformContext(), layer.sourceCrs(), UTF-8 ) if error[0] QgsVectorFileWriter.NoError: print(导出成功)注意编码参数一定要写UTF-8。我在实际项目中遇到过不少次导出后的shp在ArcGIS里打开中文乱码后来统一在导出参数里强制指定UTF-8才解决。如果你的组织还有老环境在使用GBK也可以手动改成GBK但这是从源头控制尽量统一标准。4.4 小技巧在PyQGIS里组合重分类→导出流水线最爽的开发方式是把上面的重分类和导出连成一个pipeline配合一个简单的文件遍历import os for root, dirs, files in os.walk(data/): for f in files: if f.endswith(.tif): # 重分类 # 导出成果 pass这就是单位小工具的原型。你不用开发完整插件只要在命令行敲python process.py就能一口气处理整个目录的栅格数据。5. 二次开发实战中的高频问题与排查技巧5.1 编译期问题头文件、链接库全对却报一堆语法错误这种情况90%是因为头文件包含顺序搞错。QGIS的C代码依赖Qt的很多预编译宏必须保证#include qgis_core.h在Qt头文件之后或者至少有一个统一入口。我习惯是这样组织的#include QApplication #include QtCore #include qgsapplication.h #include qgsrasterlayer.h如果到处乱include很容易报undefined symbol或者Q_OBJECT macro not found但其实根本不是代码逻辑问题。另一个高频是C17编译标准没有开启。3.6.1的源码大量用了std::optional这类C17特性CMake里set(CMAKE_CXX_STANDARD 17)千万别漏。5.2 运行期问题一启动就崩溃定位不到任何有效日志排查顺序我建议这样确认QgsApplication::setPrefixPath第二个参数是否传了true。确认Path环境变量里有没有开发包的bin目录。确认程序是64位编译且与开发包架构一致QGIS 3.6.1官方包基本是64位。看程序崩溃栈如果有QgsProviderRegistry或QgsCoordinateReferenceSystem相关帧多半是资源文件share目录路径不对。对于第二点再补充一下不要在Path里写带空格的目录虽然通常没问题但在某些C三方库里会出现解析异常。路径统一用中文的项目、无空格路径能省很多无谓的折腾。5.3 图层加载失败isValid()返回False这是二次开发里最常见的挫败体验。原因一般有三类Provider缺失比如打开GeoJSON时没有加载ogr plugin。在做headless模式开发时必须把providers、plugins目录下的东西正确复制到开发包的share/qgis目录下否则Provider注册不上。路径问题中文字符在某些编码环境下会导致文件打不开优先用英文路径测试基线。CRS问题有些矢量数据缺少.prj文件QGIS默认会当作未知CRS。处理方式是显式调用layer.setCrs(QgsCoordinateReferenceSystem(EPSG:4326))。5.4 瓦片图层显示不出图网络和TLS是重灾区瓦片加载失败的排查先看代理设置。单位内网如果走代理会让瓦片请求直接失败。QGIS 3.6.1的瓦片加载走Qt网络栈会读系统代理设置但有时Linux下环境变量不生效需要手动设置代理。还有开篇提过的HTTPS证书问题开发包运行时需要找到Qt自带的根证书库如果提示SSL错误就检查一下Qt的cacert.pem路径是否被误删或者直接改用HTTP地址测试连通性。6. 关于开发包版本管理的一个过来人经验最后聊一个很多新手不重视但老手都吃过亏的点开发包版本一定要锁定并把运行依赖一并打包分发。QGIS 3.6.1的DLL依赖链很长涉及Qt 5.11的十几个库、GDAL/OGR、GEOS、Proj等地理基础库。你开发机上的环境没问题不代表部署目标的机器能跑起来。我早期做过一个自动出图工具开发环境里一切正常拷到业务部门的电脑上却直接报缺少proj_6_2.dll后来乖乖把所有运行依赖放到同目录用windeployqt辅助扫描才彻底解决。所以你的二次开发包不仅仅指源码或SDK交付时更准确的说法是QGIS运行时开发库依赖库三件套。前期就把这个打包理顺后续部署省心十倍。我自己现在做项目一律会在工程里放一个deploy_win.bat一键复制依赖、清理Debug残留避免手工操作出错。在QGIS二次开发这条路上C插件和PyQGIS脚本各占半壁江山。C适合做深度定制、重交互的桌面工具PyQGIS适合数据处理、批量自动化。3.6.1这个开发包虽然是几年前的版本但技术栈经典、文档齐全作为学习起点和企业内部工具的基座至今依然能打。动手搭环境时碰到问题欢迎多交流多踩坑多记录GIS开发的路会越走越顺。本文还有配套的精品资源点击获取
返回列表