如何用QChart显示DEM文件

想要直接看代码的童鞋可以跳过前面的瞎BB部分。

关于代码和DEM数据都看我置顶的博客吧!有免费下载。

//缘由BB部分:

emmmmmm为什么会萌生出这样的想法呢?因为有同学在一家公司搞点云算法,分了一个生成等高线的任务。然后拿到了一个DEM文件,要用这个文件生成等高线。但是这个文件有问题,因为传统的DEM是格网化的数据,是标准的矩形,但是,他拿到的DEM不是标准的矩形,是斜着的,这就造成了出现很多空白地方,不足的地方补充了-9999。两种数据的对比如下图:

用这样的文件去生成等高线,使用传统算法就行不通了。

        我对生成等高线的算法不太了解,但是读取数据还是可以做到的。然后正巧,前几天看到QT5.9的新特性QChart,惊呆了。在QT5.5的时候还必须进行编译才能使用的QTChart直接被加进来了,然后官方也给了很多例子用来学习。然后又正巧,我看到了官网利用高度图生成DEM的例子:


我很好奇,翻开一看,这个地形原来是用高度图生成的。高度图长这个样子,地形高的地方就亮,地形低的地方就黯淡:

        所以我萌生了一个大胆的想法,既然DEM是格网化的,也就是图像,那么利用DEM生成高度图,然后显示出来不就行了吗?然后我立刻实践了一下。

//BB部分结束。

直接上代码啦!由于DEM是有固定格式的,那么我们直接读进来然后显示:

void Scarlet_MainWindow::do_ShowDEM()
{
    QString path = QFileDialog::getOpenFileName(this, tr("Open Dem"), ".", tr("Dem Files(*.DEM)"));
    if(path.length() == 0)
    {
        qDebug()<<"Do not open any file!";
        //QMessageBox::information(NULL, tr("Path"), tr("You didn't select any files."));
    }
    else
    {
        Scarlet_DEM* myDem = new Scarlet_DEM(path);
        QImage heightMapImage =myDem->get_Image();
        int Col = myDem->get_Col();
        int Row = myDem->get_Row();
        //do_ShowIMG(heightMapImage);
        Q3DSurface *graph = new Q3DSurface();
        QWidget *container = QWidget::createWindowContainer(graph);
        if (!graph->hasContext())
        {
            QMessageBox msgBox;
            msgBox.setText("Couldn't initialize the OpenGL context.");
            msgBox.exec();
            return ;
        }
        QSize screenSize = graph->screen()->size();
        container->setMinimumSize(QSize(screenSize.width() / 2, screenSize.height() / 1.6));
        container->setMaximumSize(screenSize);
        container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        container->setFocusPolicy(Qt::StrongFocus);
        graph->setAxisX(new QValue3DAxis);
        graph->setAxisY(new QValue3DAxis);
        graph->setAxisZ(new QValue3DAxis);
 
        QHeightMapSurfaceDataProxy*m_heightMapProxy = new QHeightMapSurfaceDataProxy(heightMapImage);
        QSurface3DSeries*m_heightMapSeries = new QSurface3DSeries(m_heightMapProxy);
        m_heightMapSeries->setItemLabelFormat(QStringLiteral("(@xLabel, @zLabel): @yLabel"));
        m_heightMapSeries->setDrawMode(QSurface3DSeries::DrawSurface);
        m_heightMapSeries->setFlatShadingEnabled(true);//是否允许平滑绘制
       // m_heightMapSeries->setFlatShadingEnabled(false);
 
        graph->axisX()->setLabelFormat("%.1f X(N)");
        graph->axisZ()->setLabelFormat("%.1f W(E)");
//        m_heightMapProxy->setValueRanges(34.0f, 40.0f, 18.0f, 24.0f);//由于z轴在最低下,随意必须是x-z才行,y代表高度
//        graph->axisX()->setRange(34.0f, 40.0f);
//        graph->axisZ()->setRange(18.0f, 24.0f);
        m_heightMapProxy->setValueRanges(0, Col, 0, Row);//由于z轴在最低下,随意必须是x-z才行,y代表高度
        graph->axisX()->setRange(0, Col);
        graph->axisZ()->setRange(0, Row);
        //(可以让Z自动设定Range,我们也可以根据最大最小数值人为设定)
        //即便没有这句话,也是自动设定高度值
        graph->axisY()->setAutoAdjustRange(true);
 
        graph->axisX()->setTitle(QStringLiteral("Latitude"));
        graph->axisY()->setTitle(QStringLiteral("Height"));
        graph->axisZ()->setTitle(QStringLiteral("Longitude"));
        graph->addSeries(m_heightMapSeries);
 
        container->show();
    }
 
}


里面有一个类用来读取:Scarlet_DEM* myDem = new Scarlet_DEM(path);

这个东西的h文件是这样的:

class Scarlet_DEM:public QObject
{
    Q_OBJECT
public:
    Scarlet_DEM(QString DEMFile);
    QString get_DataMark(){return m_DataMark;}
    double get_Version(){return m_Version;}
    QString get_Unit(){return m_Unit;}
    double get_Alpha(){return m_Alpha;}
    double get_Compress(){return m_Compress;}
    double get_X0(){return m_X0;}
    double get_Y0(){return m_Y0;}
    double get_DX(){return m_DX;}
    double get_DY(){return m_DY;}
    int get_Row(){return m_Row;}
    int get_Col(){return m_Col;}
    QString get_ValueType(){return m_ValueType;}
    double get_HZoom(){return m_Hzoom;}
    QVector<double> get_Data(){return m_Data;}
    QImage get_Image(){return HeightImage;}
    double get_MinData(){return m_MinData;}
    double get_MaxData(){return m_MaxData;}
private:
    void InitFromFile();
    void PrintHead();
    void do_ReadHead(QTextStream &in);
    void do_ReadData(QTextStream &in);
    void do_ReadData2(QTextStream &in);
    void do_GenerateImage();
    QString m_DEMFile;
    QString m_DataMark;
    double m_Version;
    QString m_Unit;
    double m_Alpha;
    double m_Compress;
    double m_X0;
    double m_Y0;
    double m_DX;
    double m_DY;
    int m_Row;
    int m_Col;
    QString m_ValueType;
    double m_Hzoom;
    double m_MinData;
    double m_MaxData;
    QVector<double> m_Data;
    QImage HeightImage;
};

这个类主要就是用于读取DEM并生成高度图,然后把生成的高度图QImage存在里面。CPP文件是这样的:

#include <QtDataVisualization/QValue3DAxis>
#include <QtDataVisualization/Q3DTheme>
#include <QtGui/QImage>
#include <QtCore/qmath.h>
#include <QLabel>
#include <QFile>
#include <QFileInfo>
#include <QList>
#include <QMessageBox>
#include <iostream>
using namespace std;
 
//关于DEMEngin,读取解析DEM文件------------------------
//有三个DEM文件用于显示,以后会碰到更加复杂的吗?
void ShowImgeLabel(QImage Img)
{
    QLabel* myLabel = new QLabel();
    myLabel->setPixmap(QPixmap::fromImage(Img));
    myLabel->show();
}
Scarlet_DEM::Scarlet_DEM(QString DEMFile)
{
    m_DEMFile =DEMFile;
    InitFromFile();
}
void OutStrList(QList<QString> list)
{
    for(int i=0;i<list.size();i++)
    {
        QString Str =(list[i]);
        qDebug()<<"Str:"<<Str;
    }
}
 
void Scarlet_DEM::PrintHead()
{
    qDebug()<<"m_DEMFile"<<m_DEMFile;
    qDebug()<<"m_DataMark"<<m_DataMark;
    qDebug()<<"m_Version"<<m_Version;
    qDebug()<<"m_Unit"<<m_Unit;
    qDebug()<<"m_Alpha"<<m_Alpha;
    qDebug()<<"m_Compress"<<m_Compress;
    qDebug()<<"m_X0"<<m_X0;
    qDebug()<<"m_Y0"<<m_Y0;
    qDebug()<<"m_DX"<<m_DX;
    qDebug()<<"m_DY"<<m_DY;
    qDebug()<<"m_Row"<<m_Row;
    qDebug()<<"m_Col"<<m_Col;
    qDebug()<<"m_ValueType"<<m_ValueType;
    qDebug()<<"m_Hzoom"<<m_Hzoom;
}
void Scarlet_DEM::InitFromFile()
{
    qDebug()<<"Dem path:"<<m_DEMFile;
    QFileInfo Info(m_DEMFile);
    if(!Info.isFile())
        return;
    QFile file(m_DEMFile);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;
    QTextStream in(&file);
    //Read head,一共有13行,每一行用冒号分割
    do_ReadHead(in);
    PrintHead();
    do_ReadData(in);
    //do_ReadData2(in);
    file.close();
    do_GenerateImage();
}
void Scarlet_DEM::do_ReadHead(QTextStream &in)
{
    QString LineStr;
    QList<QString> myQtringList;
    LineStr=in.readLine();
    myQtringList = LineStr.split(':',QString::SkipEmptyParts);//后面参数决定是否跳过空字符串,默认不跳过空字符串
    m_DataMark= myQtringList[1];
    LineStr=in.readLine();//OutStrList(myQtringList);
    myQtringList = LineStr.split(':',QString::SkipEmptyParts);
    m_Version =myQtringList[1].toDouble();
    LineStr=in.readLine();//OutStrList(myQtringList);
    myQtringList = LineStr.split(':',QString::SkipEmptyParts);
    m_Unit = myQtringList[1];
    LineStr=in.readLine();//OutStrList(myQtringList);
    myQtringList = LineStr.split(':',QString::SkipEmptyParts);
    m_Alpha =myQtringList[1].toDouble();
    LineStr=in.readLine();//OutStrList(myQtringList);
    myQtringList = LineStr.split(':',QString::SkipEmptyParts);
    m_Compress =myQtringList[1].toDouble();
    LineStr=in.readLine();//OutStrList(myQtringList);
    myQtringList = LineStr.split(':',QString::SkipEmptyParts);
    m_X0 =myQtringList[1].toDouble();
    LineStr=in.readLine();//OutStrList(myQtringList);
    myQtringList = LineStr.split(':',QString::SkipEmptyParts);
    m_Y0 =myQtringList[1].toDouble();
    LineStr=in.readLine();//OutStrList(myQtringList);
    myQtringList = LineStr.split(':',QString::SkipEmptyParts);
    m_DX =myQtringList[1].toDouble();
    LineStr=in.readLine();//OutStrList(myQtringList);
    myQtringList = LineStr.split(':',QString::SkipEmptyParts);
    m_DY =myQtringList[1].toDouble();
    //行号
    LineStr=in.readLine();//OutStrList(myQtringList);
    myQtringList = LineStr.split(':',QString::SkipEmptyParts);
    m_Row =myQtringList[1].toInt();
    //列号
    LineStr=in.readLine();//OutStrList(myQtringList);
    myQtringList = LineStr.split(':',QString::SkipEmptyParts);
    m_Col =myQtringList[1].toInt();
    //数据类型
    LineStr=in.readLine();//OutStrList(myQtringList);
    myQtringList = LineStr.split(':',QString::SkipEmptyParts);
    m_ValueType =myQtringList[1];
    //缩放比例
    LineStr=in.readLine();//OutStrList(myQtringList);
    myQtringList = LineStr.split(':',QString::SkipEmptyParts);
    m_Hzoom =myQtringList[1].toDouble();
}
void Scarlet_DEM::do_ReadData(QTextStream &in)
{
    //行列号不能小于0
    if(m_Row<=10||m_Col<=10)
    {
        //我们一般处理10行以上的DEM,DEM行列号过小的情况也不予处理
        QMessageBox::information(NULL, "Title", "Invalid DEM! Cannot read", QMessageBox::Yes);
        return;
    }
    int fullLineCount = m_Col/10;
    int cutColNum =m_Col-fullLineCount*10;
    int PartLineCount = fullLineCount;
    if(cutColNum!=0)//说明还有一行
        PartLineCount++;
    int LittHightCount=0;
    bool minmaxDone = false;
    for(int r=0;r<m_Row;r++)
    {
        for(int i=0;i<PartLineCount;i++)
        {
            QString LineStr = in.readLine();
            QStringList sections = LineStr.trimmed().split(QRegExp("[ ]"),QString::SkipEmptyParts);
            for(int j=0;j<sections.size();j++)
            {
                QString Str =sections[j];
                if(minmaxDone == false)
                {
                    if(Str.toInt()!=-9999)
                    {
                        m_MinData = Str.toDouble();
                        m_MaxData = Str.toDouble();
                        minmaxDone=true;
                    }
                }
                else
                {
                    if(Str.toInt()!=-9999)
                    {
                        if(Str.toDouble()>=m_MaxData)
                            m_MaxData =Str.toDouble();
                        if(Str.toDouble()<=m_MinData)
                            m_MinData = Str.toDouble();
                    }
 
                }
                //cout<<Str.toDouble()<<" ";
                m_Data.push_back(Str.toDouble());//一行一行地存储进去
            }
            //cout<<endl;
        }
    }
    cout<<"m_Data:"<<m_Data.size()<<endl;
    cout<<"DataShouldBe:"<<m_Col*m_Row<<endl;
    cout<<"MaxData:"<<m_MaxData<<endl;
    cout<<"MinData:"<<m_MinData<<endl;
}
void Scarlet_DEM::do_ReadData2(QTextStream &in)
{
    //行列号不能小于0
    if(m_Row<=10||m_Col<=10)
    {
        //我们一般处理10行以上的DEM,DEM行列号过小的情况也不予处理
        QMessageBox::information(NULL, "Title", "Invalid DEM! Cannot read", QMessageBox::Yes);
        return;
    }
    int fullLineCount = m_Col/10;
    int cutColNum =m_Col-fullLineCount*10;
    int PartLineCount = fullLineCount;
    if(cutColNum!=0)//说明还有一行
        PartLineCount++;
    int LittHightCount=0;
 
    do
    {
        QString LineStr = in.readLine();
        if(LineStr.isNull())
            break;
        QStringList sections = LineStr.trimmed().split(QRegExp("[ ]"),QString::SkipEmptyParts);
        for(int j=0;j<sections.size();j++)
        {
            QString Str =sections[j];
            if(LittHightCount==0&&j==0)
            {
                m_MinData = Str.toDouble();
                m_MaxData = Str.toDouble();
            }
            else if(Str.toDouble()>=m_MaxData)
                m_MaxData =Str.toDouble();
            else if(Str.toDouble()<=m_MinData)
                m_MinData = Str.toDouble();
            if(Str.toDouble()<=2000)
                LittHightCount++;
            //cout<<Str.toDouble()<<" ";
            m_Data.push_back(Str.toDouble());//一行一行地存储进去
        }
    }while(true);
    cout<<"m_Data:"<<m_Data.size()<<endl;
    cout<<"DataShouldBe:"<<m_Col*m_Row<<endl;
    cout<<"MaxData:"<<m_MaxData<<endl;
    cout<<"MinData:"<<m_MinData<<endl;
    cout<<"LittHightCount"<<LittHightCount<<endl;
}
 
void Scarlet_DEM::do_GenerateImage()
{
    double AbsolutHeight =m_MaxData-m_MinData;
    HeightImage = QImage(m_Col,m_Row,QImage::Format_RGB888);
    HeightImage.fill(QColor(0,0,0));
    //HeightImage.setPixelColor(j,i,color);//必须赋初值,图像才能是黑色的
    for(int i=0;i<m_Row;i++)
    {
        for(int j=0;j<m_Col;j++)
        {
            double CurrentHeight = m_Data[i*m_Col+j];
            double HeightIn256 =(CurrentHeight-m_MinData)/AbsolutHeight*256;
            int Pix = (int)(HeightIn256+0.5);
            if(Pix<0)Pix =0;
            if(Pix>255)Pix = 255;
            if((int)(CurrentHeight) ==-9999)
            Pix =0;
            HeightImage.setPixelColor(j,i,QColor(Pix,Pix,Pix));
        }
    }
    //ShowImgeLabel(HeightImage);
}
 
 

还有别忘了包含QTChart相关的各种头文件。而且必须要加命名空间。放一下效果,左边是正规的DEM,右边是斜着的那种。两种都可以处理了。表现也是非常好的。



  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值