惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

爱范儿
爱范儿
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
G
GRAHAM CLULEY
www.infosecurity-magazine.com
www.infosecurity-magazine.com
V2EX - 技术
V2EX - 技术
The Last Watchdog
The Last Watchdog
S
Secure Thoughts
Webroot Blog
Webroot Blog
PCI Perspectives
PCI Perspectives
L
LINUX DO - 最新话题
Hacker News: Ask HN
Hacker News: Ask HN
N
News and Events Feed by Topic
H
Heimdal Security Blog
H
Help Net Security
T
The Blog of Author Tim Ferriss
P
Proofpoint News Feed
The GitHub Blog
The GitHub Blog
Jina AI
Jina AI
Recent Commits to openclaw:main
Recent Commits to openclaw:main
F
Full Disclosure
小众软件
小众软件
S
Securelist
罗磊的独立博客
NISL@THU
NISL@THU
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cisco Blogs
云风的 BLOG
云风的 BLOG
C
CERT Recently Published Vulnerability Notes
Cisco Talos Blog
Cisco Talos Blog
Know Your Adversary
Know Your Adversary
S
Schneier on Security
D
DataBreaches.Net
M
MIT News - Artificial intelligence
V
Vulnerabilities – Threatpost
N
News and Events Feed by Topic
有赞技术团队
有赞技术团队
F
Fortinet All Blogs
T
Tenable Blog
The Register - Security
The Register - Security
C
Check Point Blog
AWS News Blog
AWS News Blog
Cloudbric
Cloudbric
C
CXSECURITY Database RSS Feed - CXSecurity.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
C
Cyber Attacks, Cyber Crime and Cyber Security
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Google Online Security Blog
Google Online Security Blog
博客园 - 叶小钗
Hacker News - Newest:
Hacker News - Newest: "LLM"
博客园 - 司徒正美

博客园 - 飞扬青云

GB28181视频监控推流服务/点播预览推流/录像回放推流/指令预览推流/指令回放推流/自动预览推流 超级屌的动态测距交互功能/耗时几万个脑细胞/自研原创地图控件 Qt纯原创代码实现GB28181组件/自动点播拉流并推流/支持录像回放和下载/性能凶残 全网原创再次熬夜升级/支持云台预置位的onvif设备模拟器/虚拟监控摄像头/可设置主码流子码流 使用ffmpeg播放不同节目/实时切换节目并推流/推流不同的节目流 新版监控GB28181调试神器V2026发布/对标wvp/绿色版开箱即用 对标国际Onvif工具odm/新版视频监控onvif调试助手V2026发布/简单好用开箱即用 全网唯一/不依赖浏览器和qlocation/纯代码绘制实现的地图组件/短小精悍 监控设备模拟神器V2026全新含泪发布/支持onvif和gb28181/支持云台控制和预置位 将地图组件运行在浏览器上/qtlocation都做不到/轻巧好用/自研原创 不依赖任何AI代码/纯qpainter实现的航线规划/飞行轨迹规划和模拟/无人机轨迹 如何快速搭建一套支持ONVIF的安防监控系统 没有想不到只有做不到/万能地图标注点marker设计/各种参数需求场景/你要的都有 呕心沥血/历时半年/古法编程/纯QPainter实现的地图控件/性能爆表 绘制1000个无人机只需7ms/优化到极致/地图组件海量标注点/纯QPainter绘制的威力 实时轨迹/轨迹回放/多条轨迹同时回放/轨迹平滑移动/移动速度和间隔/自动旋转角度 记一个优化改良的实施过程/纯QPainter实现的地图组件/支持天地图谷歌地图等 性能提升百倍/Qt地图组件纯QWidget绘制/缓存瓦片技术/多线程加载绘制 纯QWidget绘制实现电子地图控件/非qml非web/多线程下载和加载瓦片/支持各种图形 Qt实现离线地图下载/瓦片地图下载/划区域下载离线地图/多线程批量下载 Qt实现电子地图热力图的绘制/热力图叠加图层/拖曳缩放移动 Qt实现行政区划轮廓图下载/一键批量下载/可编辑/天地图高德地图百度地图 全网首个源码级的跨平台视频监控系统方案/持续迭代更新/视频监控系统轮询管理的优化 Qt/C++开发监控GB28181系统/个人理解/要点总结/经验分享 离线获取任意经纬度海拔高度?一个100行代码的跨平台方案 Qt开发集群地面站管理平台/飞行轨迹动态规划和模拟/自由规划路径/飞行轨迹模拟 记一次Qt视频监控系统的优化/双击打开分组可能崩溃的BUG/排对打开通道过程中关闭通道可能崩溃的BUG Qt优化onvif设备搜索/一键批量搜索/onvif设备模拟器/几千路并发/实时推流/虚拟监控摄像头 Qt/C++地图最简示例/在线离线切换/地图视图切换/执行各种js函数交互 十年磨一剑/支持海康大华宇视华为天地伟业等所有厂家的视频监控系统/支持264和265/硬解和GPU绘制/支持国产麒麟和UOS以及RK3588等环境 祖传独创/全网唯一/Qt结合ffmpeg实现读取ts文件节目流/动态切换多节目/实时切换不同轨道
Qt电子地图叠加海图/全世界海图叠加到天地图图层/1-18级海图实时查看
飞扬青云 · 2026-06-29 · via 博客园 - 飞扬青云

一、前言说明

之前已经花了巨大的精力,把纯qwidget采用painter绘制的电子地图控件写完,已经支持了多级图层叠加,最上层一般是图形绘制层,可以绘制折线、多边形、矩形、圆形等覆盖物,底图一般是瓦片电子地图,可以是天地图高德地图等,前几年就已经有不少人问过是否支持海图,近期有空刚好可以把这块研究起来,核心关键就是要拿到海图的瓦片地址,最好是在线的,类似天地图这样的,最好是免费的,百度地图吃相就很难看,现在估计绝大部分人都转移到天地图上面来了,不仅标准的gps坐标系,而且卫星图还支持到18级,既免费又真香,瓦片下载下来后,还可以离线使用。

为了支持在线海图的瓦片,之前的电子地图控件做了一些改动,比如需要支持经纬度投影,之前默认按照默卡托投影来的,而不少厂商提供的是经纬度投影,现在需要改成每个控件对象都能设置投影系类型。经过测试发现,还需要支持512像素的瓦片,之前默认按照256像素的瓦片实现的,因为市面上绝大部分的都是256像素的,而目前找的海图的瓦片很可能是512像素的。经过不断的重组和调整重构,目前已经能够支持默认在天地图上叠加海图,当然也支持任意地图作为底图,而且支持任意多个底图,比如最底层是矢量底图、然后是海图、最上层是矢量标记图,也可以叫路网图,这样才是最完整的叠加顺序。

二、效果图

Snipaste_2026-06-28_13-25-01

Snipaste_2026-06-28_13-25-13

Snipaste_2026-06-28_13-25-55

三、相关代码

#include "mapadapter.h"
#include "mapprojection.h"
#include "tilehelper.h"

MapAdapter::MapAdapter(int min_zoom, int max_zoom, QObject *parent) : QObject(parent),
    m_min_zoom(min_zoom),
    m_max_zoom(max_zoom)
{

}

MapAdapter::~MapAdapter()
{

}

QString MapAdapter::url() const
{
    return m_url;
}

void MapAdapter::setUrl(const QString &url)
{
    m_url = url;
    m_ids.clear();
    this->replaceKey(m_url, true);
    this->replaceId(m_url, m_ids);
}

QStringList MapAdapter::ids() const
{
    return m_ids;
}

void MapAdapter::setIds(const QStringList &ids)
{
    m_ids = ids;
}

bool MapAdapter::isTileValid(int x, int y, int z) const
{
    int zoom = z;
    bool success = false;    
    if (m_min_zoom <= m_max_zoom && (zoom < m_min_zoom || zoom > m_max_zoom)) {

    } else if (m_min_zoom > m_max_zoom && (zoom < m_max_zoom || zoom > m_min_zoom)) {

    } else if (x >= 0 && x < MapProjection::tileX(z) && y >= 0 && y < MapProjection::tileY(z)) {
        success = true;
    }

    return success;
}

QUrl MapAdapter::tileQuery(int x, int y, int z) const
{
    QString url = m_url;

    //替换特殊地址
    this->replaceUrl(url, z);
    //替换地图秘钥
    this->replaceKey(url, false);

    //替换主机编号
    int size = m_ids.size();
    if (size > 0 && url.contains("{n}")) {
        url.replace("{n}", m_ids.at(rand() % size));
    }

    //反转TMS坐标系
    if (url.contains("{-y}")) {
        y = (1 << z) - 1 - y;
        url.replace("{-y}", "{y}");
    }

    //替换微软地图
    if (url.contains("{x}{y}{z}")) {
        QString xyz = this->xyzToQuadKey(x, y, z);
        url.replace("{x}{y}{z}", xyz);
    }

    //替换腾讯地图
    //这种地址需要替换xy http://p0.map.gtimg.com/sateTiles/z/x/y/x_y.png
    //这种地址只需要替换y http://rt0.map.gtimg.com/tile?styleid=1&z=10&x=861&y=417
    if (url.contains("map.gtimg.com")) {
        y = (1 << z) - 1 - y;
        if (url.contains("{x}_{y}")) {
            url.replace("{x/16}", QString::number(x / 16));
            url.replace("{y/16}", QString::number(y / 16));
        }
    }

    //替换瓦片地址
    url.replace("{x}", QString::number(x));
    url.replace("{y}", QString::number(y));
    url.replace("{z}", QString::number(z));
    return QUrl(url);
}

void MapAdapter::replaceUrl(QString &url, int zoom)
{
    if (url.contains("onechart.cn")) {
        if (zoom <= 10) {
            url.replace("WMTS_1_18", "WMTS_globe_1_10");
        } else {
            url.replace("WMTS_globe_1_10", "WMTS_1_18");
        }
    }
}

void MapAdapter::replaceKey(QString &url, bool replace)
{
    //如果只有一个秘钥则直接替换掉占位符
    if (url.contains("{key}")) {
        QStringList keys;
        if (url.contains("tianditu.gov.cn")) {
            keys = TileHelper::tianKeys;
        }

        int size = keys.size();
        if (size > 0) {
            QString key = keys.at(rand() % size);
            if (!replace || size == 1) {
                url.replace("{key}", key);
            }
        }
    }
}

void MapAdapter::replaceId(QString &url, QStringList &ids)
{
    //如果带了指定主机编号的范围/先取出来/{n-0-5-n}/处理后恢复占位符
    int index1 = url.indexOf("{n-");
    int index2 = url.indexOf("-n}");
    if (index1 > 0 && index2 > 0) {
        QString range = url.mid(index1 + 3, index2 - index1 - 3);
        if (range.contains('-')) {
            QChar min = range.at(0);
            QChar max = range.at(2);
            for (QChar c = min; c <= max; c = QChar(c.unicode() + 1)) {
                ids << QString(c);
            }

            url.replace(QString("{n-%1-n}").arg(range), "{n}");
        }
    }
}

QString MapAdapter::xyzToQuadKey(int x, int y, int z)
{
    QString quadKey;
    for (int i = z; i > 0; i--) {
        char digit = '0';
        int mask = 1 << (i - 1);
        if ((x & mask) != 0) {
            if ((y & mask) != 0) {
                digit = '3';
            } else {
                digit = '1';
            }
        } else {
            if ((y & mask) != 0) {
                digit = '2';
            } else {
                digit = '0';
            }
        }
        quadKey.append(digit);
    }

    return quadKey;
}

四、相关地址

  1. 国内站点:https://gitee.com/feiyangqingyun
  2. 国际站点:https://github.com/feiyangqingyun
  3. 个人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
  4. 文件地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码:o05q 文件名:bin_mapwidget.zip

五、功能特点

  1. 支持各种地图源,包括天地图、高德地图、腾讯地图、谷歌地图、微软地图等。
  2. 标准WGS-84地球坐标系,采用默卡托投影,可以拓展其他坐标系和投影规则。
  3. 支持在线和离线两种场景需求,可以自定义在线瓦片地址格式和离线瓦片地址格式。
  4. 多线程下载和加载瓦片图片文件,多线程绘制,自动缓存瓦片文件。
  5. 在线模式下,可以开启是否缓存文件,指定缓存路径,将下载的瓦片文件存放到本地,默认优先从缓存文件查找,如果存在缓存文件则加载缓存文件,不存在则联网下载。
  6. 可以拖动地图,鼠标滚轮放大和缩小地图,以鼠标所在位置作为缩放中心点,提供缩放控件手动单击进行操作。
  7. 多图层机制,支持多个瓦片叠加图层和图形绘制图层,全部采用双缓冲技术,所有的图形和瓦片全部绘制到一个图片文件上,最终再将图片文件绘制到地图控件。不可见区域的图层包括覆盖物不会触发绘制,降低CPU占用。
  8. 预加载机制,默认绘制的图层大小以当前区域往四周放大两倍,这样在鼠标拖动和缩放的时候,不会看到明显的加载过程,体验更佳。
  9. 内置了多种图形覆盖物,包括坐标点、文本、标注点、折线、多边形、矩形、圆形等,可以设置边框颜色粗细、填充颜色和透明度等参数。
  10. 标注点支持旋转角度和提示文本,其中提示文本可以设置在标注点的相对位置,标注点图片支持gif动图,可以动态切换静态图和动图。
  11. 标注点和提示文本可以设置相对位置,位置包括左侧、右侧、上侧、下侧、中间、左上角、右上角、左下角、右下角。标注点默认按照底部居中对齐,一般圆形图标可以设置中心点对齐。
  12. 标注点提示文本可设置背景颜色,透明度、颜色边框和粗细,支持换行和多行文字。
  13. 所有的图形可以动态更新前景色、颜色粗细、背景颜色、颜色透明度等。
  14. 支持删除单个图形、删除一种类型的图形、删除所有图形、隐藏单个或者所有图形等。
  15. 支持动态绘制各种图形,开启后直接在地图上鼠标按下绘制,鼠标右键结束绘制,非常方便快捷。
  16. 在对应图形区域鼠标按下,发出图形单击信号,精准识别单击区域,比如折线以鼠标在折线条上作为判断依据,多边形区域以鼠标在整个多边形区域内为准,而不是以矩形区域,包括圆形也是以圆形内部为准。
  17. 可以动态启动禁用比例尺、十字线、缩放控件、地图拖曳、键盘操作、滚轮缩放、双击放大、鼠标追踪等特性。
  18. 可以任意指定经纬度区域进行瓦片拼接保存成图片文件,也可以直接对整个可视区域或者缓存区域的地图图片文件保存。支持任意多边形轮廓保存成图片,比如某个行政区的瓦片保存。
  19. 图形可以动态设置zindex层叠顺序,值越大,越显示在前面,内部维护着一个zindex表,默认按照添加的先后顺序增加,后面添加的显示在前面,主动设置后,按照设置的zindex来绘制。
  20. 支持将QWidget对象作为覆盖物添加到地图控件中,跟随地图移动位置,极大提高灵活性,比如可以将自定义控件直接作为地图控件的子对象加入进去。
  21. 内置MarkerMove轨迹移动类,支持历史轨迹数据回放和实时轨迹移动,可设置图标、轨迹线的颜色和粗细、移动速度、移动间隔、平滑移动等,支持多条轨迹线条同时移动。
  22. 内置MarkerLine航迹规划类,支持动态添加航迹点,显示对应箭头,可以动态拖曳调整航迹点的位置,选中点高亮显示。
  23. 大量使用按需绘制机制,包括内部提供合理的默认值来触发绘制,也可以手动传入参数指定是否需要立即绘制,比如删除了某个覆盖物,有些频繁的操作可以不指定立即绘制,等操作完成后再统一一起绘制,效率更高。
  24. 默认开启缓存瓦片机制,所有加载过的瓦片文件都存储在内存中,下次再次绘制直接从内存取出来绘制,既不需要从联网获取,也不需要从缓存文件获取,直接内存取出来绘制,响应迅速效率最高体验最佳。
  25. 支持批量添加覆盖物,比如几万个标注点和圆形,都是瞬间完成绘制,相比web网页的方式,性能提升百倍以上。
  26. 支持街道图、卫星图、混合图、路网图等各种图层,可以任意叠加N个图层,甚至杂交不同地图厂家的瓦片文件。
  27. 纯QWidget绘制,非qml也非web,不依赖qml或者浏览器控件,支持极低性能的嵌入式环境。
  28. 原创轻量级,5000行代码,架构漂亮,注释详细,拓展方便,容易学习,适合各种初学者和进阶者,方便二次开发。
  29. 支持任意Qt版本、任意系统、任意编译器,包括嵌入式linux和各种国产电脑环境。古法编程,不含任何AI代码,品质保证。