前文链接:QGraphicsView实现简易地图2『瓦片经纬度』
第一篇文章提到过,当地图层级较大时,暴力全加载地图会造成程序卡顿,因此需要实现地图的局部加载。
实现思路:以地图窗口(以下称为视口)为地图展示区域,最理想情况是行列组成的瓦片地图正好与视口大小一致。然而,大多数情况下都需要行列组成的瓦片地图比视口大才能完整覆盖视口,因此需要合理计算瓦片地图的行数和列数,以最小行数和最小列数覆盖整个视口为最佳,以下将提供实现此需求的核心代码。
1、动态演示效果
2、静态展示图片
核心代码
void MapView::scaleScene()
{
// 经纬度坐标转场景坐标、视图定位到鼠标中心
QPointF scenePos = MapUtility::sceneCoordFromGeoCoord(m_wheelGeoCoord, m_curLevel);
horizontalScrollBar()->setValue(scenePos.x() - m_offsetPos.x());
verticalScrollBar()->setValue(scenePos.y() - m_offsetPos.y());
// 视口宽度和高度
int w = viewport()->width();
int h = viewport()->height();
// 瓦片像素点坐标、视口坐标
QPointF pixelPos = MapUtility::tilePixelCoordFromScene(scenePos, m_curLevel);
QPoint viewportPos = mapFromScene(scenePos);
// 鼠标所在瓦片的四边 与 视口四边的距离
int lPixel = viewportPos.x() - pixelPos.x();
int rPixel = w - (viewportPos.x() + PIXMAP_SIZE - pixelPos.x());
int tPixel = viewportPos.y() - pixelPos.y();
int bPixel = h - (viewportPos.y() + PIXMAP_SIZE - pixelPos.y());
// 计算鼠标所在瓦片的四边应该填充的完整图片数量、是否存在剩余像素
int leftPixmapCount = lPixel / PIXMAP_SIZE;
bool remainLeftPixel = lPixel % PIXMAP_SIZE;
int rightPixmapCount = rPixel / PIXMAP_SIZE;
bool remainRightPixel = rPixel % PIXMAP_SIZE;
int topPixmapCount = tPixel / PIXMAP_SIZE;
bool remainTopPixel = tPixel % PIXMAP_SIZE;
int bottomPixmapCount = bPixel / PIXMAP_SIZE;
bool remainBottomPixel = bPixel % PIXMAP_SIZE;
// 计算呈现的瓦片地图左上角的瓦片坐标
m_curTileCoord = MapUtility::tileCoordFromGeoCoord(m_wheelGeoCoord, m_curLevel);
m_topLeftTileCoord.x = m_curTileCoord.x - leftPixmapCount;
m_topLeftTileCoord.y = m_curTileCoord.y - topPixmapCount;
if (remainLeftPixel && m_topLeftTileCoord.x > 0)
m_topLeftTileCoord.x -= 1;
if (remainTopPixel && m_topLeftTileCoord.y > 0)
m_topLeftTileCoord.y -= 1;
// 计算呈现的瓦片地图右下角的瓦片坐标
m_bottomRightTileCoord.x = m_curTileCoord.x + rightPixmapCount;
m_bottomRightTileCoord.y = m_curTileCoord.y + bottomPixmapCount;
if (remainRightPixel && m_bottomRightTileCoord.x < pow(2, m_curLevel) - 1)
m_bottomRightTileCoord.x += 1;
if (remainBottomPixel && m_bottomRightTileCoord.y < pow(2, m_curLevel) - 1)
m_bottomRightTileCoord.y += 1;
// 加载瓦片
QString dirPath = QString("F:/MapData/GaoDeMap/Map/MapPng/L0%1").arg(m_curLevel + 1);
for (int row = m_topLeftTileCoord.y; row <= m_bottomRightTileCoord.y; ++row)
{
for (int col = m_topLeftTileCoord.x; col <= m_bottomRightTileCoord.x; ++col)
{
QString fileName = QString("%1/Map_%2-%3.png").arg(dirPath)
.arg(QString::number(row + 1).rightJustified(2, '0')).arg(QString::number(col + 1).rightJustified(2, '0'));
QPixmap pixmap(fileName);
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
item->setPos(PIXMAP_SIZE * col, PIXMAP_SIZE * row);
m_scene->addItem(item);
m_mapItems[row][col] = item;
}
}
}