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 <qgspointxy.h>
#include <qgsrasterdataprovider.h>

// 读取指定坐标的像素值
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 <qgsrasterrenderer.h>
#include <qgsrastershader.h>
#include <qgsrasterinterface.h>

// 对于单波段栅格设置灰度渲染
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>
	
	<!-- ServerUrl:瓦片服务的 URL 模板,${z}表示缩放级别,${x}和${y}表示瓦片坐标 -->
    <Service name="TMS">
        <!-- <ServerUrl>file:///E:/work/5-QGis/2-doc/testDemo/build/Image/${z}/${x}/${y}.png</ServerUrl> -->
		<!-- <ServerUrl>file:///D:/qtProject/qGisDemo/recv/testDemo/build/Image/${z}/${x}/${y}.png</ServerUrl> -->
		<ServerUrl>file:///D:/qtProject/qGisDemo/qGisTest/image/${z}/${x}/${y}.png</ServerUrl>
		<ImageFormat>image/png</ImageFormat>
    </Service>
	
	<!-- DataWindow:定义瓦片服务的地理范围 -->
    <DataWindow>
		<!-- 坐标范围,通常使用Web Mercator投影的范围 -->
        <UpperLeftX>-180</UpperLeftX>
        <UpperLeftY>85.0521</UpperLeftY>
        <LowerRightY>-85.0472</LowerRightY>
        <LowerRightX>179.995</LowerRightX>
	
		<!-- TileLevel:最大缩放级别,当前级别6级:0->6文件夹 -->
        <TileLevel>6</TileLevel>
		<!-- 表示在 X 轴(横向)方向上的瓦片数量为 2。即当前视图在水平方向上由 2 个瓦片拼接而成。 -->
        <TileCountX>2</TileCountX>
		<!-- 表示在 Y 轴(纵向)方向上的瓦片数量为 1。即当前视图在垂直方向上由 1 个瓦片构成。 -->
        <TileCountY>1</TileCountY>
		<!-- Y轴原点位置,TMS通常为top,XYZ服务可能为bottom -->
        <YOrigin>bottom</YOrigin>
    </DataWindow>
    
	<!-- Projection:坐标系,在线瓦片使用 WGS84 -->
	<!-- <Projection>WGS84</Projection> -->
	<!-- Projection:坐标系,大多数在线瓦片使用 EPSG:3857,qgis使用这个加载不出来报错,需要带上proj.db数据库文件 -->
    <Projection>EPSG:3857</Projection>
	<!-- 瓦片大小,通常为256x256像素 -->
	<BlockSizeX>256</BlockSizeX>
    <BlockSizeY>256</BlockSizeY>
	<!-- 波段数量,RGB为3,包含透明通道为4 -->
    <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_OBJECT
public:
    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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长沙红胖子Qt(技术Q群4597637)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值