QGIS开发笔记(四):QgsRasterLayer加载Cesium二维地图的瓦片地图数据到QGIS
若该文为原创文章,转载请注明原文出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/151064600
长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…
Qt开发专栏:三方库开发技术
上一篇:《QGIS开发笔记(三):Windows安装版二次开发环境搭建(下):将QGis融入QtDemo,添加QGis并加载tif遥感图的Demo》
下一篇:敬请期待…
前言
地图引擎加载瓦片地图是基本操作,本篇对qgis添加图片瓦片地图。
Demo
专业名词
波段
波段(Band) 是指栅格数据中具有特定波长范围的信息层,类似于数字图像中的 “通道”。它是栅格数据(尤其是遥感影像)的核心组成部分,不同波段对应地物在不同电磁波谱范围内的反射或辐射特性。
不同波段的电磁波与地物相互作用的方式不同,因此能反映地物的不同特征:
- 单波段灰度:选择单个波段,以黑白灰度显示(如单独查看近红外波段);
- 多波段色彩:将3个不同波段分别映射到红(R)、绿(G)、蓝(B)通道,形成彩色图像(如真彩色、假彩色合成);
- 伪彩色:对单波段数据使用色带渐变显示(如 DEM 的高程渲染)
图层
图层是管理和展示地理数据的核心单元,所有空间数据(如矢量数据、栅格数据、瓦片地图等)都以图层形式加载和处理。QGIS 支持多种类型的图层:
- 矢量图层(Vector Layers)
- 栅格图层(Raster Layers)
- 瓦片图层(Tile Layers)
- 标注图层(Label Layers)
- 网格图层(Grid Layers)
- 三维图层(3D Layers)
- 其他图层
栅格数据
一种以规则网格(像素或像元)形式存储的地理空间数据,每个网格单元(像素)包含一个或多个数值,用于表示连续的地理现象(如地形、温度、植被覆盖等)。QGIS 支持多种栅格格式,常见的包括:
- TIFF/GeoTIFF(.tif/.tiff):最常用的带地理信息的栅格格式,支持多波段、压缩和空间参考。
- JPEG/JPEG2000(.jpg/.jp2):常用于卫星影像或航空照片,压缩率高。
- PNG(.png):支持透明通道,适合作为底图或符号。
- GRID(ArcGIS Grid):ESRI 的栅格格式,由多个文件组成。
- NetCDF(.nc):用于存储气象、海洋等多维栅格数据。
- HDF(.hdf):常用于遥感数据(如 MODIS、Landsat)。
QgsRasterLayer
概述
QgsRasterLayer是处理栅格数据的核心类,负责加载、显示渲染和操作栅格图层(如卫星影像、DEM 数据、遥感图像等)。
QgsRasterLayer对象通常由QgsProject管理生命周期,添加到项目后不需要手动删除。
QGIS的大部分API不是线程安全的,应避免在非主线程中操作栅格图层。
QgsRasterLayer支持多种栅格格式,具体取决于编译 QGIS 时启用的 GDAL 驱动。
核心功能与特性
- 栅格数据加载:支持多种栅格格式(GeoTIFF、JPEG、PNG、DEM 等),底层通过GDAL库实现格式解析。
- 属性信息获取:可获取图层范围、分辨率、波段数、坐标参考系(CRS)等元数据。
- 像素数据访问:提供接口读取指定坐标或区域的像素值,支持单像素查询和区域数据提取。
- 渲染控制: 支持多种渲染方式(单波段灰度、多波段 RGB、伪彩色等),可自定义颜色映射。
- 项目集成:可添加到QgsProject中进行管理,与地图画布(QgsMapCanvas)联动显示。
常用属性和操作
创建栅格图层
// 栅格文件路径和图层名称QString rasterPath = \"/path/to/your/raster.tif\";QString layerName = \"My Raster Layer\";// 创建栅格图层QgsRasterLayer* rasterLayer = new QgsRasterLayer(rasterPath, layerName);// 检查图层是否有效if (!rasterLayer->isValid()) { qDebug() << \"栅格图层加载失败: \" << rasterLayer->error().message(); delete rasterLayer; return 1;}
获取栅格图层属性信息
// 获取图层范围QgsRectangle extent = rasterLayer->extent();qDebug() << \"图层范围: \" << \"最小X:\" << extent.xMinimum() << \", 最小Y:\" << extent.yMinimum() << \"最大X:\" << extent.xMaximum() << \", 最大Y:\" << extent.yMaximum();// 获取波段数量int bandCount = rasterLayer->bandCount();qDebug() << \"波段数量: \" << bandCount;// 获取坐标参考系QgsCoordinateReferenceSystem crs = rasterLayer->crs();qDebug() << \"坐标参考系: \" << crs.authid() << \" - \" << crs.description();// 获取分辨率double xRes = rasterLayer->rasterUnitsPerPixelX();double yRes = rasterLayer->rasterUnitsPerPixelY();qDebug() << \"分辨率: X=\" << xRes << \", Y=\" << yRes;
读取栅格像素值
#include #include // 读取指定坐标的像素值QgsPointXY point(123456.78, 987654.32); // 地图坐标int bandNumber = 1; // 波段索引(从1开始)bool success = false;double value = rasterLayer->dataProvider()->sample(point, bandNumber, success);if (success){ qDebug() << \"坐标 (\" << point.x() << \", \" << point.y() << \") 的像素值: \" << value;}else{ qDebug() << \"读取像素值失败\";}
设置栅格图层渲染方式
#include #include #include // 对于单波段栅格设置灰度渲染if (bandCount == 1){ // 获取当前渲染器 QgsRasterRenderer* renderer = rasterLayer->renderer(); // 设置渲染范围 renderer->setClassificationMin(0); renderer->setClassificationMax(255); // 触发重绘 rasterLayer->triggerRepaint();}
QGis加载瓦片地图的配置
加载在线XYZ瓦片的XML配置
在线XYZ瓦片的XML配置文件通常用于批量导入多个瓦片服务连接。示例如下:
<qgsXYZTilesConnections version=\"1.0\"> <xyztiles url=\"https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}\" name=\"ESRI 卫星\" authcfg=\"\" password=\"\" http-header:referer=\"https://www.arcgis.com/\" referer=\"https://www.arcgis.com/\" tilePixelRatio=\"1\" zmin=\"1\" username=\"\" zmax=\"20\"/> <xyztiles url=\"https://map.geoq.cn/arcgis/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}\" name=\"ESRI 道路\" authcfg=\"\" password=\"\" http-header:referer=\"http://www.arcgisonline.cn/\" referer=\"http://www.arcgisonline.cn/\" tilePixelRatio=\"1\" zmin=\"1\" username=\"\" zmax=\"19\"/></qgsXYZTilesConnections>
加载离线XYZ瓦片的XML配置
离线瓦片的 XML 配置文件需要遵循 GDAL_WMS 规范,示例如下:
<GDAL_WMS> <Service name=\"TMS\"> <!-- file:///E:/work/5-QGis/2-doc/testDemo/build/Image/${z}/${x}/${y}.png --><!-- file:///D:/qtProject/qGisDemo/recv/testDemo/build/Image/${z}/${x}/${y}.png --><ServerUrl>file:///D:/qtProject/qGisDemo/qGisTest/image/${z}/${x}/${y}.png</ServerUrl><ImageFormat>image/png</ImageFormat> </Service> <DataWindow> <UpperLeftX>-180</UpperLeftX> <UpperLeftY>85.0521</UpperLeftY> <LowerRightY>-85.0472</LowerRightY> <LowerRightX>179.995</LowerRightX> <TileLevel>6</TileLevel> <TileCountX>2</TileCountX> <TileCountY>1</TileCountY> <YOrigin>bottom</YOrigin> </DataWindow> <!-- WGS84 --> <Projection>EPSG:3857</Projection><BlockSizeX>256</BlockSizeX> <BlockSizeY>256</BlockSizeY> <BandsCount>3</BandsCount><Cache><Path>D:/qtProject/qGisDemo/qGisTest/qgis_tiles_cache</Path></Cache></GDAL_WMS>
关于拽托渲染延迟刷新
概述
拖拽地图时不实时刷新、松开后延迟刷新的现象,与地图渲染策略和事件处理机制有关。
- 渲染性能优化机制:QGIS为避免拖拽过程中频繁渲染导致的卡顿,**默认采用“拖拽时暂停渲染,松开后再刷新”的策略。**这是对低性能设备的保护机制,尤其当栅格图层分辨率高、数据量大时,实时渲染会消耗大量CPU/GPU资源。
- 事件处理优先级:拖拽操作(如鼠标拖动QgsMapCanvas)属于高频事件(如mouseMoveEvent)。若在事件触发时立即调用刷新接口(如refresh()或repaint()),会导致事件队列阻塞,反而降低体验。
- 栅格图层的特殊性:栅格数据渲染需要处理大量像素(尤其是大尺寸/高分辨率图层),拖拽时实时重绘可能导致明显延迟,因此框架默认选择延迟刷新。
实时刷新方案一:调整画布刷新策略
// 获取地图画布指针(假设已初始化)QgsMapCanvas* canvas = ...;// 禁用\"拖拽时暂停渲染\"的优化canvas->setParallelRenderingEnabled(true); // 启用并行渲染(多核加速)canvas->setRenderFlag(true); // 强制始终允许渲染// 调整刷新触发方式:在鼠标移动时主动触发刷新connect(canvas, &QgsMapCanvas::extentsChanged, canvas, &QgsMapCanvas::refresh);
实时刷新方案二:优化栅格图层渲染性能
若实时刷新仍卡顿,可降低渲染负载:
// 临时降低栅格图层分辨率(拖拽时)QgsRasterLayer* rasterLayer = ...;rasterLayer->setDrawingStyle(QgsRasterLayer::DrawingStyle::Preview); // 预览模式(低分辨率)// 拖拽结束后恢复高质量渲染// 在鼠标释放事件中:rasterLayer->setDrawingStyle(QgsRasterLayer::DrawingStyle::Default);canvas->refresh();
实时刷新方案三:自定义事件处理通过重写QgsMapCanvas的鼠标事件,控制刷新时机
class CustomMapCanvas : public QgsMapCanvas{ Q_OBJECTpublic: using QgsMapCanvas::QgsMapCanvas;protected: void mouseMoveEvent(QMouseEvent* e) override { // 调用父类方法处理拖拽逻辑 QgsMapCanvas::mouseMoveEvent(e); // 拖拽过程中主动刷新(仅在鼠标按下时) if (e->buttons() & Qt::LeftButton) { this->refresh(); // 实时刷新 } }};
关于图层QGgsProject
经过简单测试,确认画布添加图层,这个QGgsProject里面不添加图层:
这个全局类应该是为了方便一些缓存调用,省的自己管理类,还有一些函数,比如图层是否显示是否包含等等基本操作,还有一个最重要的是项目结束的时候,添加进去的元素项目类实例都会自动销毁,无需手动销毁。
Demo源码
void QGisWidget::test_demo2(QString filePath){ // 步骤一:创建画布 QgsMapCanvas *pMapCanvas = new QgsMapCanvas(); // 启用并行渲染 pMapCanvas->setParallelRenderingEnabled(true); // 强制始终允许渲染 pMapCanvas->setRenderFlag(true); // 步骤二:创建栅格图层 QgsRasterLayer *pLayer = 0; // new的时候就赋值 pLayer = new QgsRasterLayer(filePath); pMapCanvas->setLayers({pLayer}); pMapCanvas->setExtent(pLayer->extent()); pMapCanvas->refresh(); // 步骤三:需要拽托移动,则需要QgsMapToolPan,否则无法移动只能滚轮缩放 QgsMapToolPan *pMapToolPan = new QgsMapToolPan(pMapCanvas); pMapCanvas->setMapTool(pMapToolPan); // 布局初始化 // 注意:这里使用动态创建控件 QHBoxLayout *pHBoxLayout = dynamic_cast<QHBoxLayout *>(this->layout()); if(!pHBoxLayout) { pHBoxLayout = new QHBoxLayout(this); LOG; } pHBoxLayout->addWidget(pMapCanvas, 1); pHBoxLayout->setMargin(0); setLayout(pHBoxLayout);}
工程模板v1.1.0
入坑
入坑一:纵横比显示错误
问题
纵横比显示错误,导致变形
原因
Xml的坐标系范围不对
解决
修正xml配置参数
入坑二:修改坐标系种类后空白
问题
修改坐标系后空表
尝试
确保投影定义使用正确的EPSG代码格式,确认没问题。
打开桌面版QGIS看他支持不:
是支持的。
解决
是数据库.db的问题,部署环境的时候,需要带上:
开发环境的把proj.db带上去,再测试可以了:
上一篇:《QGIS开发笔记(三):Windows安装版二次开发环境搭建(下):将QGis融入QtDemo,添加QGis并加载tif遥感图的Demo》
下一篇:敬请期待…
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/151064600