基于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 <QWidget>
5 #include <QObject>
6 #include <QString>
7 #include <QDebug>
8 #include <QDir>
9 #include <QFileDialog>
10 #include <QThread>
11 #include <QIcon>
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 <QThread> 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
工具界面布局如下:
核心功能实现步骤:获取输入路径下的所有nc文件,形成文件列表,根据列表的size进行循环,循环内部对单个文件执行单个文件的操作,该操作包括逐层插值函数、平均值计算、数据整理成三维点Point3D数据、写入文本等内容,循环结束,则处理完毕;为了方便用户使用,辅助添加了实时处理信息显示,批量文件处理进度等功能。具体源代码如下:
h文件
1 #ifndef MDSST_H
2 #define MDSST_H
3
4 #include <QObject>
5 #include <vector>
6 #include <gdal_priv.h>
7 #include <QVector>
8 #include <string>
9 #include <QString>
10 #include <QStringList>
11 #include <QDebug>
12 #include <odplib_extd.h>
13 #include <QDir>
14 #include <QFileDialog>
15 #include <QDateTime>
16 #include <gdalgrid.h>
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, QVector<QVector<float>> tempAT, QList<Point3D> &tempPL);
36
37 void crateTxtFile(QString fileSavePath, QList<Point3D> tempPointList);
38
39 void avageOfDailySST(NC_OBJ temp_Obj, GRD_OBJ &temp_ATInfo, QVector<QVector<float>> &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; pbn<pbnMax;pbn++){
135 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;BandNum<BandNumMax;BandNum++){
152 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<Point3D> filterPoint3d;
205 for(int i = 0;i<itplGRDOBJ.dSValue.size();i++){
206 for(int j = 0;j<itplGRDOBJ.dSValue[i].size();j++){
207
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;i<nPoints;i++){
235 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 QVector<QVector<float>> tempValue;
281 tempValue.resize(nYSize);
282 for(int lineNum = 0;lineNum<nYSize;lineNum++){
283 tempValue[lineNum].resize(nXSize);
284 for(int pixalNum = 0;pixalNum<nXSize;pixalNum++){
285 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,QVector<QVector<float>> &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;BandNum<temp_Obj.dSAttrInfo[dsIdx].bCount;BandNum++){
401
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, QVector<QVector<float>> tempAT, QList<Point3D> &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;i<iYSize;i++){
443 double B = iYStart + i * iYPixel;
444 for(int j = 0;j<iXSize;j++){
445 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<Point3D> 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; i<tempPointList.size();i++){
485
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 <<endl;
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;i<fileList.size();i++){
528 QString filePath = inputFilePath + "/" + fileList[i];
529
530 NC_OBJ Obj;
531 GRD_OBJ aTInfo;
532 QList<Point3D> pList;
533 QVector<QVector<float>> 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软件中,进行进一步的编辑操作。
运行结果
原始数据截图
程序运行截图
成果数据截图
至此,小工具设计完成了!
源码我已经上传至博客园了,下载地址:https://files.cnblogs.com/files/thyou/CT_MDSST.7z,希望能对处理SST数据这方面的同学有一丝帮助。
致谢
最后,感谢李民录老师前期对我在GDAL库方面的技术指导!
基于GDAL库海洋表温日平均计算工具设计与实现 C++版的更多相关文章
- 基于GDAL库,读取.nc文件(以海洋表温数据为例)C++版
对于做海洋数据处理的同学,会经常遇到nc格式的文件,nc文件的格式全称是NetCDF,具体的详细解释请查询官网[https://www.unidata.ucar.edu/software/netcdf ...
- 关于基于GDAL库QT软件平台下C++语言开发使用说明
背景前提 地理空间数据抽象库(GDAL)是一个用于读取和编写栅格和矢量地理空间数据格式的计算机软件库,由开源地理空间基金会在许可的X / MIT风格免费软件许可下发布. 作为一个库,它为调用应用程序提 ...
- 基于GDAL库,读取海洋风场数据(.nc格式)c++版
经过这一段时间的对海洋数据的处理,接触了大量的与海洋相关的数据,例如海洋地形.海洋表面温度.盐度.湿度.云场.风场等数据,除了地形数据是grd格式外,其他的都是nc格式的数据.本文将以海洋风场数据为例 ...
- 基于GDAL库,读取.grd文件(以海洋地形数据为例)C++版
技术背景 海洋地形数据主要是通过美国全球地形起伏数据(GMT)获得,数据格式为grd(GSBG)二进制数据,打开软件通过是Surfer软件,surfer软件可进行数据的编辑处理,以及进一步的可视化表达 ...
- 基于GDAL库,读取.grd文件(以海洋地形数据为例)Java版
技术背景 海洋地形数据主要是通过美国全球地形起伏数据(GMT)获得,数据格式为grd(GSBG)二进制数据,打开软件通过是Surfer软件,surfer软件可进行数据的编辑处理,以及进一步的可视化表达 ...
- GDAL库简介以及在Windows下编译过程
GDAL(Geospatial Data Abstraction Library,地理空间数据抽象库)是一个在X/MIT许可协议下的开源栅格空间数据转换库.官网http://www.gdal.org/ ...
- 基于jsmpeg库下使用ffmpeg创建视频流连接websocket中继器传输视频并播放
这个功能的基本工作是这样的: 1.使用node运行jsmpeg库下的websocket-relay.js文件,这个文件的作用是创建一个websocket视频传输中继器 2.运行ffmpeg,将输出发送 ...
- LineCalc,一个基于Lex&Yacc的简单行计算工具
LineCalc是基于Lex&Yacc的一个简单的行计算工具,支持常见的运算符和部分POSIX中定义于math.h中的数学函数:同时,LineCalc还提供了一个简单的错误处理模块,能检测公式 ...
- 基于Struts2框架实现登录案例 之 使用Struts2标签库简化表单+继承ActionSupport完成输入交验
一,使用Struts2标签库简化表单 在文章[基于Struts2框架实现登录案例]的基础上,通过使用Struts标签库可以简化登录页面login2.jsp <%@ page language=& ...
随机推荐
- pymysql防止SQL注入的方法
import pymysql class Db(object): def __init__(self): self.conn = pymysql.connect(host="192.168. ...
- [ Flask ] myblog_flask问题集(RESTfull风格)
VUE问题 前端VUE怎么捕获所有404NOT FOUND的路由呢? [ 解决方案 ] vue-router路由守卫,参考文档:动态路由匹配 对于路由.../edit/<id>,自己能编辑 ...
- 第10组 Alpha冲刺 总结(组长)
1.基本情况 组长博客链接:https://www.cnblogs.com/cpandbb/p/14007413.html 答辩总结: ·产品偏离了最开始的方向,地图和刷一刷功能做得没那么好,外卖订单 ...
- Python的内存管理和垃圾回收机制
内存管理 Python解释器由c语言开发完成,py中所有的操作最终都由底层的c语言来实现并完成,所以想要了解底层内存管理需要结合python源码来进行解释. 1. 两个重要的结构体 include/o ...
- iframe页面二次登录问题
原文链接:iframe页面二次登录问题 生产问题 问题背景 由于历史原因,公司内部系统有一些页面是基于iframe嵌入的其他系统的页面,之前一直运行正常,最近不知什么原因接连出现访问所有iframe页 ...
- Golang 常见设计模式之选项模式
熟悉 Python 开发的同学都知道,Python 有默认参数的存在,使得我们在实例化一个对象的时候,可以根据需要来选择性的覆盖某些默认参数,以此来决定如何实例化对象.当一个对象有多个默认参数时,这个 ...
- react中引入图片路劲正确但是页面上不显示或者打包后不能正常显示的问题
一.react中图片引入方式 以前我们用img引入图片只需要如下即可,在react中这样写会报错: <img src="../assets/zzsc1.png" /> ...
- [C# 学习]委托和线程
委托有点像C语言的函数指针,简单总结一下如何使用委托. 1. 声明一个委托 public delegate void LabelSetEventHandler(Label la, string str ...
- C# 同步 异步 回调 状态机 async await Demo
源码 https://gitee.com/s0611163/AsyncAwaitDemo 为什么会研究这个? 我们项目的客户端和服务端通信用的是WCF,我就想,能不能用异步的方式调用WCF服务呢?或者 ...
- VS code远程连接Linux 开发C++ 配置详细介绍
VS code 远程连接服务器,编译C++ 一.前期准备 1.VS code安装 Remote-SSH插件 2.Windows安装SSH. 3.Linux服务器连接测试. a.接通测试使用ping命令 ...