










之前做的地图组件,耗费了巨大的时间精力,前后完善了五年之多,能够想到的应用场景几乎都实现了,也有不少的用户,现场实际需求也不断反馈,不断的修改和增加功能,尽管优点很多,依然有个巨大缺点就是依赖浏览器控件,性能肯定是要打折扣的,毕竟有些嵌入式板子甚至老的开发环境,不一定有浏览器控件,就算有,在嵌入式板子环境上或者一些国产硬件的系统上,配置比较低,在浏览器上运行的网页,性能指数级下降,甚至一些环境连GPU都没有,老板为了节省成本,尽量选一些配置低的板子,所以也没有一种可能用QWidget绘制来实现呢,这样性能极好,而且控制度极高,qt的painter非常灵活可靠。
经过大量的尝试改造,总算在今年实现了这个地图控件,不依赖浏览器控件,也不依赖qml,有些人用的Qt自带的qml的location组件来实现的,这个尽管方便,但是性能也低,因为嵌入式环境配置低的板子,根本无法正常跑起来qml,别提要新版的Qt才有qlocaltion组件。用qwidget来实现有两个最大难点,一个是如何将地理坐标映射到像素绘制坐标,一个是如何快速的加载瓦片多线程绘制,这个必须采用多个分层绘制的机制。还有一个难点是绘制的图形有两大类,一种是面积大小自适应的比如多边形,一种是不需要自适应的一直是固定大小的比如标注点,这两种都需要在固定的经纬度区域,拖动移动要自动移动的对应的位置。将地理坐标映射到像素绘制坐标这个是最难的,整个地图组件的绘制要不断的将经纬度坐标转像素坐标,识别区域要将像素坐标转经纬度坐标。


#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->setTileType(TileType(tileType));
QString offlinePath = TileHelper::getOfflinePath(TileSource(tileSource));
ui->mapWidget->setOffline(ui->cboxOffline->currentIndex() == 1);
ui->mapWidget->setOfflinePath(offlinePath);
QString cachePath = (ui->cboxCache->currentIndex() == 1 ? QtHelper::appPath() + "/mapcache" : "");
ui->mapWidget->setCachePath(cachePath);
}
void frmOverlay::receivePoint(qreal lng, qreal lat)
{
this->lng = lng;
this->lat = lat;
ui->txtLng->setText(QString::number(lng, 'f', 6));
ui->txtLat->setText(QString::number(lat, 'f', 6));
}
void frmOverlay::addIndex()
{
index++;
QString text = QString("overlay%1").arg(index);
QString item = QString("overlay%1").arg(index - 1);
ui->cboxFlag->addItem(item);
ui->cboxFlag->lineEdit()->setText(text);
}
void frmOverlay::textChanged(const QString &arg1)
{
if (!arg1.isEmpty()) {
this->flag = arg1;
}
}
void frmOverlay::on_btnAddMarker_clicked()
{
QString file = ":/image/marker.png";
//QString file = ":/image/gif_person.gif";
OverlayBase *marker = ui->mapWidget->addMarker(flag, lng, lat, file);
OverlayHelper::updateText(marker, "标注点文本", "#000000", 4, 0, "");
this->addIndex();
}
void frmOverlay::on_btnDeleteMarker_clicked()
{
ui->mapWidget->deleteOverlay(flag);
}
void frmOverlay::on_btnUpdateMarker_clicked()
{
QString file = ":/image/gif_person.gif";
OverlayBase *marker = ui->mapWidget->updateMarker(flag, lng, lat, file);
OverlayHelper::updateText(marker, "新的文本底部居中", "#ff0000", 8, 0, "", 20);
}
void frmOverlay::on_btnRotateMarker_clicked()
{
ui->mapWidget->updateMarker(flag, NULL, NULL, QString(), QPixmap(), 30);
}
void frmOverlay::on_btnAddLabel_clicked()
{
ui->mapWidget->addLabel(flag, lng, lat, "#ff0000", "测试文本", 2);
this->addIndex();
}
void frmOverlay::on_btnUpdateLabel_clicked()
{
ui->mapWidget->updateLabel(flag, lng, lat, "#00ffff", "新的文本", 8, 20);
}
void frmOverlay::on_btnAddPolyline_clicked()
{
QPointF point(lng, lat);
QList<QPointF> points = MapHelper::getRandPoints(point, 4, 0.1);
ui->mapWidget->addPolyline(flag, points, "#ff0000", 3);
this->addIndex();
}
void frmOverlay::on_btnUpdatePolyline_clicked()
{
ui->mapWidget->updatePolyline(flag, QStringList(), QColor(0, 100, 100, 180), 5);
}
void frmOverlay::on_btnAddPolygon_clicked()
{
QPointF point(lng, lat);
QList<QPointF> points = MapHelper::getRandPoints(point, 3, 0.15);
ui->mapWidget->addPolygon(flag, points, "#00ff00", 2, QColor(0, 255, 0, 100));
this->addIndex();
}
void frmOverlay::on_btnUpdatePolygon_clicked()
{
ui->mapWidget->updatePolygon(flag, QStringList(), Qt::yellow, 4, QColor(250, 200, 89, 150));
}
void frmOverlay::on_btnAddRectangle_clicked()
{
QPointF point(lng, lat);
QList<QPointF> points = MapHelper::getRandPoints(point, 1, 0.15);
ui->mapWidget->addRectangle(flag, points.at(0), points.at(1), "#008888", 2, QColor(0, 255, 0, 100));
this->addIndex();
}
void frmOverlay::on_btnUpdateRectangle_clicked()
{
ui->mapWidget->updateRectangle(flag, QPointF(), QPointF(), Qt::red, 3, QColor(255, 0, 89, 150));
}
void frmOverlay::on_btnAddCircle_clicked()
{
//根据当前缩放级别获取合适的长度
int distance = MapHelper::getDistance(ui->mapWidget->getZoom());
qreal radius = MapHelper::getRadius(distance);
ui->mapWidget->addCircle(flag, lng, lat, radius, "#0000ff", 3, QColor(0, 0, 255, 50));
this->addIndex();
}
void frmOverlay::on_btnUpdateCircle_clicked()
{
qreal radius = MapHelper::getRadius(8000);
ui->mapWidget->updateCircle(flag, lng, lat, radius, "#ff0000");
}
void frmOverlay::on_btnAddWidget_clicked()
{
MagicFish *widget = new MagicFish(ui->mapWidget);
ui->mapWidget->addWidget(flag, lng, lat, widget);
this->addIndex();
}
void frmOverlay::on_btnUpdateWidget_clicked()
{
ui->mapWidget->updateWidget(flag, lng, lat);
}
void frmOverlay::on_btnAddBoundary_clicked()
{
on_btnClearOverlay_clicked();
QString fileName = QtHelper::getOpenFileName("*.txt", QtHelper::appPath() + "/mapboundary");
if (!fileName.isEmpty()) {
QFile file(fileName);
if (file.open(QFile::ReadOnly | QFile::Text)) {
QString points = file.readAll();
ui->mapWidget->addBoundary("boundary", points, "#ff55ff", 2, QColor(255, 100, 255, 100));
}
}
}
void frmOverlay::on_btnAddOverlays_clicked()
{
//批量添加可以先禁用重绘
OverlayHelper::redraw = false;
on_btnClearOverlay_clicked();
ui->mapWidget->setZoom(10);
ui->mapWidget->setCenter(121.424362, 31.175942);
for (int i = 0; i < 1000; ++i) {
qreal lng = QtHelper::getRandFloat(121.135250, 121.77727);
qreal lat = QtHelper::getRandFloat(30.99056, 31.43569);
qreal r = QtHelper::getRandFloat(0.02, 0.07);
QColor color = QtHelper::getRandColor();
QColor bgColor = color;
bgColor.setAlpha(150);
ui->mapWidget->addCircle(QString("circle%1").arg(i), lng, lat, r, color, 3, bgColor);
}
//添加完成后启用重绘
OverlayHelper::redraw = true;
}
void frmOverlay::on_btnDeleteOverlay_clicked()
{
ui->mapWidget->deleteOverlay(flag);
}
void frmOverlay::on_btnDeleteGroup_clicked()
{
ui->mapWidget->deleteGroup("circle");
}
void frmOverlay::on_btnClearOverlay_clicked()
{
this->reset();
ui->mapWidget->clearOverlay();
}
void frmOverlay::on_btnVisibleOverlay_clicked()
{
if (ui->btnVisibleOverlay->text() == "显示所有") {
ui->mapWidget->setOverlayVisible("", true);
ui->btnVisibleOverlay->setText("隐藏所有");
} else {
ui->mapWidget->setOverlayVisible("", false);
ui->btnVisibleOverlay->setText("显示所有");
}
}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。