前文链接:QGraphicsView实现简易地图9『层级缩放显示底图』
自适应窗口大小
当地图窗口放大或缩小的时候,需要地图能够动态覆盖整个视口。
1、动态演示效果
2、核心代码
注:WHMapView继承自MapView
void WHMapView::resize()
{
if (m_curLevel >= 0)
moveScene();
}
void MapView::moveScene()
{
QString appPath = QApplication::applicationDirPath();
QString dirPath = QString("%1/MapData/GaoDeMap/Map/MapPng/L0%2").arg(appPath).arg(m_curLevel + 1);
// 视口宽度和高度
int vw = viewport()->width();
int vh = viewport()->height();
// 计算呈现的瓦片地图左上角的场景坐标和视口坐标、呈现的瓦片地图右下角的场景坐标和视口坐标
QPoint topLeftScenePos(m_topLeftTileCoord.x * PIXMAP_SIZE, m_topLeftTileCoord.y * PIXMAP_SIZE);
QPointF topLeftViewPos = mapFromScene(topLeftScenePos);
QPoint bottomRightScenePos(m_bottomRightTileCoord.x * PIXMAP_SIZE, m_bottomRightTileCoord.y * PIXMAP_SIZE);
QPointF bottomRightViewPos = mapFromScene(bottomRightScenePos);
int mapSideCount = pow(2, m_curLevel);
if (MapUtility::sceneSize(m_curLevel) > vw)
{
// 1、水平瓦片坐标控制:判断最左侧瓦片是否完全进入视口、最右侧瓦片是否完全离开视口
if (topLeftViewPos.x() > 0)
{
int count = qCeil(topLeftViewPos.x() / PIXMAP_SIZE); // 左侧进入视口瓦片数量
m_topLeftTileCoord.x = qMax(m_topLeftTileCoord.x - count, 0); // 更新现左侧瓦片坐标X
}
if (bottomRightViewPos.x() > vw)
{
int count = qFloor((bottomRightViewPos.x() - vw) / PIXMAP_SIZE) + 1; // 右侧离开视口瓦片数量
m_bottomRightTileCoord.x = qMax(m_bottomRightTileCoord.x - count, 0); // 更新现右侧瓦片坐标X
}
// 2、水平瓦片坐标控制:判断最右侧瓦片是否完全进入视口、最左侧瓦片是否完全离开视口
if (bottomRightViewPos.x() + PIXMAP_SIZE < vw)
{
int count = qCeil((vw - (bottomRightViewPos.x() + PIXMAP_SIZE)) / PIXMAP_SIZE); // 右侧进入视口瓦片数量
m_bottomRightTileCoord.x = qMin(m_bottomRightTileCoord.x + count, mapSideCount - 1); // 保存现右侧瓦片坐标X
}
if (topLeftViewPos.x() + PIXMAP_SIZE < 0)
{
int count = qFloor(fabs(topLeftViewPos.x()) / PIXMAP_SIZE); // 左侧离开视口瓦片数量
m_topLeftTileCoord.x = qMin(m_topLeftTileCoord.x + count, mapSideCount - 1); // 保存现左侧瓦片坐标X
}
}
if (MapUtility::sceneSize(m_curLevel) > vh)
{
// 3、垂直瓦片坐标控制:判断最上侧瓦片是否完全进入视口,最下侧瓦片是否完全离开视口
if (topLeftViewPos.y() > 0)
{
int count = qCeil(topLeftViewPos.y() / PIXMAP_SIZE); // 上侧进入视口瓦片数量
m_topLeftTileCoord.y = qMax(m_topLeftTileCoord.y - count, 0); // 保存现上侧瓦片坐标Y
}
if (bottomRightViewPos.y() > vh)
{
int count = qFloor((bottomRightViewPos.y() - vh) / PIXMAP_SIZE) + 1; // 下侧离开视口瓦片数量
m_bottomRightTileCoord.y = qMax(m_bottomRightTileCoord.y - count, 0); // 保存现下侧瓦片坐标Y
}
// 4、垂直瓦片坐标控制:判断最下侧瓦片是否完全进入视口,最上侧瓦片是否完全离开视口
if (bottomRightViewPos.y() + PIXMAP_SIZE < vh)
{
int count = qCeil((vh - (bottomRightViewPos.y() + PIXMAP_SIZE)) / PIXMAP_SIZE); // 下侧进入视口瓦片数量
m_bottomRightTileCoord.y = qMin(m_bottomRightTileCoord.y + count, mapSideCount - 1); // 保存现下侧瓦片坐标Y
}
if (topLeftViewPos.y() + PIXMAP_SIZE < 0)
{
int count = qFloor(fabs(topLeftViewPos.y()) / PIXMAP_SIZE); // 上侧离开视口瓦片数量
m_topLeftTileCoord.y = qMin(m_topLeftTileCoord.y + count, mapSideCount - 1); // 保存现上侧瓦片坐标Y
}
}
// 获取移动前瓦片集合
vector<TileCoord> vecOldTileCoord;
for (int row = m_viewAndAroundTileRect.top(); row <= m_viewAndAroundTileRect.bottom(); ++row)
{
for (int col = m_viewAndAroundTileRect.left(); col <= m_viewAndAroundTileRect.right(); ++col)
{
vecOldTileCoord.push_back(TileCoord(col, row));
}
}
// 获取移动后瓦片集合
vector<TileCoord> vecNewTileCoord, vecAddTileCoord;
m_viewAndAroundTileRect = CommonUtility::getViewAndAroundTileCoords(m_topLeftTileCoord.y, m_topLeftTileCoord.x, m_bottomRightTileCoord.y, m_bottomRightTileCoord.x, m_curLevel, vecNewTileCoord);
for (const auto &tc : vecNewTileCoord)
{
// ①筛除已加载过的瓦片 ②线程加载存在滞后性,第二次移动时可能第一次m_tileItems还没有加载完毕,所以需要前一次范围作为过滤
if (!m_tileItems.contains(tc) && std::find(vecOldTileCoord.begin(), vecOldTileCoord.end(), tc) == vecOldTileCoord.end())
{
vecAddTileCoord.push_back(tc);
}
}
//showTileCoord();
showGraticules();
// 上方即为计算瓦片索引的核心代码,省略下方加载瓦片的代码...
// 加载瓦片代码...
}