当前位置: 首页 > ai >正文

qt 3d航迹图

一般就是三种方法

1.opengl,vtk这种从零自己画,网上也可能有半成品,大多是付费的。

2.重写qwt3d,07年就停止更新了,画出来类似opengl,需要自己修改参数,参数修改不对很难搞,对于经纬高某一个数数值跨度小不太友好。我这边需求数据就不太符合,所以很难搞,直接换成q3d了

在这里插入图片描述

3.直接用q3d,耗费资源比较大,方便点,但是只有曲面图,散点图和柱形图。除了不能拟合个线,其他都挺好用。

在这里插入图片描述

照着这个大佬的配置一下Am_Jun

重写qwt3d

track3d.h

#ifndef TRACK3D_H
#define TRACK3D_H#include <QTimer>
#include <qwt3d_surfaceplot.h>
#include <qwt3d_function.h>
#include <QMouseEvent>
using namespace Qwt3D;class Rosenbrock:public Function{ // 定义Rosenbrock类,继承自Function类
public:Rosenbrock(SurfacePlot & pw):Function(pw){} // 构造函数,初始化SurfacePlot对象和Function对象Rosenbrock(){} // 无参构造函数double operator()(double x, double y)//需要自行更改这个函数,以x,y轴的数值确定z值,坑的很{//    return 2*x*y;//z轴初始范围与该函数相关return 9 * (y - 32.6);}
};class track3D:public Qwt3D::SurfacePlot
{
public:// 构造函数 初始化三维图表track3D();// 初始化Rosenbrock函数表面(用于定义坐标系底图)//void rosenbrockinit();// 添加航迹线bool addLine(QString linename,int linewidth);// 添加标记点(实现为仅保留单点的特殊线段)bool addPoint(QString pointName, int color,int lineWidth);// 更新指定标记点的坐标(保持固定长度)bool updatePointData(QString pointName,Qwt3D::Triple point);// 删除指定航迹线bool deleteLine(QString linename);// 清除所有航迹线bool deleteAllLine();// 向指定航迹线添加数据点bool addData(QString linename,Qwt3D::Triple point);// 设置当前坐标范围极值virtual void setCurMaxMin();// 重新绘制图表void replot();// 将QColor转换为Qwt3D的RGBA格式Qwt3D::RGBA colorToRGBA(const QColor& qtColor);
protected:virtual void keyPressEvent(QKeyEvent *);private:bool first = 0;// 三维图表实例(当前类本身)Qwt3D::SurfacePlot plot;//地图  管理航迹  航迹线管理器(键:线名称,值:线对象指针)QMap<QString,Qwt3D::Line3D*> mLine;//航迹  管理大小  航迹线长度记录(用于动态截断)QMap<QString,int> mLineSize;QVector<Line3D> testData;//颜色索引(循环使用预设颜色)int colorindex;// 预设颜色列表QVector<QColor> baseColors = {QColor(Qt::red), QColor(Qt::blue), QColor(Qt::black),QColor(Qt::green), /* 其他颜色 */};// 当前坐标轴范围临时变量double myCurxMin = 10000;double myCurxMax = -10000;double myCuryMin = 10000;double myCuryMax = -10000;// 初始坐标轴范围(经度/纬度)double myxMin = 10000;double myxMax = -10000;double myyMin = 10000;double myyMax = -10000;// 单条航迹最大数据点数int m_limit = 20000;// 默认线宽int defaultWidth = 5;//设置显示盒子Rosenbrock *m_rosenbrock;
};#endif // TRACK3D_H
track3d.cpp
#include "track3d.h"
#include <QDebug>track3D::track3D()
{// 设置图表的标题setTitle("GPS");// 设置绘图样式为线条三维样式setPlotStyle(Qwt3D::LINE3D_STYLE);//自动缩放坐标轴//coordinates()->setAutoScale(0);//设置隔离线数目setIsolines(5);// 创建一个Rosenbrock函数对象,并将其与当前SurfacePlot对象关联m_rosenbrock = new Rosenbrock(*this);// 设置网格的分辨率为10x10m_rosenbrock->setMesh(41,31);// 设置函数的定义域为x,y都在0到100之间m_rosenbrock->setDomain(myxMin,myxMax,myyMin,myyMax);m_rosenbrock->setMinZ(0);m_rosenbrock->setMaxZ(50);m_rosenbrock->create();// 设置坐标轴的网格线显示,仅在左侧、背面和底面显示
//    coordinates()->setGridLines(true,false,Qwt3D::LEFT|Qwt3D::BACK|Qwt3D::FLOOR);// 为每个坐标轴设置主刻度和次刻度数量for (unsigned i=0; i != coordinates()->axes.size(); ++i){coordinates()->axes[i].setMajors(5); // 主刻度数量coordinates()->axes[i].setMinors(1); // 次刻度数量}// 设置各坐标轴的标签coordinates()->axes[X1].setLabelString("经度/°");coordinates()->axes[Y1].setLabelString("纬度/°");coordinates()->axes[Z1].setLabelString("高度/m");// 设置坐标轴样式为盒子样式setCoordinateStyle(BOX);// 设置图表的平移、旋转、缩放、缩小比例以及坐标轴的主刻度和副刻度数目setShift(1,0,0);setRotation(30,0,15);setShift(0, 0, 0);      // 将图表移动到中心setZoom(0.9);// 更新数据,并更新图表replot();
}//void track3D::rosenbrockinit()
//{
//    //更新坐标轴样式
//    Rosenbrock rosenbrock(*this);
//    rosenbrock.setDomain(myxMin,myxMax,myyMin,myyMax);
//    rosenbrock.setMinZ(myzMin);
//    rosenbrock.setMaxZ(myzMax);
//    rosenbrock.create();
//}void track3D::keyPressEvent(QKeyEvent * e)  // 定义键盘事件处理函数
{int c = e->key();  // 获取用户按下的键if(e->key() == Qt::Key_Up)  // 判断用户按下的键是否为向上键{setShift(1,0,0);  // 设置图形在三维空间中的位置,参数为x,y,z轴方向上的偏移量setRotation(30,0,15);  // 设置图形在三维空间中的旋转角度,参数为x,y,z轴方向上的旋转角度setScale(1,1,1);  // 设置图形缩放比例setShift(0.15,0,0);  // 重新设置图形的偏移量,使其在x轴正方向上有一定的移动setZoom(0.9);  // 缩小视图镜头}else if(c == 65)  // 判断用户按下的键是否为字符'A'{setScale(xScale(),yScale(),zScale() * 1.2);  // 增加z方向上的缩放比例}else if(c == 68)  // 判断用户按下的键是否为字符'D'{setScale(xScale() * 1.2,yScale(),zScale());  // 增加x方向上的缩放比例}else if(c == 83)  // 判断用户按下的键是否为字符'S'{setScale(xScale(),yScale() * 1.2,zScale());  // 增加y方向上的缩放比例}
}
//添加轨迹线
bool track3D::addLine(QString linename,int linewidth)
{//如果没有,则进行添加if(!mLine.contains(linename)){Qwt3D::Line3D _l3d;Qwt3D::Line3D *myLine1 = dynamic_cast<Qwt3D::Line3D *>(this->addEnrichment(_l3d));myLine1->configure(linewidth,true);colorindex = colorindex % 2;myLine1->setLineColor(colorToRGBA(baseColors[colorindex]));  //设置默认颜色为红色colorindex++;mLine.insert(linename,myLine1);return true;}return false;
}bool track3D::addPoint(QString pointName,int color, int lineWidth)
{//实现方法:按照正常线段添加曲线  更新时只保留一个点位//如果没有,则进行添加if(!mLine.contains(pointName)){Qwt3D::Line3D _l3d;Qwt3D::Line3D *myLine1 = dynamic_cast<Qwt3D::Line3D *>(this->addEnrichment(_l3d));myLine1->configure(lineWidth,true);myLine1->setLineColor(colorToRGBA(baseColors[color]));mLine.insert(pointName,myLine1);return true;}return false;
}
//更新标识线-动态绘制时每次调用该函数使得线段长度固定
bool track3D::updatePointData(QString pointName, Triple point)
{//更新点的坐标if(mLine.contains(pointName)){mLineSize[pointName] += 1;auto it = mLine.find(pointName);if(mLineSize[pointName] > m_limit){//删除原来的数据it.value()->clear();mLineSize[pointName] = 0;}//更新点it.value()->add(point);}}
//删除单挑轨迹线
bool track3D::deleteLine(QString linename)
{if(mLine.contains(linename))   //如果包含{auto it = mLine.find(linename);it.value()->clear();this->degrade(it.value());mLine.remove(linename);return true;}return false;
}
//删除所有轨迹线
bool track3D::deleteAllLine()
{for(auto line:mLine){line->clear();   //移除所有曲线数据this->degrade(line);}mLine.clear();  //移除所有曲线return true;
}bool track3D::addData(QString linename, Triple point)
{if(mLine.contains(linename)) {// 独立判断各坐标轴极值if (point.x < myCurxMin) { myCurxMin = point.x;}if (point.x > myCurxMax) { myCurxMax = point.x;}if (point.y < myCuryMin) { myCuryMin = point.y;}if (point.y > myCuryMax) { myCuryMax = point.y;}setCurMaxMin(); // 只有当极值变化时才更新坐标范围replot();       // 刷新图表auto it = mLine.find(linename);it.value()->add(point);return true;} else {if(addLine(linename,defaultWidth)) return true;return false;}
}void track3D::setCurMaxMin()
{myxMax = qMax(myxMax,myCurxMax);myxMin = qMin(myxMin,myCurxMin);myyMax = qMax(myyMax,myCuryMax);myyMin = qMin(myyMin,myCuryMin);//myzMax = qMax(myzMax,myCurzMax);//myzMin = qMin(myzMin,myCurzMin);//    myxMax = myxMax + 1;
//    myxMin = myxMin - 1;//    myyMax = myyMax + 1;
//    myyMin = myyMin - 1;//    myzMax = myzMax + 1;
//    myzMin = myzMin - 1;qDebug() << "myxMax" << myxMax << "myxMin" << myxMin<< "myyMax" << myyMax << "myyMin" << myyMin;//<< "myzMax" << myzMax << "myzMin" << myzMin;//    double _yScale = myxMax / myzMax;
//    _yScale = (myxMax / myzMax) > _yScale? (myyMax / myzMax): _yScale;
//    setScale(1,1,_yScale);m_rosenbrock->setDomain(myxMin - 0.001,myxMax + 0.001,myyMin - 0.001,myyMax + 0.001);//m_rosenbrock->setMinZ(0);//m_rosenbrock->setMaxZ(50);m_rosenbrock->create();// 为每个坐标轴设置主刻度和次刻度数量for (unsigned i = 0; i != coordinates()->axes.size(); ++i){coordinates()->axes[i].setMajors(5); // 主刻度数量coordinates()->axes[i].setMinors(1); // 次刻度数量}// 设置各坐标轴的标签coordinates()->axes[X1].setLabelString("经度/°");coordinates()->axes[Y1].setLabelString("纬度/°");coordinates()->axes[Z1].setLabelString("高度/m");// 设置坐标轴样式为盒子样式//setCoordinateStyle(BOX);}// 数据更新与重绘
void track3D::replot()
{std::vector<Line3D> lineContain;for(auto line:mLine){lineContain.push_back(*line);//方法1  单独为线段更新//updateData(*line);//updateGL();}//存在两条以上曲线时,必须使用此方法更新数据(参数为vector<Line3D>)updateData(lineContain);updateGL();
}//qColor  2 RGBA
RGBA track3D::colorToRGBA(const QColor &qtColor)
{Qwt3D::RGBA qwt3DColor;qwt3DColor.r = qtColor.redF();  // 获取红色分量并转换为0.0到1.0的范围qwt3DColor.g = qtColor.greenF(); // 获取绿色分量并转换为0.0到1.0的范围qwt3DColor.b = qtColor.blueF();  // 获取蓝色分量并转换为0.0到1.0的范围qwt3DColor.a = qtColor.alphaF(); // 获取透明度分量并转换为0.0到1.0的范围return qwt3DColor;
}
使用示例
track3D *m_track = nullptr;
//初始化航迹图并插入
m_track = new track3D();
ui->tabWidget->insertTab(1, m_track, "3D Track"); // 我插入到tab里的,可以直接创建个界面中
//插入线条
if (m_track->addLine("理论轨迹", 2)) {for (int i = 1;i < m_data.length() - 1;i ++) {Triple point(m_data.at(i).Longitude, m_data.at(i).Latitude, m_data.at(i).Altitude);m_track->addData("理论轨迹", point);qDebug() << m_data.at(i).Longitude << "  " <<  m_data.at(i).Latitude << "   " << m_data.at(i).Altitude;}m_track->replot();
}

照着这个大佬配置长沙红胖子Qt

直接使用q3d

q3dsurfacewidget.h
#ifndef Q3DSURFACEWIDGET_H
#define Q3DSURFACEWIDGET_H#include <QMainWindow>#include <Q3dscatter>
#include <q3dsurface.h>
#include <q3dtheme.h>
#include <qsurface3dseries.h>
#include <qvector3d.h>
#include <QtDataVisualization>
#include <qabstract3dinputhandler.h>
#include <qmap.h>using namespace QtDataVisualization;QT_BEGIN_NAMESPACE
namespace Ui { class Q3dSurfaceWidget; }
QT_END_NAMESPACEclass Q3dSurfaceWidget : public QMainWindow
{Q_OBJECTpublic:Q3dSurfaceWidget(QWidget *parent = nullptr);~Q3dSurfaceWidget();void drawPoint(QString linename,QVector<QVector3D> points);private:Ui::Q3dSurfaceWidget *ui;Q3DScatter *m_3Dgraph;void initControl();//理论数据QtDataVisualization::QScatter3DSeries  *m_Theory;//散点类型//实际数据QtDataVisualization::QScatter3DSeries  *m_Actual;//散点类型//数据代理QScatterDataProxy *proxy_Theory = nullptr;QScatterDataProxy *proxy_Actual = nullptr;};#endif // Q3DSURFACEWIDGET_H
q3dsurfacewidget.cpp
#include "q3dsurfacewidget.h"
#include "ui_q3dsurfacewidget.h"
#include "QSplitter"#include <QDebug>
#include <QDateTime>Q3dSurfaceWidget::Q3dSurfaceWidget(QWidget *parent) :QMainWindow(parent),ui(new Ui::Q3dSurfaceWidget)
{ui->setupUi(this);this->setWindowTitle("UDP_Reciver");initControl();QSplitter *splitter = new QSplitter(Qt::Horizontal);splitter->addWidget(ui->widget);this->setCentralWidget(splitter);}Q3dSurfaceWidget::~Q3dSurfaceWidget()
{delete ui;
}void Q3dSurfaceWidget::initControl()
{m_3Dgraph = new Q3DScatter();ui->widget = QWidget::createWindowContainer(m_3Dgraph);proxy_Theory = new QScatterDataProxy(); //数据代理proxy_Actual = new QScatterDataProxy(); //数据代理m_Theory = new QScatter3DSeries(proxy_Theory);//创建序列m_Theory->setMeshSmooth(true);m_3Dgraph->addSeries(m_Theory);m_Actual = new QScatter3DSeries(proxy_Actual);//创建序列m_Actual->setMeshSmooth(true);m_3Dgraph->addSeries(m_Actual);//创建坐标轴m_3Dgraph->axisX()->setTitle("经度");m_3Dgraph->axisX()->setTitleVisible(true);m_3Dgraph->axisX()->setRange(0,100);m_3Dgraph->axisY()->setTitle("海拔");m_3Dgraph->axisY()->setTitleVisible(true);m_3Dgraph->axisY()->setRange(0,100);m_3Dgraph->axisZ()->setTitle("纬度");m_3Dgraph->axisZ()->setTitleVisible(true);m_3Dgraph->axisZ()->setRange(0,100);m_3Dgraph->activeTheme()->setLabelBackgroundEnabled(false);m_3Dgraph->activeTheme()->setBackgroundColor(QColor(90,90,90));//设置背景色m_Theory->setMesh(QAbstract3DSeries::MeshMinimal);//数据点为圆球m_Theory->setSingleHighlightColor(QColor(0,0,255));//设置点选中时的高亮颜色m_Theory->setBaseColor(QColor(0,255,255));//设置点的颜色m_Theory->setItemSize(0.05);//设置点的大小m_Actual->setMesh(QAbstract3DSeries::MeshMinimal);//数据点为圆球m_Actual->setSingleHighlightColor(QColor(0,0,0));//设置点选中时的高亮颜色m_Actual->setBaseColor(QColor(255,0,255));//设置点的颜色m_Actual->setItemSize(0.05);//设置点的大小}void Q3dSurfaceWidget::drawPoint(QString linename,QVector<QVector3D> points)
{if (points.isEmpty()) return; // 如果点集合为空,直接返回// 计算所有点的最小值和最大值float minX = points[0].x(), minY = points[0].y(), minZ = points[0].z();float maxX = points[0].x(), maxY = points[0].y(), maxZ = points[0].z();for (const auto &point : points) {minX = qMin(minX, point.x());minY = qMin(minY, point.y());minZ = qMin(minZ, point.z());maxX = qMax(maxX, point.x());maxY = qMax(maxY, point.y());maxZ = qMax(maxZ, point.z());}// 动态调整坐标轴范围m_3Dgraph->axisX()->setRange(minX - 1, maxX + 1);m_3Dgraph->axisY()->setRange(minY - 1, maxY + 1);m_3Dgraph->axisZ()->setRange(minZ - 1, maxZ + 1);if(linename == "理论"){QScatterDataArray *dataArray = new QScatterDataArray();dataArray->resize(points.count());QScatterDataItem *ptrToDataArray = &dataArray->first();for (int i = 0;i < points.count();i++ ){ptrToDataArray->setPosition(points[i]);ptrToDataArray++;}m_Theory->dataProxy()->resetArray(dataArray);//更新散点}if(linename == "实际"){QScatterDataArray *dataArray = new QScatterDataArray();dataArray->resize(points.count());QScatterDataItem *ptrToDataArray = &dataArray->first();for (int i = 0;i < points.count();i++ ){ptrToDataArray->setPosition(points[i]);ptrToDataArray++;}m_Actual->dataProxy()->resetArray(dataArray);//更新散点}
}
使用示例
Q3dSurfaceWidget *m_track = nullptr;//初始化航迹图并插入
m_track = new Q3dSurfaceWidget();
ui->tabWidget->insertTab(1, m_track, "3D Track"); // 在第二个位置(索引为1)插入标签页//我这边用定时器每十毫秒加个点,也能用for
//初始化时钟
if(timer_show == nullptr)
{timer_show = new QTimer();//开始跑connect(timer_show, &QTimer::timeout, [=]() {if(i < m_data.length() -1){if(isTheory == 1){   m_points_2.append(QVector3D(m_data.at(i).TargetLongitude,m_data.at(i).TargetAltitude,m_data.at(i).TargetLatitude));m_track->drawPoint("理论",m_points_2);}if(isActual == 1){m_points.append(QVector3D(m_data.at(i).Longitude,m_data.at(i).Altitude,m_data.at(i).Latitude));m_track->drawPoint("实际",m_points);}i++;}
});timer_show->start(10);
}

计算经纬高两个点之间的距离

//计算经纬高距离
//Haversine公式 然后当成三角形计算斜边
QVector<datacsv> m_data;
struct datacsv
{//时间戳QString TimeStamp;//经度double Longitude;//纬度double Latitude;//海拔double Altitude;//目标经度double TargetLongitude;//目标纬度double TargetLatitude;//目标海拔double TargetAltitude;
};
double a =  pow(sin((m_data.at(i).Latitude - m_data.at(i).TargetLatitude)  / 100000 / 2 * 3.1415926535 / 180) ,2) + cos(m_data.at(i).Latitude  / 100000 * 3.1415926535 / 180)  * cos(m_data.at(i).TargetLatitude  / 100000 * 3.1415926535 / 180) * pow(sin((m_data.at(i).Longitude - m_data.at(i).TargetLongitude) / 100000 /  2 * 3.1415926535 / 180) ,2);
double d = 2 * m_R * atan(sqrt(a / (1 - a)));
double d_2 = abs(m_data.at(i).Altitude - m_data.at(i).TargetAltitude);
double result = sqrt(d * d + d_2 * d_2);
//restlt就是最后结果
http://www.xdnf.cn/news/2333.html

相关文章:

  • Scala集合操作与WordCount案例实战总结
  • Linux高效IO
  • SQL面试之--明明建了索引为什么失效了?
  • docker部署ruoyi系统
  • Rule.resourceQuery(通过路径参数指定loader匹配规则)
  • 【音视频】FFmpeg过滤器框架分析
  • django.db.models.query_utils.DeferredAttribute object
  • PDF嵌入图片
  • python连接Elasticsearch并完成增删改查
  • 游戏遭遇DDoS攻击如何快速止损?实战防御策略与应急响应指南
  • 百度Create大会深度解读:AI Agent与多模态模型如何重塑未来?
  • PostgreSQL的扩展 pgcrypto
  • 全场景婴幼儿托育服务与管理实训室建设方案
  • 鸿蒙版电影app设计开发
  • 【Quest开发】透视环境下抠出身体并能遮挡身体上的服装
  • 【前端基础】viewport 元标签的详细参数解析与实战指南
  • Milvus(8):密集向量、二进制向量、稀疏向量
  • 烽火HG680-MC_晨星MSO9385芯片-2+8G_安卓9.0_不分地区通刷卡刷固件包
  • Java面向对象:抽象类详解
  • Linux文件操作
  • 如何避免爬虫因Cookie过期导致登录失效
  • 视觉/深度学习/机器学习相关面经总结(2)(持续更新)
  • vscode vue 的插件点击组件不能跳转到文件问题解决
  • LeetCode13_罗马数字转整数
  • OpenVLA:大语言模型用于机器人操控的经典开源作品
  • 界面打印和重定向同时实现
  • 多级缓存架构设计与实践经验
  • 决策树随机深林
  • Mysql从入门到精通day6————时间和日期函数精讲
  • PDF嵌入隐藏的文字