基于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 #include5 #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
工具界面布局如下:
核心功能实现步骤:获取输入路径下的所有nc文件,形成文件列表,根据列表的size进行循环,循环内部对单个文件执行单个文件的操作,该操作包括逐层插值函数、平均值计算、数据整理成三维点Point3D数据、写入文本等内容,循环结束,则处理完毕;为了方便用户使用,辅助添加了实时处理信息显示,批量文件处理进度等功能。具体源代码如下:
h文件
1 #ifndef MDSST_H 2 #define MDSST_H 3 4 #include5 #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, QVector float>> tempAT, QList &tempPL); 36 37 void crateTxtFile(QString fileSavePath, QList tempPointList); 38 39 void avageOfDailySST(NC_OBJ temp_Obj, GRD_OBJ &temp_ATInfo, 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; 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;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 filterPoint3d; 205 for(int i = 0;i 206 for(int j = 0;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 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 float>> tempValue; 281 tempValue.resize(nYSize); 282 for(int lineNum = 0;lineNum 283 tempValue[lineNum].resize(nXSize); 284 for(int pixalNum = 0;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 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 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 float>> 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;i 443 double B = iYStart + i * iYPixel; 444 for(int j = 0;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 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 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 < 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 528 QString filePath = inputFilePath + "/" + fileList[i]; 529 530 NC_OBJ Obj; 531 GRD_OBJ aTInfo; 532 QList pList; 533 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库方面的技术指导!