• 1406阅读
  • 0回复

Qt编写地图综合应用53-省市轮廓图下载 [复制链接]

上一主题 下一主题
离线liudianwu
 

图酷模式  只看楼主 倒序阅读 楼主  发表于: 2022-01-16
## 一、前言
Qt的浏览器控件的交互机制非常方便,所以在在线地图的时候可以对每个区域的经纬度坐标集合发给Qt程序,让他去存储文件,在实际的测试过程中,发现有部分地图有多个封闭的曲线的,比如散落的岛屿和飞地,这些可不能遗漏呢,所以存储经纬度坐标信息,要按照数组的形式存储,最开始做的时候按照一个字符串集合存储的,后面发现部分地方少了甚至不规则,原来是有多个曲线集合,解析的时候根据数组来实例化不规则线条的类即可。

在线地图默认只能精确到县城,如果还要更精确的话,就需要自己手动调整边界点拉动好,然后主动获取当前边界点的经纬度坐标集合,存储起来,这就需要一开始设定一个基本的边界点的形状,开启允许编辑属性,然后自行去调整好位置,最后单击获取边界点坐标,保存文件即可,如果需要很多的乡镇的轮廓图,那只能很有耐心的慢慢的调整获取咯,当然这种无聊的没有技术含量的事情也可以交给小姑娘去做啦。

之前做获取边界点的时候,主要采用的是在线地图的方式,因为在线地图中直接内置了函数可以根据行政区域的名称来自动获取边界,其实这些边界就是一些点坐标集合连接起来的平滑线,然后形成的轮廓图,这种方式有个弊端就是只能在线的时候使用,而我们大部分的应用场景应该是离线的,甚至很多设备永远是离线的,根本不可能去联网获取信息,但是又想要这个各省市区域的轮廓图怎办呢,只能事先拿到下载到这些需要的轮廓图文件才行,这些文件存储的就是经纬度坐标集合,在离线地图中只需要定义不规则线条绘制传入这些经纬度坐标集合即可。

## 二、功能特点
1. 定时器排队下载省市轮廓图点坐标集合存储到JS文件。
2. 支持一个行政区域多个不规则区域下载。
3. 自动计算行政区域的下载轮廓数量。
4. 可精确选择省份、市区、县城,也可直接输入行政区域的名称。
5. 可以设置下载间隔、随时开始下载和停止下载。
6. 提供编辑边界功能,可以直接在地图上编辑好不规则区域的点集合,然后获取边界点集合数据,这个可以用来自己绘制区域拿到数据,比如某个乡镇甚至某个小区的行政区域数据,很牛逼。

## 三、体验地址
1. 体验地址:[https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A](https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A) 提取码:o05q  文件名:bin_map.zip
2. 国内站点:[https://gitee.com/feiyangqingyun](https://gitee.com/feiyangqingyun)
3. 国际站点:[https://github.com/feiyangqingyun](https://github.com/feiyangqingyun)
4. 个人主页:[https://blog.csdn.net/feiyangqingyun](https://blog.csdn.net/feiyangqingyun)
5. 知乎主页:[https://www.zhihu.com/people/feiyangqingyun/](https://www.zhihu.com/people/feiyangqingyun/)

## 四、效果图



## 五、相关代码
```c++
void frmMapBoundary::getBoundary()
{
    //判断当前索引对应的省会的复选框有没有勾选,没有勾选则找到下一个勾选的
    int count = names.count();
    while (indexMain < count - 1 && !cks.at(indexMain)->isChecked()) {
        indexMain++;
        indexSub = 0;
    }

    //到了最后一个省会的索引,停止定时器
    if (indexMain == count || !cks.at(indexMain)->isChecked()) {
        on_btnStop_clicked();
        return;
    }

    //下载到省会的最后一个县,索引自动跳到下一个省会
    QStringList list = names.at(indexMain);
    if (indexSub == list.count()) {
        indexMain++;
        indexSub = 0;
        getBoundary();
        return;
    }

    QString name = list.at(indexSub);
    addBoundary(name);
    indexSub++;

    //更新进度条
    int value = bars.at(indexMain)->value();
    bars.at(indexMain)->setValue(value + 1);
    ui->txtTip->setText(name);
}

void frmMapBoundary::addBoundary()
{
    //开启编辑状态
    QString name = ui->cboxName->currentText();
    addBoundary(name, true);
}

void frmMapBoundary::addBoundary(const QString &name, bool edit)
{
    currentName = name;
    QString js = QString("addBoundary('%1', true, %2)").arg(name).arg(edit ? "true" : "false");
    runJs(js);
}

void frmMapBoundary::saveBoundary(const QString &fileName, const QVariant &data)
{
    //传过来的是行政区划的边界点坐标集合,存储到js文件
    //可能会有多个数据,比如台湾的金门岛,都是独立的区域形状,存入数组
    QStringList boundarys;
    QStringList list = data.toString().split("|");
    foreach (QString points, list) {
        boundarys << QString("{'points': '%1'}").arg(points);
    }

    //最终js文件内容数据
    QString boundary = QString("var boundarys = [%1]").arg(boundarys.join(", "));
    QFile file(fileName);
    if (file.open(QFile::WriteOnly | QFile::Truncate)) {
        QTextStream out(&file);
#if (QT_VERSION < QT_VERSION_CHECK(6,0,0))
        out.setCodec("utf-8");
#endif
        out << boundary;
    }
}

void frmMapBoundary::clear()
{
    //先进度条全部置为0
    indexMain = indexSub = 0;
    ui->txtTip->setText("等待下载...");
    foreach (QProgressBar *bar, bars) {
        bar->setValue(0);
    }
}

void frmMapBoundary::receiveDataFromJs(const QString &type, const QVariant &data)
{
    if (data.isNull()) {
        return;
    }

    //qDebug() << "frmMapBoundary" << type << data;
    if (type == "boundary") {
        //开启了定时器则按照目录存放
        QString fileName = QString("%1/citypointjs/%2.js").arg(ConfigPath).arg(currentName);
        if (timerDown->isActive()) {
            QString provinceName = cks.at(indexMain)->text();
            QString path = QString("%1/citypointjs/%2").arg(ConfigPath).arg(provinceName);
            QDir dir(path);
            if (!dir.exists()) {
                dir.mkdir(path);
            }

            fileName = QString("%1/%2.js").arg(path).arg(currentName);
        }

        saveBoundary(fileName, data);
    } else if (type == "newboundary") {
        //拖动可编辑的边界以后读取到的边界点
        QString fileName = ui->txtFileName->text().trimmed();
        fileName = QString("%1/citypointjs/%2.js").arg(ConfigPath).arg(fileName);
        saveBoundary(fileName, data);
    }
}
```
4条评分好评度+1贡献值+1金钱+10威望+1
20091001753 好评度 +1 - 2022-01-16
20091001753 贡献值 +1 - 2022-01-16
20091001753 威望 +1 - 2022-01-16
20091001753 金钱 +10 - 2022-01-16
欢迎关注微信公众号:Qt实战 (各种开源作品、经验整理、项目实战技巧,专注Qt/C++软件开发,视频监控、物联网、工业控制、嵌入式软件、国产化系统应用软件开发)QQ:517216493  WX:feiyangqingyun  QQ群:751439350
快速回复
限100 字节
 
上一个 下一个