Qt绘制雷达图(卫星轨迹图)

效果图

在这里插入图片描述

功能

  1. 使用QPainter绘制,雷达图主要包括,同心圆、十字架、刻度、不同颜色的圆圈。
  2. 可以设置卫星的俯仰角,方位角,程序采用系统与卫星的结合,多种系统,n个卫星数据,进行显示,可自行搭配数据结构。
  3. 监测卫星活动状态,定时清理无数据卫星。
  4. 上百目标,界面绘制流畅,无卡顿。

代码

skyMap.h

#ifndef SKYMAP_H
#define SKYMAP_H

#include <QWidget>
#include <QDateTime>
#include <QTimer>
#include <QMap>

#define  PI 3.141592
#define ListSize 1200

struct StarSumData
{
    float elevation;            //仰角
    float azimuth;              //方位角
    QDateTime time;             //数据接受时间
};

struct StarSum
{
    int starSum;
    QColor color;
    QColor fontColor;
    QList<StarSumData> starSumDataList;

    StarSum()
        :fontColor("black")
    {}

    bool operator == (const StarSum& s)
    {
        if (starSum == s.starSum) {
            return true;
        }
        return false;
    }
};


//系统
enum SystemFlag {
    GPS_SYSTEM = 0,
    BDS_SYSTEM,
    GAL_SYSTEM,
    GLO_SYSTEM
};

struct StarPitch {
    float elevation;    //仰角
    float azimuth;      //方位角
};

QT_BEGIN_NAMESPACE
namespace Ui { class skyMap; }
QT_END_NAMESPACE

class SkyMap : public QWidget
{
    Q_OBJECT

public:
    SkyMap(QWidget *parent = nullptr);
    ~SkyMap();

    void clearSkyData();

    //获取所有卫星号
    void getAllStarSum(QMap<int, QStringList> &onLineStarNumber);

    void stopDelData();
public slots:

    //接受数据插入图中
    void insertData(int system, int starSum, float elevation, float azimuth, QDateTime time = QDateTime::currentDateTime());
    //设置颜色
    void setColor(QMap<int, QColor> colorList);

    //卫星超时不运行删除
    void timeout();
    //更新画面
    void timeoutUpdate();
private:
    void init();
    void drawCircle(QPainter *painter);
    void drawLabel(QPainter *painter);
    void drawAxisLabel(QPainter *painter);
    void drawStar(QPainter *painter);

    QColor getStarColor(int system);
protected:
    void paintEvent(QPaintEvent *e);
private:
    Ui::skyMap *ui;
    int m_Angle;
    int m_CircleSum;
    QStringList m_LabelList;
    QStringList m_AxisLabelList;
    QMap<int, QColor> m_ColorList;
    int m_Axis_max;
    int m_Axis_min;
    int m_CircleSize;
    int m_FontSize;
    QTimer* m_Time;
    QTimer* m_TimeUpdate;
    int m_UpdateTime;
    int m_TailSize;

    QMap<SystemFlag, QList<StarSum>> m_MapStarList; //天空图中的卫星数

};
#endif // SKYMAP_H

skyMap.cpp

#include "SkyMap.h"
#include "ui_SkyMap.h"
#include "qmath.h"
#include <QPainter>
#include <QPaintEvent>
#include <QPainterPath>
#include <QPen>
#include <QDebug>
#include <QTextOption>
#include <QPainterPath>

SkyMap::SkyMap(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::skyMap)
{
    ui->setupUi(this);
    init();
}

SkyMap::~SkyMap()
{
    delete ui;
}

void SkyMap::clearSkyData()
{
    m_MapStarList.clear();
}

void SkyMap::getAllStarSum(QMap<int, QStringList> &onLineStarNumber)
{
    QMap<SystemFlag, QList<StarSum>>::iterator i = m_MapStarList.begin();
    while (i != m_MapStarList.end()) {
        QList<StarSum> starSumList = i.value();

        QStringList starList;

        for (int index = 0; index < starSumList.size(); ++index) {
            StarSum starSumTemp = starSumList.at(index);

            starList << QString::number(starSumTemp.starSum);

        }
        onLineStarNumber.insert(int(i.key()), starList);
        i++;
    }
}

void SkyMap::stopDelData()
{
    m_Time->stop();
}

void SkyMap::insertData(int system, int starSum, float elevation, float azimuth, QDateTime time)
{
    if (elevation <= 0 || azimuth <= 0) {
        qDebug() << "天空图方位角俯仰角为0";
        return;
    }

    if (m_MapStarList.contains(SystemFlag(system))) { //判断系统是否存在
        QMap<SystemFlag, QList<StarSum>>::iterator i = m_MapStarList.begin();
        while (i != m_MapStarList.end()) {
            if (i.key() == SystemFlag(system)) {
                QList<StarSum> starSumList = i.value();

                //找卫星号
                StarSum starSumTemp;
                starSumTemp.starSum = starSum;
                if (starSumList.contains(starSumTemp)) {
                    int index = starSumList.indexOf(starSumTemp);
                    //吧找到的卫星数据列表给一下
                    QList<StarSumData> starSumDataList = starSumList.at(index).starSumDataList;


                    //判断上一条数据的浮动
                    if (starSumDataList.size() >= 1) {
                        StarSumData starSumDataTemp = starSumDataList.last();
                        int temp = azimuth - starSumDataTemp.azimuth;
                        if (temp > 5 || temp < -5) {
                            return;
                        }
                        temp = elevation - starSumDataTemp.elevation;
                        if (temp > 5 || temp < -5) {
                            return;
                        }
                    }

                    StarSumData starSumDataTemp;
                    starSumDataTemp.azimuth = azimuth;
                    starSumDataTemp.elevation = elevation;
                    starSumDataTemp.time = time;
                    //给卫星数据列表增加新数据
                    starSumDataList.append(starSumDataTemp);
                    //把找到的卫星数据替换一下
                    starSumTemp.starSumDataList = starSumDataList;
                    starSumTemp.color = getStarColor(system);

                    starSumList[index] = starSumTemp;
                }
                else {
                    //没有这个卫星增加新数据
                    QList<StarSumData> starSumDataList;
                    StarSumData starSumDataTemp;

                    starSumDataTemp.azimuth = azimuth;
                    starSumDataTemp.elevation = elevation;
                    starSumDataTemp.time = time;
                    starSumDataList.append(starSumDataTemp);


                    starSumTemp.starSumDataList = starSumDataList;
                    starSumTemp.color = getStarColor(system);

                    starSumList.append(starSumTemp);
                }
                //更新map
                i.value() = starSumList;
            }
            ++i;
        }
    }
    else {
        //系统不存在增加新系统
        QList<StarSum> starSumList;
        StarSum starSumTemp;
        starSumTemp.color = getStarColor(system);
        starSumTemp.starSum = starSum;

        QList<StarSumData> starSumDataList;
        StarSumData starSumData;

        starSumData.azimuth = azimuth;
        starSumData.elevation = elevation;
        starSumData.time = time;
        starSumDataList.append(starSumData);

        starSumTemp.starSumDataList = starSumDataList;
        starSumList.append(starSumTemp);

        m_MapStarList.insert(SystemFlag(system), starSumList);
    }
}

void SkyMap::setColor(QMap<int, QColor> colorList)
{
    m_ColorList = colorList;
}

void SkyMap::timeout()
{
    if (m_MapStarList.isEmpty()) {
        return;
    }
    QDateTime oldTime = QDateTime::currentDateTime();
    oldTime.setTime_t(oldTime.toTime_t() - 60 * 60 * 2);
    //遍历map
    QMap<SystemFlag, QList<StarSum>>::iterator i = m_MapStarList.begin();
    while (i != m_MapStarList.end()) {
        QList<StarSum> starSumList = i.value();
        for (int var = 0; var < starSumList.size(); ++var) {
            StarSum starSum = starSumList.at(var);
            for (int dataIndex = 0; dataIndex < starSum.starSumDataList.size(); ++dataIndex) {
                //数据的时间 小于当前时间-2h  删掉
                if (starSum.starSumDataList.at(dataIndex).time.toTime_t() < oldTime.toTime_t()) {
                    qDebug() << starSum.starSumDataList.at(dataIndex).time << "-------" << oldTime << "删除超时时间" << starSum.starSum  <<"---"<< i.key();
                    starSum.starSumDataList.removeAt(dataIndex);
                }
            }

            starSumList[var] = starSum; //更新卫星列表
            if (starSum.starSumDataList.isEmpty()) {
                //卫星数据列表空
                qDebug() << "删除卫星" << starSum.starSum << "---" << i.key();
                starSumList.removeAt(var);
            }
        }

        //更新map
        i.value() = starSumList;
        i++;
    }
}

void SkyMap::timeoutUpdate()
{
    this->update();
}

void SkyMap::init()
{
    m_Angle = 30; //角度
    m_CircleSum = 5; //圈数
    m_Axis_max = 90; //最大轴
    m_Axis_min = 0;
    m_CircleSize = 10; //圆大小
    m_FontSize = m_CircleSize - 2;
    m_UpdateTime = 100; //3s更新界面
    m_TailSize = m_CircleSize / 3;//尾巴粗细

    m_Time = new QTimer(this);
    m_Time->setInterval(60000);
    connect(m_Time, SIGNAL(timeout()), this, SLOT(timeout()));
    m_Time->start();

    m_TimeUpdate = new QTimer(this);
    m_TimeUpdate->setInterval(m_UpdateTime);
    connect(m_TimeUpdate, SIGNAL(timeout()), this, SLOT(timeoutUpdate()));
    m_TimeUpdate->start();

    //初始外围标签
    for (int i = 0; i < 360; i += m_Angle) {
        if (i == 0) {
            m_LabelList << QString::number(360);
        }
        else {
            m_LabelList << QString::number(i);
        }
    }
    m_AxisLabelList << "90" << "72" << "54" << "36" << "18" << "0";

}

void SkyMap::drawCircle(QPainter *painter)
{
    painter->save();

    QPen pen;
    pen.setWidthF(1.5);
    pen.setColor(Qt::black);
    painter->setPen(pen);

    QPainterPath looppath;
    int w = width();
    int h = height();


    int radius = qMin(w, h);
    int step = radius / (m_CircleSum + 1);  //加1是为了四周留出空间,写标签
    int x = w * 0.2;
    int y = h * 0.2;

    // 画圆
    QRectF outrect;
    for (int i = 1; i < m_CircleSum + 1; ++i)
    {
        radius = step * i;
        x = w / 2 - radius / 2;
        y = h / 2 - radius / 2;
        QRectF rect(x, y, radius, radius);
        looppath.addEllipse(rect);
        outrect = rect;
    }
    painter->drawPath(looppath);

    //画线
    int linecount = 360 / m_Angle;
    int x0 = w / 2 ;
    int y0 = h / 2;
    int newradius = outrect.height() / 2;
    for (int i = 0 ; i < linecount; ++i)
    {
        int x1 = x0 + newradius*qSin(PI * 2 / linecount * i);
        int y1 = y0 + newradius*qCos(PI * 2 / linecount * i);

        painter->drawLine(x0, y0, x1, y1);
    }

    painter->restore();
}

void SkyMap::drawLabel(QPainter *painter)
{
    if (m_LabelList.isEmpty()) {
        return;
    }

    painter->save();
    QPen pen;
    pen.setWidthF(1.5);
    pen.setColor(Qt::black);
    painter->setPen(pen);

    //QPen pen;
    //QColor color(Qt::black);
    //pen.setColor(color/*.lighter(100)*/); //添加线的颜色
    //painter->setPen(pen);


    int  laycount = m_CircleSum;  //默认是几层
    int w = width();
    int h = height();
    int count = 360 / m_Angle;
    int radius = qMin(w, h) / 2;
    int x0 = w / 2 ;
    int y0 = h / 2;

    QFont font;
    int m_FontSize = 10;
    if (h > 500) {
        m_FontSize = 12;
    }

    font.setPointSize(m_FontSize);
    painter->setFont(font);


    for (int i = 0 ; i < count; ++i)
    {
        int newradius = radius * laycount / (laycount + 1) + 10;
        newradius = newradius + 10 * qSin(PI * 2 / count * i);
        int x1 = x0 + newradius * qSin(PI * 2 / count * i) - 5;
        int y1 = y0 - newradius * qCos(PI * 2 / count * i) + 5;

        if (i == 6) { //180
            x1 -= m_FontSize;
            y1 += m_FontSize;
        }
        if (i == 9) { //270
            x1 -= (m_FontSize * 2) + 10;
        }
        if (i == 7 || i == 8) { //210,240
            x1 -= (m_FontSize * 2);
            y1 += m_FontSize;
        }
        if (i ==  10 || i == 11) {  //300,330
            x1 -= (m_FontSize * 2) + 5;
            y1 -= 5;
        }

        if (i < m_LabelList.count())
        {
            painter->drawText(x1, y1, m_LabelList.at(i));
        }
    }

    painter->restore();
}

void SkyMap::drawAxisLabel(QPainter *painter)
{
    if (m_AxisLabelList.isEmpty()) {
        return;
    }

    painter->save();
    QPen pen;
    pen.setWidthF(1.5);
    pen.setColor(Qt::black);
    painter->setPen(pen);

    //QPen pen;
    //QColor color(Qt::black);
    //pen.setColor(color/*.lighter(100)*/); //添加线的颜色
    //painter->setPen(pen);


    int  laycount = m_CircleSum;  //默认是几层
    int w = width();
    int h = height();
    int radius = qMin(w, h)/2;
    int x0 = w / 2 ;
    int y0 = h / 2;

    QFont font;
    int m_FontSize = 10;
    if (h > 500) {
        m_FontSize = 12;
    }

    font.setPointSize(m_FontSize);
    painter->setFont(font);

    for (int j = 0 ; j < laycount + 1; ++j)
    {
        int newradius = radius * j / (laycount + 1);
        int x1 = x0 + newradius * qSin(PI);
        int y1 = y0 + newradius * qCos(PI) - 2;

        if (j+1 == m_AxisLabelList.size()) { //把0下移
            painter->drawText(x1 + m_FontSize / 2, y1 + m_FontSize + 6, m_AxisLabelList.at(j));
            continue;
        }
        if (j < m_AxisLabelList.count())
        {
            painter->drawText(x1, y1, m_AxisLabelList.at(j));
        }
    }

    painter->restore();
}

void SkyMap::drawStar(QPainter *painter)
{
    painter->save();

    int w = width();
    int h = height();

    int radius = qMin(w, h) / 2 * m_CircleSum / (m_CircleSum + 1);

    qreal step = 1.0 * radius / (90 - 0);
    QMap<SystemFlag, QList<StarSum>>::iterator iter = m_MapStarList.begin();

    while (iter != m_MapStarList.end()) {
        QList<StarSum> starSumList = iter.value();
        for (int i = 0; i < starSumList.size(); ++i) {

            QPainterPath path; //画线路径
            //某个卫星的数据
            StarSum starSum = starSumList.at(i);

            QList<StarSumData> starSumDataList = starSum.starSumDataList;

            for (int j = 0; j < starSumDataList.size(); ++j) {
                bool isDrawHead = false;
                int m_CircleSizeTemp = m_CircleSize;
                //获取单个卫星的单个数据绘制
                StarSumData statSumData = starSumDataList.at(j);
                if (statSumData.azimuth <= 0 && statSumData.elevation <= 0) {
                    continue;
                }
                //判断数据量
                if (starSumDataList.size() == 1 || j >= starSumDataList.size() -1) {
                    //如果只有一条数据或者最后一条数据那么就画头
                    isDrawHead = true;
                    m_CircleSizeTemp = m_CircleSize;
                }
                else {
                    //如果数量大于1那么就要画点
                    m_CircleSizeTemp = 10;
                    painter->setBrush(QColor("green"));
                }

                qreal length = step * (m_Axis_max - statSumData.elevation);
                statSumData.azimuth = (m_Axis_max - statSumData.azimuth);

                QPointF certp(w / 2 + length * qCos(statSumData.azimuth * PI / 180),
                              h / 2 - length * qSin(statSumData.azimuth * PI / 180));

                //增加线条数据
                if (j == 0) {
                    path.moveTo(certp);
                }
                path.lineTo(certp);
                path.moveTo(certp);

                if (isDrawHead) {
                    //画线
                    painter->setPen(QPen(starSum.color, m_TailSize));
                    painter->drawPath(path);
                    //画头
                    painter->setFont(QFont("Arial", m_FontSize));
                    painter->setPen(QPen(starSum.color));
                    painter->setBrush(QBrush(starSum.color));
                    painter->drawEllipse(certp, m_CircleSizeTemp, m_CircleSizeTemp);
                    //画字
                    painter->setPen(QPen(starSum.fontColor));
                    QRect rect;
                    rect.setRect(certp.x() - (m_CircleSize / 2), certp.y() - (m_CircleSize / 2), m_CircleSize, m_CircleSize);
                    painter->drawText(rect, Qt::AlignCenter, QString::number(starSum.starSum));
                }
                else {

                }
            }
        }
        ++iter;
    }

    painter->restore();
    painter->end();
}

QColor SkyMap::getStarColor(int system)
{
    QMap<int, QColor>::const_iterator i = m_ColorList.begin();
    while (i != m_ColorList.end()) {
        if (i.key() == system) {
            return i.value();
        }
        ++i;
    }
    return QColor("red");
}

void SkyMap::paintEvent(QPaintEvent *e)
{
    Q_UNUSED(e)
    QPainter *painter = new QPainter(this);
    painter->setRenderHint(QPainter::Antialiasing);
    painter->setRenderHint(QPainter::SmoothPixmapTransform);
    painter->setRenderHint(QPainter::TextAntialiasing);

    //画圈
    drawCircle(painter);
    //画外围
    drawLabel(painter);
    //画俯仰刻度
    drawAxisLabel(painter);

    //画圆
    drawStar(painter);
}

调用方式

初始化调用SkyMap.setColor
通过信号与槽调用SkyMap.insertData
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值