首頁 > 軟體

基於Qt實現離線瓦片地圖下載器

2022-01-14 19:01:16

一、前言

寫這個離線地圖下載器的初衷,就是為了方便自己的幾個需要離線地圖的程式,客戶需求,既然地圖程式已經可以支援離線地圖,那如何獲取到這些離線瓦片地圖檔案是個關鍵,而且這是這個功能的關鍵,拿到這些一張張的瓦片圖片檔案,才能根據js函數繪製組合成離線地圖。

網上其實有很多各種各樣的離線地圖下載器,大部分都是要收費的,免費的要麼是限制了下載的瓦片數量或者級別,要麼是下載的瓦片圖打上了水印,看起來很難看,由於經常需要用到離線地圖,擺脫這個限制,特意花了點時間重新研究了瓦片地圖的原理,做了個離線地圖下載器,其實瓦片地圖下載沒有那麼複雜,其實就是從開放的幾個伺服器地址組建要請求的瓦片地圖的地址,傳送請求以後會自動將圖片返回給你,你只需要拿到圖片資料儲存成圖片即可。

瓦片地圖下載流程步驟如下:

  1. 獲取可視區域或者行政區域的範圍。
  2. 拿到區域的左下角右上角經緯度座標。
  3. 根據層級數計算對應層級的瓦片數。
  4. 自動生成下載瓦片地圖的地址並行出請求。
  5. 解析收到的資料儲存成圖片。
  6. 更新對應介面的下載數量和進度。
  7. 可選擇對應儲存的目錄、全選層級、中途停止下載等。
  8. 可選擇是下載街道圖還是衛星圖等。

二、功能特點

多執行緒同步下載多級別瓦片地圖,不卡介面。

內建多個離線地圖下載請求地址,自動隨機選擇一個傳送請求。

下載地圖型別同時支援街道圖和衛星圖。

自動計算可視區域或者行政區域的下載瓦片數量。

下載的級別可以自定義範圍和選擇。

每個瓦片下載完成都傳送訊號通知,引數包括下載用時。

可設定下載最大超時時間,超過了則丟棄跳到下一個下載任務。

實時顯示下載進度,以及當前級別已經下載的瓦片數和總瓦片數。

下載過程中可以停止下載,下載完成自動統計總用時。

內建經緯度和螢幕座標互相轉換函數。

目前支援百度地圖,其他地圖比如谷歌地圖、騰訊地圖、高德地圖可以客製化。

函數介面友好和統一,使用簡單方便,就一個類。

支援任意Qt版本、任意系統、任意編譯器。

三、體驗地址

體驗地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取碼:o05q 檔名:bin_map.zip

國內站點:https://gitee.com/feiyangqingyun

國際站點:https://github.com/feiyangqingyun

四、效果圖

五、相關程式碼

void MapDownload::download(const QString &path, int mapType, int downType, int xmin, int xmax, int ymin, int ymax, int zoom)
{
    for (int x = xmin; x <= xmax; x++) {
        for (int y = ymin; y <= ymax; y++) {
            if (stopped) {
                return;
            }

            QString url = getUrl(mapType, downType, x, y, zoom);
            QString dirName = QString("%1/%2/%3/").arg(path).arg(zoom).arg(x);
            QString fileName = QString("%1.jpg").arg(y);
            downloadImage(url, dirName, fileName, zoom);
        }
    }
}

void MapDownload::downloadBaiDu(const QString &path, int downType, int xmin, int xmax, int ymin, int ymax, int zoom)
{
    download(path, 0, downType, xmin, xmax, ymin, ymax, zoom);
}

void MapDownload::downloadTian(const QString &path, int downType, int xmin, int xmax, int ymin, int ymax, int zoom)
{
    download(path, 3, downType, xmin, xmax, ymin, ymax, zoom);
}

void MapDownload::downloadGoogle(const QString &path, int downType, int xmin, int xmax, int ymin, int ymax, int zoom)
{
    download(path, 4, downType, xmin, xmax, ymin, ymax, zoom);
}

void MapDownload::downloadImage(const QString &url, const QString &dirName, const QString &fileName, int zoom)
{
    if (url.isEmpty()) {
        return;
    }

    //啟動計時
    QElapsedTimer time;
    time.start();

    //先判斷資料夾是否存在,不存在則新建
    QDir dir(dirName);
    if (!dir.exists()) {
        dir.mkpath(dirName);
    }

    //區域性的事件迴圈,不卡主介面
    QEventLoop eventLoop;

    //設定超時 5.15開始自帶了超時時間函數 預設30秒
#if (QT_VERSION >= QT_VERSION_CHECK(5,15,0))
    manager->setTransferTimeout(timeout);
#else
    QTimer timer;
    connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
    timer.setSingleShot(true);
    timer.start(timeout);
#endif

    QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url)));
    connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
    eventLoop.exec();

    bool error = false;
    if (reply->bytesAvailable() > 0 && reply->error() == QNetworkReply::NoError) {
        //讀取所有資料儲存成檔案
        QByteArray data = reply->readAll();
        QFile file(dirName + fileName);
        if (file.open(QFile::WriteOnly | QFile::Truncate)) {
            file.write(data);
            file.close();
        }
    } else {
        //可以自行增加下載失敗的統計
        error = true;
        qDebug() << TIMEMS << "下載出錯" << reply->errorString();
    }

    reply->deleteLater();
    int useTime = time.elapsed();
    emit finsh(url, fileName, zoom, useTime, error);
}

到此這篇關於基於Qt實現離線瓦片地圖下載器的文章就介紹到這了,更多相關Qt離線瓦片地圖下載內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com