QGIS 在 Qt 环境下实现地图的无限拖动,双画布叠加实现无限拖动地图实现轮播效果

张开发
2026/6/13 20:39:24 15 分钟阅读

分享文章

QGIS 在 Qt 环境下实现地图的无限拖动,双画布叠加实现无限拖动地图实现轮播效果
*核心原理双画布叠加 (Master-Slave Overlay)传统的 GIS 引擎通常不直接支持平面地图的无限水平循环只有 3D 球体支持。为了实现 2D 平面地图的无限拖动我们采用了 “双层画布 视觉欺骗” 的策略主画布 (mMapCanvas)负责实际的交互点击、拖拽、缩放和主要渲染。永远铺满容器。从画布 (mSlaveCanvas)负责视觉补全。当主画布拖动到世界边缘如经度 180°显示出空白时从画布覆盖在上面显示世界另一端经度 -180°的内容形成无缝衔接的错觉。*初始化双画布 ,同时创建两个画布并设置从画布对鼠标事件透明。voidQGISMapManager::createMapCanvas(){// 1. 创建主画布mMapCanvasnewQgsMapCanvas(mMapContainer);// 2. 创建从画布 (Slave)mSlaveCanvasnewQgsMapCanvas(mMapContainer);// 3. 关键设置点击穿透// 让从画布对鼠标事件透明所有点击/拖拽直接穿透给下方的主画布处理mSlaveCanvas-setAttribute(Qt::WA_TransparentForMouseEvents);// 4. 同步坐标系 (EPSG:3857)QgsCoordinateReferenceSystemmapCrs(EPSG:3857);mMapCanvas-setDestinationCrs(mapCrs);mSlaveCanvas-setDestinationCrs(mapCrs);// 5. 绑定信号同步状态connect(mMapCanvas,QgsMapCanvas::extentsChanged,this,QGISMapManager::checkInfiniteScroll);connect(mMapCanvas,QgsMapCanvas::layersChanged,this,QGISMapManager::updateSlaveCanvasState);}无限轮播逻辑 ,实时计算当前视图是否越界。如果主画布显示到了边缘就移动从画布到合适的位置并使用 setMask 进行裁剪只显示补全的部分。voidQGISMapManager::checkInfiniteScroll(){// 常量Web Mercator 世界宽度constdoubleMIN_X-20037508.342789244;constdoubleMAX_X20037508.342789244;constdoubleWORLD_WMAX_X-MIN_X;QgsRectangle extentmMapCanvas-extent();// 计算越界量doubleoverRightextent.xMaximum()-MAX_X;doubleoverLeftMIN_X-extent.xMinimum();if(overRight0){// 向右越界从画布显示左半球的内容连接到右边QgsRectangle slaveExtentextent;// 将从画布的视野平移一个世界宽度 (向左移)slaveExtent.setXMinimum(extent.xMinimum()-WORLD_W);slaveExtent.setXMaximum(extent.xMaximum()-WORLD_W);mSlaveCanvas-setExtent(slaveExtent);// 计算需要遮罩的像素宽度intpixelWidthcalculatePixelWidth(overRight);// 关键使用 Mask 只显示右侧补全的那一小条避免遮挡主画布正常内容mSlaveCanvas-setMask(QRegion(fullWidth-pixelWidth,0,pixelWidth,fullHeight));mSlaveCanvas-show();}elseif(overLeft0){// 向左越界逻辑同上方向相反// ... (省略对称代码)}else{mSlaveCanvas-hide();}// 中心点回绕 (Teleport)防止坐标无限变大溢出// 当视图中心跑太远时瞬间拉回到中心区域因主从画布画面一致用户无感知if(extent.center().x()MAX_XWORLD_W/2.0){mMapCanvas-setExtent(shiftedExtent(-WORLD_W));}}交互修正 (Interaction Fix)由于从画布是透明的用户点击屏幕上的幽灵/补全区域时实际坐标点击的是主画布的越界区域空区域。工具类必须具备多世界感知能力。// 示例Tool 中的点击检测逻辑voidTool::canvasPressEvent(QgsMapMouseEvent*e){QgsPointXY mapPointe-mapPoint();doublesearchRadius...;// 搜索偏移量当前位置以及左右各一个世界的位置constdoubleworldWidth40075016.68;constdoubleoffsets[]{0.0,-worldWidth,worldWidth};for(doubleoffset:offsets){// 构建带偏移的搜索点QgsPointXYsearchPoint(mapPoint.x()offset,mapPoint.y());// 在该位置搜索要素...if(foundFeatureAt(searchPoint)){// 找到了处理交互break;}}}路径连线修复 (Path Continuity)拓展对于跨越本初子午线的路径绘制处理对于跨越180° 经线的路径如台风路径简单的截断会导致视觉断裂。需要在数据层面进行插值。// 检测到经度跨越 180 度大跳变时if(abs(lon-prevLon)180.0){// 1. 计算插值点生成两段线// 2. 第一段从上一位置 - 180度边缘// 3. 第二段从 -180度边缘 - 当前位置// 这样在双画布渲染下视觉上两线会首尾相连}

更多文章