基于GDAL库海洋表温日平均计算工具设计与实现 C++版


技术背景  

  在对物理海洋数据处理过程中,表层温度是众多要素中的一种,本文书要是针对海洋表温数据批量日平均处理的一个工具设计。首先要在对当前的SST数据文件作一下简要的说明,SST全称为sea surfer Temperature,文件后缀为.nc,文件里面主要有两个数据集(datasets),第一个数据集全球的海洋表温的温度数据,其中标记值为-999(float数据类型),第二个数据集为遗失数据补充说明,具体大家可以参考附件链接中的文本文件,表温数据集主要分为8个时间节点,每个时间节点是一层,共有八层,每一层的范围是全球范围,空间分辨率为0.25度,为了方便利用surfer软件打开,并进行进一步制图。需要进行日平均计算。

计算原理

  首先将相应海峡范围的数据在读取的时候8个波段直接读上来,然后再将同一个栅格点上的8个波段的观测值进行相加,取平均后重新赋给当前栅格点;由于观测因素,部分栅格点或波段出现标记值,即数据缺失,所以在进行均值计算之前要进行数据的插值,本工具插值是采用反距离定权插值的方法,具体请参考GDAL库相关插值函数的使用方法。平均值计算出来以后,然后进行数据整理,数据整理主要是根据起始坐标、分辨率、栅格的宽度和高度,计算出每一个栅格点的坐标值,然后匹配上对应的表温数值,整合成三维点数据,打印出来。数据打印出来为txt数据。

  该工具可批量计算同一个文件下的所有文件下的所有SST数据(*.nc文件),生成相应的日平均数据。但是该程序对文件名具有限制性,格式必须为官方网站上下载的文件名称(例如:SEAFLUX-OSB-CDR_V02R00_SST_D20060101_C20160824.nc),这个可以根据源码进行修改。

开发环境

  本工具采用GDAL库及其扩展库netCDF,开发平台为QT 5.11.2(MSVC 2017),开发语言为C++

源码解析

  工具主要分为两个部分,即界面和核心功能,二者各占一个线程,通过信号和槽函数进行通信,界面代码如下:

h文件

  1 #ifndef MAINWINDOWS_H
  2 #define MAINWINDOWS_H
  3 
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8 #include 
  9 #include 
 10 #include 
 11 #include 
 12 
 13 #include "mdsst.h"
 14 
 15 namespace Ui {
 16 class MainWindows;
 17 }
 18 
 19 class MainWindows : public QWidget
 20 {
 21     Q_OBJECT
 22 
 23 public:
 24     explicit MainWindows(QWidget *parent = nullptr);
 25     ~MainWindows();
 26 
 27 private slots:
 28     void on_startBtn_clicked();
 29 
 30     void on_aboutBtn_clicked();
 31 
 32     void on_closeBtn_clicked();
 33 
 34     void on_inchooseBtn_clicked();
 35 
 36     void on_outchooseBtn_clicked();
 37 
 38     void infoshow(QString tempInfo);
 39 
 40     void completedInfoShow(QString info);
 41 
 42     void fileNumInfoShow(QString info);
 43 
 44     void compedFileNumshow(QString info);
 45 
 46 signals:
 47     void start(QString inputFilePath,QString outputFilePath);
 48 
 49 private:
 50     Ui::MainWindows *ui;
 51 
 52     MDSST *mdsst;
 53 
 54     QSharedPointer  mdsst_thd;
 55 
 56 };
 57 
 58 #endif // MAINWINDOWS_H

cpp文件

  1 #include "mainwindows.h"
  2 #include "ui_mainwindows.h"
  3 
  4 MainWindows::MainWindows(QWidget *parent) :
  5     QWidget(parent),
  6     ui(new Ui::MainWindows)
  7 {
  8     ui->setupUi(this);
  9     infoshow("使用前请了解相关使用方法.");
 10 
 11     mdsst = new MDSST();
 12     connect(this, SIGNAL(start(QString,QString)), mdsst, SLOT(startprocess(QString,QString)));
 13     connect(mdsst, SIGNAL(showInfo(QString)), this, SLOT(infoshow(QString)));
 14     connect(mdsst, SIGNAL(showCompedInfo(QString)), this, SLOT(completedInfoShow(QString)));
 15     connect(mdsst, SIGNAL(showFileNumInfo(QString)), this, SLOT(fileNumInfoShow(QString)));
 16     connect(mdsst, SIGNAL(showCompedFileNum(QString)), this, SLOT(compedFileNumshow(QString)));
 17 
 18     mdsst_thd.reset(new QThread);
 19     mdsst->moveToThread(mdsst_thd.data());
 20     mdsst_thd->start();
 21 
 22     this->setFixedSize(this->size());
 23     //setWindowIcon(QIcon(":/logo.png"));
 24 }
 25 
 26 MainWindows::~MainWindows()
 27 {
 28     if(mdsst_thd->isRunning())
 29     {
 30         mdsst_thd->terminate();
 31         mdsst_thd->wait();
 32         mdsst_thd->quit();
 33     }
 34     delete ui;
 35 }
 36 
 37 void MainWindows::infoshow(QString tempInfo)
 38 {
 39     if(tempInfo == "所有文件已处理完毕!"){
 40         ui->startBtn->setEnabled(true);
 41     }
 42     ui->Infoshowtedt->append(tempInfo);
 43 }
 44 
 45 void MainWindows::on_startBtn_clicked()
 46 {
 47     ui->startBtn->setEnabled(false);
 48     QString inputFilePath = ui->inputledt->text();
 49     QString outputFilePath = ui->outputledt->text();
 50     if(inputFilePath == "" && outputFilePath == "")
 51     {
 52         infoshow("文件路径或保存路径有误!");
 53         ui->startBtn->setEnabled(true);
 54     }else{
 55         emit start(inputFilePath,outputFilePath);
 56     }
 57 }
 58 
 59 void MainWindows::on_aboutBtn_clicked()
 60 {
 61     QString info = "本工具只针对于海洋表温数据进行天平均处理,对于缺失数据已经进行了插值处理.";
 62     infoshow(info);
 63     info = "如有问题讨论或反馈,请联系制作人";
 64     infoshow(info);
 65     info = "制作:thyou,邮箱:thyou@vip.qq.com,时间:2018年12月22日";
 66     infoshow(info);
 67 }
 68 
 69 void MainWindows::on_closeBtn_clicked()
 70 {
 71     if(mdsst_thd->isRunning())
 72     {
 73         mdsst_thd->terminate();
 74         mdsst_thd->wait();
 75         mdsst_thd->quit();
 76     }
 77     close();
 78 }
 79 
 80 void MainWindows::on_inchooseBtn_clicked()
 81 {
 82     QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this,tr("选择"),QDir::currentPath()));
 83     if(directory != "")
 84     {
 85         ui->inputledt->setText(directory);
 86     }else
 87     {
 88         ui->Infoshowtedt->append("路径选择失败!");
 89     }
 90 }
 91 
 92 void MainWindows::on_outchooseBtn_clicked()
 93 {
 94     QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this,tr("选择"),QDir::currentPath()));
 95     if(directory != "")
 96     {
 97         ui->outputledt->setText(directory);
 98     }else
 99     {
100         ui->Infoshowtedt->append("路径选择失败!");
101     }
102 }
103 
104 void MainWindows::completedInfoShow(QString info)
105 {
106     ui->completedledt->setText(info);
107 }
108 
109 void MainWindows::fileNumInfoShow(QString info)
110 {
111     ui->fileNumledt->setText(info);
112 }
113 
114 void MainWindows::compedFileNumshow(QString info)
115 {
116     ui->compedFileNumledt->setText(info);
117 }
118 

  工具界面布局如下:

image

  核心功能实现步骤:获取输入路径下的所有nc文件,形成文件列表,根据列表的size进行循环,循环内部对单个文件执行单个文件的操作,该操作包括逐层插值函数、平均值计算、数据整理成三维点Point3D数据、写入文本等内容,循环结束,则处理完毕;为了方便用户使用,辅助添加了实时处理信息显示,批量文件处理进度等功能。具体源代码如下:

h文件

  1 #ifndef MDSST_H
  2 #define MDSST_H
  3 
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8 #include <string>
  9 #include 
 10 #include 
 11 #include 
 12 #include 
 13 #include 
 14 #include 
 15 #include 
 16 #include 
 17 
 18 #pragma execution_character_set("utf-8")
 19 
 20 class MDSST : public QObject
 21 {
 22     Q_OBJECT
 23 public:
 24     explicit MDSST(QObject *parent = nullptr);
 25 
 26     void getNcFileNamesList(const QString &filePath, QStringList &tempFileList);
 27 
 28     void fileRead(QString filePath,NC_OBJ &temp_Obj,QString tempMark);
 29 
 30     //反距离权重插值函数
 31     void inverDistToPowerItpl(GRD_OBJ itplGRDOBJ , GRD_OBJ &itpledGRDOBJ , double pixResoultion);
 32 
 33     void inverDistToPowerItplProcess(NC_OBJ  &temp_Obj);
 34 
 35     void dataArrangement(GRD_OBJ temp_obj, QVectorfloat>> tempAT, QList &tempPL);
 36 
 37     void crateTxtFile(QString fileSavePath, QList tempPointList);
 38 
 39     void avageOfDailySST(NC_OBJ  temp_Obj, GRD_OBJ &temp_ATInfo, QVectorfloat>> &tempAvageTemper);
 40 
 41     void createFilePath(QString savePath, QString fileNam, QString &filePath);
 42 signals:
 43     void showInfo(QString tempInfo);
 44 
 45     void showCompedInfo(QString info);
 46 
 47     void showFileNumInfo(QString info);
 48 
 49     void showCompedFileNum(QString info);
 50 
 51 public slots:
 52     void startprocess(QString inputFilePath,QString outputFilePath);
 53 };
 54 
 55 #endif // MDSST_H

cpp文件

  1 #include "mdsst.h"
  2 
  3 MDSST::MDSST(QObject *parent) : QObject(parent){}
  4 
  5 void MDSST::getNcFileNamesList(const QString &filePath, QStringList &tempFileList)
  6 {
  7     // 文件路径信息是否为空判断
  8     if(filePath == NULL){
  9         QString info = "输入路径有误!";
 10         emit showInfo(info);
 11         return;
 12     } else{
 13         QString info = "检索当前路径下的文件...";
 14         emit showInfo(info);
 15     }
 16 
 17     QDir dir(filePath);
 18     QStringList nameFilters;
 19     nameFilters << "*.nc" ;
 20     tempFileList = dir.entryList(nameFilters, QDir::Files|QDir::Readable, QDir::Name);
 21 
 22     QString info = "文件检索已完成,文件数量:";
 23     info += tempFileList.size();
 24     emit showInfo(info);
 25 }
 26 
 27 void MDSST::fileRead(QString filePath,NC_OBJ &temp_Obj,QString tempMark)
 28 {
 29     QByteArray  fpArr       = filePath.toLocal8Bit();
 30     const char* ncFilePath  = fpArr.data();
 31 
 32     GDALAllRegister();
 33     // 设置支持中文路径
 34     CPLSetConfigOption("GDAL_FILENAME_IS_UTF8","NO");
 35     // 以只读方式打开数据集
 36     GDALDataset* fileDataset = (GDALDataset*) GDALOpen(ncFilePath,GA_ReadOnly);
 37     if (fileDataset == NULL)
 38     {
 39         QString info = "文件路径有误!";
 40         emit showInfo(info);
 41         return;
 42     }else{
 43         QString info = "读取文件...";
 44         emit showInfo(info);
 45     }
 46 
 47     // 获得数据的字符串,可以打印出来看看自己需要的数据在那
 48     char** sublist = GDALGetMetadata((GDALDatasetH) fileDataset,"SUBDATASETS");
 49 
 50     int iCount = CSLCount(sublist);
 51     if(iCount <= 0){
 52         QString info = filePath + "数据为空!";
 53         emit showInfo(info);
 54         GDALClose((GDALDriverH)fileDataset);
 55         return;
 56     }
 57 
 58     // 存储数据集信息
 59     for(int i = 0; sublist[i] != NULL;i++){
 60 
 61         // 打印数据集表述信息
 62         // qDebug() << sublist[i] << endl;
 63 
 64         if(i%2 != 0){
 65             continue;
 66         }
 67 
 68         QString tmpstr = sublist[i];
 69         tmpstr = tmpstr.mid(tmpstr.indexOf("=")+1);
 70         QByteArray  tmpstrArr = tmpstr.toLocal8Bit();
 71         const char* tmpc_str  = tmpstrArr.data();
 72 
 73         QString tmpdsc = sublist[i+1];
 74         tmpdsc = tmpdsc.mid(tmpdsc.indexOf("=")+1);
 75 
 76         GDALDataset* hTmpDt = (GDALDataset*)GDALOpen(tmpc_str,GA_ReadOnly);//打开该数据
 77 
 78         if (hTmpDt != NULL)
 79         {
 80             temp_Obj.dataSet.push_back(tmpc_str);
 81         }
 82         if(&temp_Obj.dSDesc != NULL){
 83             temp_Obj.dSDesc.push_back(tmpdsc);
 84         }
 85         GDALClose(hTmpDt);
 86     }
 87 
 88     temp_Obj.dSAttrInfo.resize(temp_Obj.dataSet.size());
 89     temp_Obj.dSValue.resize(temp_Obj.dataSet.size());
 90 
 91     QString qtmpdsc = temp_Obj.dSDesc[0];
 92     QStringList qtmpdsclist = qtmpdsc.split("");
 93     QString dataset_name = qtmpdsclist[1];
 94 
 95 
 96     for(int dsIdx = 0; dsIdx < temp_Obj.dataSet.size(); dsIdx++){
 97         string tempInfo = temp_Obj.dataSet[dsIdx].toStdString();
 98         GDALDataset* tempDt   = (GDALDataset*)GDALOpen(tempInfo.data(), GA_ReadOnly);
 99 
100         double adfGeoTransform[6];
101         if( tempDt->GetGeoTransform(adfGeoTransform) != CE_None ){
102             QString info = filePath + "投影信息不存在!";
103             emit showInfo(info);
104             return;
105         }
106         temp_Obj.dSAttrInfo[dsIdx].bCount = tempDt->GetRasterCount();
107         temp_Obj.dSValue[dsIdx].resize(tempDt->GetRasterCount());
108 
109         /***************************************************************
110          *          大隅-吐噶啦海峡
111          *          范围:
112          *              126 E ~ 135E
113          *              26  N ~ 34 N
114          * *************************************************************/
115 
116         int  iStartX = floor((126 - adfGeoTransform[0]) / adfGeoTransform[1]);
117         int  iStartY = floor((34  - adfGeoTransform[3]) / adfGeoTransform[5]);
118         int  iSizeX  = floor((135 - 126) / adfGeoTransform[1]);
119         int  iSizeY  = floor((26  - 34 ) / adfGeoTransform[5]);
120 
121         temp_Obj.dSAttrInfo[dsIdx].orgLocat.x   = adfGeoTransform[0] + iStartX*adfGeoTransform[1] + iStartY*adfGeoTransform[2];
122         temp_Obj.dSAttrInfo[dsIdx].orgLocat.y   = adfGeoTransform[3] + iStartX*adfGeoTransform[4] + iStartY*adfGeoTransform[5];
123         temp_Obj.dSAttrInfo[dsIdx].pixelSize.x  = adfGeoTransform[1];
124         temp_Obj.dSAttrInfo[dsIdx].pixelSize.y  = adfGeoTransform[5];
125         temp_Obj.dSAttrInfo[dsIdx].rXSize       = iSizeX;
126         temp_Obj.dSAttrInfo[dsIdx].rYSize       = iSizeY;
127 
128         QString dataSetNam = temp_Obj.dataSet[dsIdx];
129         QString info = "正在解析" + dataSetNam + "...";
130         emit showInfo(info);
131 
132         int pbnMax = tempDt->GetRasterCount();
133         int *pBandMap = new int[pbnMax];
134         for(int pbn = 0; pbn135             pBandMap[pbn] = pbn + 1;
136         }
137         /**********获取数据类型,定义缓存空间大小*******************
138 
139         GDALRasterBand* pBand = tempDt->GetRasterBand(1);
140         GDALDataType dataType = pBand->GetRasterDataType();
141 
142         ********************************************************/
143 
144         float* lineData = new float[pbnMax*iSizeX*iSizeY];
145         tempDt->RasterIO(GF_Read, iStartX, iStartY, iSizeX, iSizeY,lineData,iSizeX, iSizeY, GDT_Float32, pbnMax, pBandMap, 0, 0, 0);
146 
147         int BandNumMax  = pbnMax;
148         int iLineMax    = iSizeY;
149         int iPixelMax   = iSizeX;
150 
151         for(int BandNum = 0;BandNum152             int tempBN = BandNum + 1;
153 
154             temp_Obj.dSValue[dsIdx][BandNum].resize(iLineMax);
155             for (int iLine = 0; iLine < iLineMax; iLine++)
156             {
157                 temp_Obj.dSValue[dsIdx][BandNum][iLine].resize(iPixelMax);
158                 for (int iPixel = 0; iPixel < iPixelMax; iPixel++)
159                 {
160                     int index = BandNum * iLineMax * iPixelMax + iLine * iPixelMax + iPixel;
161                     temp_Obj.dSValue[dsIdx][BandNum][iLine][iPixel] = lineData[index];
162                 }
163             }
164 
165             info = "波段" + QString::number(tempBN) + "已完成.";
166             emit showInfo(info);
167         }
168 
169         delete [] lineData;
170         lineData = NULL;
171         GDALClose((GDALDatasetH)tempDt);
172 
173         info = dataSetNam + "解析已完成.";
174         emit showInfo(info);
175     }
176 
177     QString info = filePath + "读取已完成.";
178     emit showInfo(info);
179     GDALClose(fileDataset);
180 }
181 
182 void MDSST::inverDistToPowerItpl(GRD_OBJ itplGRDOBJ,GRD_OBJ &itpledGRDOBJ,double pixResoultion)
183 {
184     // 相关参数信息是否为空判断
185     if(pixResoultion == NULL){
186         qDebug() << __FUNCTION__
187                  << "tempPoint3d: data is empty!"
188                  << __LINE__
189                  << endl;
190         return;
191     }else if(itplGRDOBJ.dSAttrInfo.rXSize == NULL){
192         qDebug() << __FUNCTION__
193                  << "tempGRDOBJ: data is empty!"
194                  << __LINE__
195                  << endl;
196         return;
197     }else{
198         QString info = "对当前文件进行插值处理...";
199         emit showInfo(info);
200         qDebug() << "start inverDistToPowerItpl ..." << endl;
201     }
202 
203     // 有效数据筛选,剔除标记值
204     QList filterPoint3d;
205     for(int i = 0;i206         for(int j = 0;j207 
208             double tempValue = itplGRDOBJ.dSValue[i][j];
209             if(tempValue == -999){
210                 continue;
211             }
212             Point3D tempP3d;
213             tempP3d.y = i + 1;
214             tempP3d.x = j + 1;
215             tempP3d.z = tempValue;
216             filterPoint3d.append(tempP3d);
217         }
218     }
219 
220     // 定义散点总数
221     int nPoints = filterPoint3d.size();
222 
223     // 定义插值空间范围
224     double dfXMin = 0;
225     double dfXMax = itplGRDOBJ.dSAttrInfo.rXSize;
226     double dfYMin = 0;
227     double dfYMax = itplGRDOBJ.dSAttrInfo.rYSize;
228 
229     // 定义散点坐标信息
230     double* padfX = new double[nPoints];
231     double* padfY = new double[nPoints];
232     double* padfZ = new double[nPoints];
233 
234     for(int i = 0;i235         padfX[i] = filterPoint3d[i].x;
236         padfY[i] = filterPoint3d[i].y;
237         padfZ[i] = filterPoint3d[i].z;
238     }
239 
240     int nXSize = (dfXMax-dfXMin)*abs(itplGRDOBJ.dSAttrInfo.pixelSize.x)/pixResoultion;
241     int nYSize = (dfYMax-dfYMin)*abs(itplGRDOBJ.dSAttrInfo.pixelSize.y)/pixResoultion;
242 
243     // 构造插值算法参数并设置差值参数值
244     GDALGridInverseDistanceToAPowerOptions* poOptions = new GDALGridInverseDistanceToAPowerOptions();
245     // 权重指数
246     poOptions->dfPower   = 2;
247     // 搜索椭圆第一半径
248     poOptions->dfRadius1 = 20;
249     // 搜索椭圆第二半径
250     poOptions->dfRadius2 = 15;
251 
252     //定义插值后输出数据组
253     float* lineData = new float[nXSize*nYSize];
254 
255     //反距离权重插值(IDW)
256     GDALGridCreate(GGA_InverseDistanceToAPower,poOptions,nPoints,padfX,padfY,padfZ,dfXMin,dfXMax,dfYMin,dfYMax,nXSize,nYSize,GDT_Float32,lineData,NULL,NULL);
257 
258     //数据信息整理
259     itpledGRDOBJ.dataSet = itplGRDOBJ.dataSet;
260     itpledGRDOBJ.dSDesc  = itplGRDOBJ.dSDesc;
261 
262     itpledGRDOBJ.dSAttrInfo.bCount = itplGRDOBJ.dSAttrInfo.bCount;
263     itpledGRDOBJ.dSAttrInfo.orgLocat = itplGRDOBJ.dSAttrInfo.orgLocat;
264 
265     if(itplGRDOBJ.dSAttrInfo.pixelSize.x == abs(itplGRDOBJ.dSAttrInfo.pixelSize.x)){
266         itpledGRDOBJ.dSAttrInfo.pixelSize.x = pixResoultion;
267     }else{
268         itpledGRDOBJ.dSAttrInfo.pixelSize.x = -1 * pixResoultion;
269     }
270     if(itplGRDOBJ.dSAttrInfo.pixelSize.x == abs(itplGRDOBJ.dSAttrInfo.pixelSize.x)){
271         itpledGRDOBJ.dSAttrInfo.pixelSize.y = pixResoultion;
272     }else{
273         itpledGRDOBJ.dSAttrInfo.pixelSize.y = -1 * pixResoultion;
274     }
275 
276     itpledGRDOBJ.dSAttrInfo.rXSize = nXSize;
277     itpledGRDOBJ.dSAttrInfo.rYSize = nYSize;
278 
279     // 插值数据存储
280     QVectorfloat>> tempValue;
281     tempValue.resize(nYSize);
282     for(int lineNum = 0;lineNum283         tempValue[lineNum].resize(nXSize);
284         for(int pixalNum = 0;pixalNum285             tempValue[lineNum][pixalNum] = lineData[lineNum*nXSize+pixalNum];
286         }
287     }
288 
289     itpledGRDOBJ.dSValue.append(tempValue);
290 
291     delete poOptions;
292     delete [] lineData;
293 
294     QString info = "插值处理完成.";
295     emit showInfo(info);
296 }
297 
298 void MDSST::avageOfDailySST(NC_OBJ  temp_Obj,GRD_OBJ &temp_ATInfo,QVectorfloat>> &tempAvageTemper)
299 {
300     // 数据存储信息是否为空判断
301     if(temp_Obj.dSValue[0].size() == 0){
302         return;
303     }else if(temp_Obj.dSValue[0][0].size() == 0){
304         return;
305     }else if(temp_Obj.dSValue[0][0][0].size() == 0){
306         return;
307     }else{
308         //数据值存在
309         qDebug() << "check data info completed,no error." << endl;
310         QString info = "对插值后的数据进行检查...";
311         emit showInfo(info);
312     }
313 
314     //存储当前的数据信息
315     if(temp_ATInfo.dataSet.isEmpty()){
316         temp_ATInfo.dataSet = temp_Obj.dataSet[0];
317         temp_ATInfo.dSDesc  = temp_Obj.dSDesc[0];
318 
319         temp_ATInfo.dSAttrInfo = temp_Obj.dSAttrInfo[0];
320         temp_ATInfo.dSAttrInfo.bCount = 1;
321     }
322 
323     // 插值处理--反距离定权插值
324     inverDistToPowerItplProcess(temp_Obj);
325 
326     // 日均值计算 处理对象为SST表温数据
327     qDebug() << "start calc average temperature of sea..." << endl;
328     QString info = "对当前数据进行日平均计算...";
329     emit showInfo(info);
330     tempAvageTemper.resize(temp_Obj.dSValue[0][0].size());
331     for(int i = 0;i < temp_Obj.dSValue[0][0].size();i++){
332 
333         tempAvageTemper[i].resize(temp_Obj.dSValue[0][0][i].size());
334         for(int j = 0;j < temp_Obj.dSValue[0][0][i].size();j++){
335 
336             float   tempNum     = 0;
337             int     avgNum      = 0;
338             float   tempMark    = 0;
339 
340             for(int k = 0;k < temp_Obj.dSValue[0].size();k++){
341                 float tempValue = temp_Obj.dSValue[0][k][i][j];
342                 if(tempValue == -999){
343                     tempMark = temp_Obj.dSValue[0][k][i][j];
344                     continue;
345                 }
346                 avgNum  += 1;
347                 tempNum += temp_Obj.dSValue[0][k][i][j];
348             }
349 
350             if(avgNum == 0){
351                 tempAvageTemper[i][j] = tempMark;
352             }else{
353                 tempNum = tempNum/avgNum;
354                 tempAvageTemper[i][j] = tempNum;
355             }
356 
357         }
358     }
359     qDebug() << "Daily mean temperature of sea_surface is received." << endl;
360     info = "计算完成.";
361     emit showInfo(info);
362 }
363 
364 void MDSST::inverDistToPowerItplProcess(NC_OBJ  &temp_Obj)
365 {
366     // 数据存储信息是否为空判断
367     if(temp_Obj.dSValue[0].size() == 0){
368         qDebug() << __FUNCTION__
369                  << "temp_Obj: data is empty!"
370                  << __LINE__
371                  << endl;
372         return;
373     }else if(temp_Obj.dSValue[0][0].size() == 0){
374         qDebug() << __FUNCTION__
375                  << "temp_Obj: data is empty!"
376                  << __LINE__
377                  << endl;
378         return;
379     }else if(temp_Obj.dSValue[0][0][0].size() == 0){
380         qDebug() << __FUNCTION__
381                  << "temp_Obj: data is empty!"
382                  << __LINE__
383                  << endl;
384         return;
385     }else{
386         //数据值存在
387         qDebug() << "check data info completed,ItplProcess start ..." << endl;
388     }
389 
390     GRD_OBJ   itplGRDOBJ;
391 
392     for(int dsIdx = 0; dsIdx < temp_Obj.dataSet.size(); dsIdx++){
393 
394         itplGRDOBJ.dataSet = temp_Obj.dataSet[dsIdx];
395         itplGRDOBJ.dSDesc  = temp_Obj.dSDesc[dsIdx];
396 
397         itplGRDOBJ.dSAttrInfo = temp_Obj.dSAttrInfo[dsIdx];
398         itplGRDOBJ.dSAttrInfo.bCount = 1;
399 
400         for(int BandNum = 0;BandNum401 
402             itplGRDOBJ.dSValue.append(temp_Obj.dSValue[dsIdx][BandNum]);
403             GRD_OBJ itpledGRDOBJ;
404             inverDistToPowerItpl(itplGRDOBJ,itpledGRDOBJ,0.25);
405             temp_Obj.dSValue[dsIdx][BandNum].clear();
406             temp_Obj.dSValue[dsIdx][BandNum].append(itpledGRDOBJ.dSValue);
407         }
408     }
409 
410     qDebug() << "ItplProcess completed." << endl;
411 }
412 
413 void MDSST::dataArrangement(GRD_OBJ temp_obj, QVectorfloat>> tempAT, QList &tempPL)
414 {
415     // 路径信息是否为空判断
416     if(temp_obj.dSAttrInfo.rXSize == NULL){
417         qDebug() << __FUNCTION__
418                  << "temp_obj:data is empty!"
419                  << __LINE__
420                  << endl;
421         return;
422     }else if(tempAT.size() == 0){
423         qDebug() << __FUNCTION__
424                  << "tempAT:data is empty!"
425                  << __LINE__
426                  << endl;
427         return;
428     }else{
429         qDebug() << "start dataArrangement ...." << endl;
430         QString info = "整理当前成果数据...";
431         emit showInfo(info);
432     }
433 
434     double iXStart = temp_obj.dSAttrInfo.orgLocat.x;
435     double iYStart = temp_obj.dSAttrInfo.orgLocat.y;
436     double iXPixel = temp_obj.dSAttrInfo.pixelSize.x;
437     double iYPixel = temp_obj.dSAttrInfo.pixelSize.y;
438 
439     double iXSize  = temp_obj.dSAttrInfo.rXSize;
440     double iYSize  = temp_obj.dSAttrInfo.rYSize;
441 
442     for(int i = 0;i443         double B = iYStart + i * iYPixel;
444         for(int j = 0;j445             double L = iXStart + j * iXPixel;
446 
447             Point3D tempP;
448             tempP.x = B;
449             tempP.y = L;
450             tempP.z = tempAT[i][j];
451 
452             tempPL.append(tempP);
453         }
454     }
455 
456     QString info = "整理完毕.";
457     emit showInfo(info);
458     qDebug() << "Point infomation arrange completed!" << endl;
459 }
460 
461 void MDSST::createFilePath(QString savePath, QString fileNam, QString &filePath)
462 {
463     QDateTime local(QDateTime::currentDateTime());
464     QString localTime = local.toString("yyyyMMdd");
465     //文件名称格式为SEAFLUX-OSB-CDR_V02R00_SST_D20060101_C20160824.nc
466     QString tempStr = fileNam.split("_")[3];
467     filePath = savePath + "/SEAFLUX-OSB-CDR_V02R00_SST_" + tempStr+ "_C" + localTime + ".txt";
468 }
469 
470 void MDSST::crateTxtFile(QString fileSavePath, QList tempPointList)
471 {
472     QFile file(fileSavePath);
473     /******************************************************************
474     if(!file.open(QIODevice::WriteOnly))
475     {
476         qDebug() << "Open failed, please check the file path!" << endl;
477         return;
478     }
479     ******************************************************************/
480 
481     QString info = "写入文件" + fileSavePath;
482     emit showInfo(info);
483     if(file.open(QFile::ReadWrite)){
484         for(int i = 0; i485 
486             /******************************************************************
487             QString tempPointInfo = QString::number(tempPointList[i].x) + "," +
488                                     QString::number(tempPointList[i].y) + "," +
489                                     QString::number(tempPointList[i].z) + "\n";
490             file.write(tempPointInfo.toUtf8());
491             ******************************************************************/
492             QTextStream outPut(&file);
493             outPut << tempPointList[i].x
494                    <<","
495                    << tempPointList[i].y
496                    <<","
497                    << tempPointList[i].z
498                    <499         }
500     }else{
501         qDebug() << "Open failed, please check the file path!" << endl;
502         return;
503     }
504 
505     file.close();
506 
507     QString fileName = fileSavePath.split("/")[fileSavePath.split("/").size()-1];
508     qDebug() << "File "
509              << fileName
510              << "write completed!"
511              << endl;
512 
513     info = fileName + "写入完成.";
514     emit showInfo(info);
515 }
516 
517 void MDSST::startprocess(QString inputFilePath,QString outputFilePath)
518 {
519 
520     inputFilePath  = inputFilePath.replace(QString("\\"),QString("/"));
521     outputFilePath = outputFilePath.replace(QString("\\"),QString("/"));
522 
523     QStringList fileList;
524     getNcFileNamesList(inputFilePath,fileList);
525 
526     emit showFileNumInfo(QString::number(fileList.size()));
527     for(int i = 0;i528         QString filePath = inputFilePath + "/" + fileList[i];
529 
530         NC_OBJ     Obj;
531         GRD_OBJ aTInfo;
532         QList pList;
533         QVectorfloat>> avageTemper;
534 
535         QString tempinfo = QString::number((i+0.3)*100/fileList.size()) + "%";
536         emit showCompedInfo(tempinfo);
537         fileRead(filePath,Obj,"SST");
538 
539         tempinfo = QString::number((i+0.6)*100/fileList.size()) + "%";
540         emit showCompedInfo(tempinfo);
541         avageOfDailySST(Obj,aTInfo,avageTemper);
542 
543         tempinfo = QString::number((i+0.9)*100/fileList.size()) + "%";
544         emit showCompedInfo(tempinfo);
545         dataArrangement(aTInfo,avageTemper,pList);
546 
547         QString savePath = "";
548         createFilePath(outputFilePath,fileList[i],savePath);
549         crateTxtFile(savePath,pList);
550         tempinfo = QString::number((i+1)*100/fileList.size()) + "%";
551         emit showCompedInfo(tempinfo);
552 
553         tempinfo = QString::number(i + 1);
554         emit showCompedFileNum(tempinfo);
555     }
556     emit showInfo("所有文件已处理完毕!");
557 }

  文件输出以后,即可进行导入到Surfer软件中,进行进一步的编辑操作。

运行结果

  原始数据截图

image

  程序运行截图

image

  成果数据截图

image

  至此,小工具设计完成了!

  源码我已经上传至博客园了,下载地址:https://files.cnblogs.com/files/thyou/CT_MDSST.7z,希望能对处理SST数据这方面的同学有一丝帮助。

致谢

  最后,感谢李民录老师前期对我在GDAL库方面的技术指导!