## 一、前言说明
之前做的地图组件,耗费了巨大的时间精力,前后完善了五年之多,能够想到的应用场景几乎都实现了,也有不少的用户,现场实际需求也不断反馈,不断的修改和增加功能,尽管优点很多,依然有个巨大缺点就是依赖浏览器控件,性能肯定是要打折扣的,毕竟有些嵌入式板子甚至老的开发环境,不一定有浏览器控件,就算有,在嵌入式板子环境上或者一些国产硬件的系统上,配置比较低,在浏览器上运行的网页,性能指数级下降,甚至一些环境连GPU都没有,老板为了节省成本,尽量选一些配置低的板子,所以也没有一种可能用QWidget绘制来实现呢,这样性能极好,而且控制度极高,qt的painter非常灵活可靠。
经过大量的尝试改造,总算在今年实现了这个地图控件,不依赖浏览器控件,也不依赖qml,有些人用的Qt自带的qml的location组件来实现的,这个尽管方便,但是性能也低,因为嵌入式环境配置低的板子,根本无法正常跑起来qml,别提要新版的Qt才有qlocaltion组件。用qwidget来实现有两个最大难点,一个是如何将地理坐标映射到像素绘制坐标,一个是如何快速的加载瓦片多线程绘制,这个必须采用多个分层绘制的机制。还有一个难点是绘制的图形有两大类,一种是面积大小自适应的比如多边形,一种是不需要自适应的一直是固定大小的比如标注点,这两种都需要在固定的经纬度区域,拖动移动要自动移动的对应的位置。将地理坐标映射到像素绘制坐标这个是最难的,整个地图组件的绘制要不断的将经纬度坐标转像素坐标,识别区域要将像素坐标转经纬度坐标。
## 二、效果图
## 三、相关代码
```cpp
#include "frmoverlay.h"
#include "ui_frmoverlay.h"
#include "qthelper.h"
#include "maphelper.h"
#include "overlayhelper.h"
#include "magicfish.h"
frmOverlay::frmOverlay(QWidget *parent) : QWidget(parent), ui(new Ui::frmOverlay)
{
ui->setupUi(this);
this->initForm();
this->initConfig();
this->loadMap();
}
frmOverlay::~frmOverlay()
{
delete ui;
}
void frmOverlay::initForm()
{
lng = 121.424362;
lat = 31.175942;
connect(ui->mapWidget, SIGNAL(receivePoint(qreal, qreal)), this, SLOT(receivePoint(qreal, qreal)));
connect(ui->cboxFlag->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(textChanged(QString)));
}
void frmOverlay::initConfig()
{
MapHelper::loadTileSource(ui->cboxTileSource, AppConfig::OverlaySource);
connect(ui->cboxTileSource, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig()));
connect(ui->cboxTileSource, SIGNAL(currentIndexChanged(int)), this, SLOT(loadMap()));
MapHelper::loadTileType(ui->cboxTileType, AppConfig::OverlayType);
connect(ui->cboxTileType, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig()));
connect(ui->cboxTileType, SIGNAL(currentIndexChanged(int)), this, SLOT(loadMap()));
ui->cboxOffline->setCurrentIndex(AppConfig::OverlayOffline);
connect(ui->cboxOffline, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig()));
connect(ui->cboxOffline, SIGNAL(currentIndexChanged(int)), this, SLOT(loadMap()));
ui->cboxCache->setCurrentIndex(AppConfig::OverlayCache);
connect(ui->cboxCache, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig()));
connect(ui->cboxCache, SIGNAL(currentIndexChanged(int)), this, SLOT(loadMap()));
}
void frmOverlay::saveConfig()
{
AppConfig::OverlaySource = ui->cboxTileSource->itemData(ui->cboxTileSource->currentIndex()).toInt();
AppConfig::OverlayType = ui->cboxTileType->itemData(ui->cboxTileType->currentIndex()).toInt();
AppConfig::OverlayOffline = ui->cboxOffline->currentIndex();
AppConfig::OverlayCache = ui->cboxCache->currentIndex();
AppConfig::writeConfig();
}
void frmOverlay::reset()
{
index = 1;
flag = "overlay1";
ui->cboxFlag->clear();
ui->cboxFlag->lineEdit()->setText(flag);
}
void frmOverlay::loadMap()
{
this->reset();
int tileSource = ui->cboxTileSource->itemData(ui->cboxTileSource->currentIndex()).toInt();
ui->mapWidget->setTileSource(TileSource(tileSource));
int tileType = ui->cboxTileType->itemData(ui->cboxTileType->currentIndex()).toInt();
ui->mapWidget->setT



