




























基于Qt开发的集群地面站管理平台,为多无人机系统的集中监控与协同控制提供了高效、稳定的解决方案。该平台利用Qt跨平台、高性能的GUI开发能力,构建了直观、友好的人机交互界面,能够实时显示各无人机的状态信息、位置数据和飞行参数。通过集成化的通信模块,平台可同时管理数十架甚至上百架无人机,实现任务分发、状态回传、故障报警等核心功能,极大地提升了集群作业的效率和安全性,广泛适用于应急救援、区域测绘、农林植保等大规模应用场景。
Qt提供了成熟的图形用户界面框架(Qt Widgets 和 Qt Quick),拥有大量预置控件(按钮、菜单、图表、树形视图等),可快速构建复杂的人机交互界面。同时,其强大的样式表(QSS)和图形视图框架(QGraphicsView)支持高度自定义的可视化效果,能够实现地图显示、飞行轨迹动画、仪表盘、状态监控面板等专业级UI需求。Qt底层基于C++,运行效率高,资源占用低,适合处理无人机实时数据流(如遥测数据、视频流、GPS位置等)。结合信号与槽机制,可以高效实现模块间的异步通信,确保系统响应及时,满足地面站对低延迟、高稳定性的要求。




#include "mapdrawmarkerline.h"
#include "mapobjbase.h"
#include "maphelper.h"
#include "maputil.h"
MapDrawMarkerLine::MapDrawMarkerLine(QObject *parent) : QObject(parent)
{
this->mapObj = NULL;
lastTime = QDateTime::currentDateTime();
}
void MapDrawMarkerLine::runJs(const QString &js)
{
if (mapObj) {
mapObj->runJs(js);
}
}
void MapDrawMarkerLine::receiveDataFromJs(const QString &type, const QVariant &data)
{
if (!mapObj) {
return;
}
QString value = data.toString();
if (type == "click") {
if (flag.isEmpty()) {
return;
}
//测试发现部分地图在拖曳松开后会触发单击
if (lastTime.msecsTo(QDateTime::currentDateTime()) < 500) {
return;
}
//添加标注点
QString point = MapHelper::getLngLat2(value);
this->points << point;
this->append(points.count() - 1, point);
emit updatePoints();
} else if (type == "marker") {
//更新经纬度坐标 value=marker0_test|dragging|121.416762,31.190477
if (value.contains("|dragging")) {
QString name = value.split("_").first();
QString point = value.split("|").last();
point = MapHelper::getLngLat2(point);
int index = name.mid(6).toInt();
points[index] = point;
this->runJs(QString("setPolyline('%1', '%2')").arg(lineFlag).arg(points.join("|")));
//重新调整两侧的箭头标注的旋转角度和位置
this->setArrow(index, false);
this->setArrow(index + 1, false);
} else if (value.contains("|dragend")) {
lastTime = QDateTime::currentDateTime();
emit updatePoints();
} else if (value.contains("|click")) {
QString point = value.split("|").last();
point = MapHelper::getLngLat2(point);
emit markerClick(point);
}
}
}
void MapDrawMarkerLine::setArrow(int index, bool add)
{
//有些内核不支持旋转
MapCore mapCore = mapObj->getMapCore();
if (mapCore == MapCore_Google || mapCore == MapCore_Leaflet) {
return;
}
//超过范围的不用处理
if (index - 1 < 0 || index >= points.count()) {
return;
}
//计算两点之间的中间点和旋转角度
QString p1 = points.at(index - 1);
QString p2 = points.at(index);
int angle = MapUtil::getAngle(p1, p2);
QPointF arrow = MapUtil::getCenter(p1, p2);
QString center = QString("%1,%2").arg(arrow.x(), 0, 'f', 10).arg(arrow.y(), 0, 'f', 10);
QString arrowFlag = QString("arrow%1_%0").arg(flag).arg(index);
//添加和旋转移动箭头
if (add) {
this->runJs(QString("addMarker('%1', '%2', '', '../mapimage/arrow.png', 30, 30, true, -1, true)").arg(arrowFlag).arg(center));
this->runJs(QString("setMarker('%1', null, null, %2)").arg(arrowFlag).arg(angle));
} else {
this->runJs(QString("setMarker('%1', null, '%2', %3)").arg(arrowFlag).arg(center).arg(angle));
}
}
void MapDrawMarkerLine::append(int index, const QString &point)
{
//生成一个唯一标识
QString markerFlag = QString("marker%1_%0").arg(flag).arg(index);
//可以改成每个点不同的图标
QString markerImage = MapHelper::getMarkerIcon("blue", index);
//添加标注点
this->runJs(QString("addMarker('%1', '%2', '', '%3', 25, 36)").arg(markerFlag).arg(point).arg(markerImage));
//监听标注点拖动事件
this->runJs(QString("addMarkerEvent('%1', 2, 'click')").arg(markerFlag));
this->runJs(QString("addMarkerEvent('%1', 2, 'dragging')").arg(markerFlag));
this->runJs(QString("addMarkerEvent('%1', 2, 'dragend')").arg(markerFlag));
//启动可编辑拖曳
this->runJs(QString("editOverlay('%1', true)").arg(markerFlag));
//经纬度坐标添加到对应线条
this->runJs(QString("addDataByFlag('%1', '%2')").arg(lineFlag).arg(point));
//添加和旋转箭头
this->setArrow(index, true);
}
void MapDrawMarkerLine::setMapObj(MapObjBase *mapObj)
{
this->mapObj = mapObj;
}
void MapDrawMarkerLine::setPara(const QStringList &points)
{
this->points = points;
}
void MapDrawMarkerLine::init(const QString &flag, const QString ¢er, int zoom)
{
this->flag = flag;
this->lineFlag = "line_" + flag;
//移动到中心点
if (zoom > 0) {
this->runJs(QString("setCenterAndZoom('%1', %2)").arg(center).arg(zoom));
}
//初始化一个折线对象用于后面添加数据
this->runJs(QString("initPolyline('%1')").arg(lineFlag));
//复位折线数据为空
this->runJs(QString("resetPolyline('%1')").arg(lineFlag));
//自动生成对应的标注点/绑定鼠标拖曳事件/开启可拖动
int count = points.count();
for (int i = 0; i < count; ++i) {
this->append(i, points.at(i));
}
}
void MapDrawMarkerLine::clear()
{
this->runJs("clearOverlay()");
this->flag.clear();
this->points.clear();
}
void MapDrawMarkerLine::stop()
{
//移除标注点拖动事件/禁用拖曳
int count = this->points.count();
for (int i = 0; i < count; ++i) {
QString markerFlag = QString("marker%1_%0").arg(flag).arg(i);
this->runJs(QString("removeMarkerEvent('%1', 'click')").arg(markerFlag));
this->runJs(QString("removeMarkerEvent('%1', 'dragging')").arg(markerFlag));
this->runJs(QString("removeMarkerEvent('%1', 'dragend')").arg(markerFlag));
this->runJs(QString("editOverlay('%1', false)").arg(markerFlag));
}
}
void MapDrawMarkerLine::getPoints()
{
emit receivePoints(points);
}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。