瓦片图的基本结构

与地图瓦片结构不同,本文瓦片图格式使用 level.x.y.ext 的格式,其中level是当前瓦片实际缩放的倍数。

如:1:1显示的最底层的level是1,上一层使用1:2的缩放的level是2,再上一层使用1:4的缩放的level是4,以此类推。

所以最高层的level最大,也是最大的鸟瞰图,同时level也一定是2的倍数。

这次层级关系是与常见的GIS模式不用, 如果需要兼容,可以重写以下部分 即可:

​ MXTGraphicsTileLoader::Private::ParseLevelInfo,修改瓦片文件夹的解析流程,进行层级转化到本文的level模式

​ MXTGraphicsTileLoader::Private::MakeTilePath,生成瓦片文件的路径

  1. 层级(Level / Zoom Level)
    • 每个瓦片图通常有多个层级,用于支持不同缩放级别
    • 层级 N 表示最小缩放(整体缩略图)
    • 层级 1 表示最大分辨率
    • 每上升一层,瓦片分辨率 / 2,瓦片层级 × 2
  2. 瓦片坐标(x, y)
    • 每个层级的图像被切分成大小固定的瓦片(如 256×256)
    • 以 (x, y) 作为瓦片坐标,且从(1,1)开始计算
    • 常用命名规则:level.x.y.png 或 level.x.y.tif
  3. 瓦片存储路径
    • 单文件夹全部存储
    • 如果需要分层分行存储,需要修改代码

三、核心配置结构

// 瓦片加载器配置信息
struct MXTGraphicsTileLoaderConfig {
    QString         folderPath;                         // 文件夹路径,瓦片所在根目录
    QByteArray      format = "tif";                     // 瓦片图像格式(tif/png/jpg/bmp)
    QSize           tileSize = QSize(1024, 1024);       // 每个瓦片在 scene 中显示的大小
                                                        // 影响缩放比例,可与真实瓦片不一致,实现缩放/拉伸
                                                        // 若原图512x512,设置为256x256则缩小显示
    int             ringRadius = 1;                     // 环形加载半径(视野扩展加载优化)
    int             crossLevelRadius = 1;               // 交叉层加载跨度(通常用于多层级预加载)
    int             debounceMs = 80;                    // 加载请求防抖控制(毫秒)
                                                        // 避免鼠标滚轮或平移时过多请求
    long long       maxCacheCount = 200;                // Tile 最大缓存数量(LRU 淘汰)
    int             mutexSleepTime = 200;               // 互斥锁等待超时(毫秒)
    LayerFilterMode filterMode = LayerFilterMode::Auto; // 层级过滤模式(自动/手动)
    QSet<ZLEVEL>    filterLevels;                       // 若为手动模式,这里指定要加载的层级
    bool            autoCropEdges = true;               // 自动裁剪右/下边缘黑边(不规则大图常用)
};

结构体要点解析(重点)

  • tileSize ≠ 原图分割瓦片大小
    • tileSize 控制瓦片的 显示比例
    • 可以用来让整图整体缩放、拉伸显示、甚至做分辨率适配
    • 例如想降低 GPU 压力,可把 1024×1024 的瓦片以 512×512 的方式显示
  • ringRadius 与 crossLevelRadius 是性能关键参数
    • ringRadius 用于“视野周边提前加载”
    • crossLevelRadius 用于“缩放时提前加载其他层级瓦片”
  • maxCacheCount 推荐根据显存或内存调整
    • 200 → 一般合适
    • 1000 → 内存大时能减少频繁加载
  • autoCropEdges 自动裁剪
    • 因为原图尺寸不太可能是瓦片的整数倍,这里假设会在右侧和下侧的边缘区域填充黑色像素
    • 开启后,可显示自动裁剪该黑色区域

四、关键函数

计算当前需要显示哪一个层级时,获取参数显示视图尺寸visibleRect,获取显示视图内物理显示屏的像素尺寸physicalViewportSize,去计算不同层级下显示视图尺寸在当前缩放倍数下和像素尺寸的差距,以最小值作为显示层级。

详细代码如下:

    static ZLEVEL FindClosestLevel( const QMap<ZLEVEL, TileLevelInfo>& levels,
                                    const QRectF& visibleRect,
                                    const QSize& physicalViewportSize)
    {
        ZLEVEL bestLevel = 0;
        double minDist2 = std::numeric_limits<double>::max();

        for (auto it = levels.constBegin(); it != levels.constEnd(); ++it) {
            const TileLevelInfo& info = it.value();

            // 计算当前 level 对应的 point
            double w = visibleRect.width() / info.level_;
            double h = visibleRect.height() / info.level_;
            QPointF pt(w, h);

            // 计算与 physicalViewportSize 的平方距离
            double dx = pt.x() - physicalViewportSize.width();
            double dy = pt.y() - physicalViewportSize.height();
            double dist2 = dx * dx + dy * dy;

            if (dist2 < minDist2) {
                minDist2 = dist2;
                bestLevel = it.key();
            }
        }

        return bestLevel;
    }

五、使用示例

// 创建瓦片图 Item
MXTGraphicsTilePixmapItem* item = new MXTGraphicsTilePixmapItem();

// 构建加载配置
MXTGraphicsTileLoaderConfig lConfig;
lConfig.folderPath = "D:/TEST_IMAGES";
lConfig.tileSize   = QSize(500, 500);  // 控制瓦片显示的缩放比例
lConfig.format     = "tif";
lConfig.maxCacheCount = 200;

// 初始化加载器
item->InitializeLoader(lConfig);

// 添加到 scene
view->scene()->addItem(item);

// !!! 必须绑定 view,触发视图更新瓦片缓存
item->bindView(view);

// 删除当前图片
item->ClearLoader();

// 加载新图片
item->InitializeLoader(lAnotherConfig);

六、流程图

1.初始化流程

TileCacheMXTGraphicsTileLoaderSingleLevelPixmapItemMXTGraphicsTilePixmapItemQGraphicsView用户操作TileCacheMXTGraphicsTileLoaderSingleLevelPixmapItemMXTGraphicsTilePixmapItemQGraphicsView用户操作loop[每个 ZLEVEL]InitializeLoader(config)1创建 TileLoader(config)2初始化缓存(按 maxCacheCount)3完成初始化4依据文件结构扫描 ZLEVEL 列表5创建 SingleLevelPixmapItem6设置 tileSize、层级值等7保存到内部容器 (levelItems[z])8bindView(view)9注册视图绑定10

2.视图拖动和缩放

ImageIOTileCacheQThread(加载线程)MXTGraphicsTileLoader(线程)SingleLevelPixmapItemMXTGraphicsTilePixmapItemQGraphicsView用户操作ImageIOTileCacheQThread(加载线程)MXTGraphicsTileLoader(线程)SingleLevelPixmapItemMXTGraphicsTilePixmapItemQGraphicsView用户操作alt[缓存命中][缓存未命中]loop[每个 TileKey]paint()1loadTile(TileKey)2不为空就显示pixmap

更多推荐