OGS
NetCdfConfigureDialog.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
5
6#include <vtkImageImport.h>
7
8#include <QMessageBox>
9#include <QSettings>
10
11#include "GeoLib/Raster.h"
12#include "MathLib/Point3d.h"
13#include "MeshLib/MeshEnums.h"
16#include "VtkVis/VtkRaster.h"
17
18using namespace netCDF;
19
20// Constructor
22 QDialog* parent)
23 : QDialog(parent),
24 _currentFile(fileName.c_str(), NcFile::read),
25 _currentMesh(nullptr),
26 _currentRaster(nullptr),
27 _currentPath(fileName)
28{
29 setupUi(this);
30
31 int const idx =
32 setVariableSelect(); // set up variables of the file in the combobox
33 comboBoxVariable->setCurrentIndex(
34 idx); // pre-select the variable with the biggest number of
35 // dimensions...valueWithMaxDim()
37 _currentFile.getVar(comboBoxVariable->itemText(idx).toStdString());
38
40
41 lineEditName->setText(setName());
42
43 this->radioMesh->setChecked(true);
44}
45
50
51// Instructions if the OK-Button has been pressed.
53{
54 QMessageBox valueErrorBox;
55 if (_currentVar.getDimCount() < 2)
56 {
57 valueErrorBox.setText("Selected Variable has not enough dimensions.");
58 valueErrorBox.exec();
59 }
60 else if (doubleSpinBoxDim2Start->value() ==
61 doubleSpinBoxDim2Start->maximum())
62 {
63 valueErrorBox.setText("Lon has invalid extend.");
64 valueErrorBox.exec();
65 }
66 else if (doubleSpinBoxDim1Start->value() ==
67 doubleSpinBoxDim1Start->maximum())
68 {
69 valueErrorBox.setText("Lat has invalid extend.");
70 valueErrorBox.exec();
71 }
72 else
73 {
75 this->done(QDialog::Accepted);
76 }
77}
78
79// Instructions if the Cancel-Button has been pressed.
81{
82 this->done(QDialog::Rejected);
83}
84
86{
87 std::string const var_name = comboBoxVariable->currentText().toStdString();
88 _currentVar = _currentFile.getVar(var_name);
90}
91
92// set up x-axis/lat
94{
95 double firstValue = 0, lastValue = 0;
96 unsigned size = 0;
97 getDimEdges(comboBoxDim1->currentText().toStdString(), size, firstValue,
98 lastValue);
99 doubleSpinBoxDim1Start->setValue(firstValue);
100 doubleSpinBoxDim1End->setValue(lastValue);
101 doubleSpinBoxResolution->setValue(getResolution());
102}
103
104// set up y-axis/lon
106{
107 if (_currentVar.getDimCount() > 1)
108 {
109 double firstValue = 0, lastValue = 0;
110 unsigned size = 0;
111 getDimEdges(comboBoxDim2->currentText().toStdString(), size, firstValue,
112 lastValue);
113 doubleSpinBoxDim2Start->setValue(firstValue);
114 doubleSpinBoxDim2End->setValue(lastValue);
115 }
116}
117
118// set up time
120{
121 if (_currentVar.getDimCount() > 2)
122 {
123 double firstValue = 0, lastValue = 0;
124 unsigned size = 0;
125 getDimEdges(comboBoxDim3->currentText().toStdString(), size, firstValue,
126 lastValue);
127 dateTimeEditDim3->setValue(static_cast<int>(firstValue));
128 dateTimeEditDim3->setMinimum(static_cast<int>(firstValue));
129 dateTimeEditDim3->setMaximum(static_cast<int>(lastValue));
130 lineEditName->setText(setName());
131 }
132}
133
134// set up additional dimension
136{
137 if (_currentVar.getDimCount() > 3)
138 {
139 double firstValue = 0, lastValue = 0;
140 unsigned size = 0;
141 getDimEdges(comboBoxDim4->currentText().toStdString(), size, firstValue,
142 lastValue);
143 spinBoxDim4->setValue(static_cast<int>(firstValue));
144 spinBoxDim4->setMinimum(static_cast<int>(firstValue));
145 spinBoxDim4->setMaximum(static_cast<int>(lastValue));
146 }
147}
148
150{
151 int max_dim = 0;
152 int max_dim_idx = 0;
153 auto const& names = _currentFile.getVars();
154 for (auto [name, var] : names)
155 {
156 int const var_dim_count = var.getDimCount();
157 if (var_dim_count > 1)
158 {
159 comboBoxVariable->addItem(QString::fromStdString(name));
160 if (var_dim_count > max_dim)
161 {
162 max_dim = var_dim_count;
163 max_dim_idx = comboBoxVariable->count() - 1;
164 }
165 }
166 }
167 return max_dim_idx;
168}
169
171{
172 int const dim_count = _currentVar.getDimCount();
173 std::array<QComboBox*, 4> dim_box = {
174 {comboBoxDim1, comboBoxDim2, comboBoxDim3, comboBoxDim4}};
175
176 for (int i = 0; i < 4; ++i)
177 {
178 dim_box[i]->clear();
179 dim_box[i]->setEnabled(i < dim_count);
180 }
181
182 // write dimension-names into selection-boxes
183 for (int i = 0; i < dim_count; ++i)
184 {
185 for (int j = 0; j < dim_count; ++j)
186 {
187 dim_box[j]->addItem(
188 QString::fromStdString(_currentVar.getDim(i).getName()));
189 }
190 }
191 comboBoxDim1->setCurrentIndex(dim_count - 2);
193 comboBoxDim2->setCurrentIndex(dim_count - 1);
195 // time is only enabled if dim > 2
196 dateTimeEditDim3->setEnabled(dim_count > 2);
197 // 3rd data dimension is only enabled if dim > 3
198 spinBoxDim4->setEnabled(dim_count > 3);
199
200 if (dim_count > 2)
201 {
202 comboBoxDim3->setCurrentIndex(0);
204 }
205 else
206 dateTimeEditDim3->setSingleStep(0);
207
208 if (dim_count == 4)
209 {
210 comboBoxDim4->setCurrentIndex(1);
212 }
213 else
214 spinBoxDim4->setValue(0);
215}
216
217void NetCdfConfigureDialog::getDimEdges(std::string const& name, unsigned& size,
218 double& firstValue, double& lastValue)
219{
220 size = 0;
221 firstValue = 0;
222 lastValue = 0;
223 if (_currentFile.getVar(name).isNull())
224 return;
225
226 NcVar const& tmpVarOfDim = _currentFile.getVar(name);
227 if ((tmpVarOfDim.getDimCount()) == 1)
228 {
229 size = tmpVarOfDim.getDim(0).getSize();
230 tmpVarOfDim.getVar({0}, {1}, &firstValue);
231 tmpVarOfDim.getVar({size - 1}, {1}, &lastValue);
232 }
233}
234
236{
237 return dateTimeEditDim3->value();
238}
239
241{
242 NcVar const& dim3Var =
243 _currentFile.getVar(comboBoxDim4->currentText().toStdString());
244 std::vector<std::size_t> start{
245 static_cast<std::size_t>(spinBoxDim4->value())};
246 int value(0);
247 dim3Var.getVar(start, {1}, &value);
248 if (value < 0)
249 value = 0; // if the value isn't found in the array, set it to 0 as
250 // default...
251 return value;
252}
253
255{
256 if (comboBoxDim1->currentIndex() > -1)
257 {
258 NcVar const& var =
259 _currentFile.getVar(comboBoxDim1->currentText().toStdString());
260 double firstValue = 0, lastValue = 0;
261 unsigned size = 0;
262 getDimEdges(var.getName(), size, firstValue, lastValue);
263 if (size < 2)
264 {
265 return 1;
266 }
267
268 double interval = fabs(lastValue - firstValue);
269 double resolution = (double)interval / (size - 1);
270 return resolution;
271 }
272
273 return 0;
274}
275
277{
278 double originLon = 0, originLat = 0;
279 double lastLon = 0, lastLat = 0;
280 unsigned sizeLon = 0, sizeLat = 0;
281 std::string const dim1_name = comboBoxDim1->currentText().toStdString();
282 getDimEdges(dim1_name, sizeLat, originLat, lastLat);
283 std::string const dim2_name = comboBoxDim2->currentText().toStdString();
284 getDimEdges(dim2_name, sizeLon, originLon, lastLon);
285
286 // set up array
287 std::vector<double> data_array(sizeLat * sizeLon, 0);
288
289 std::vector<std::size_t> data_origin;
290 std::vector<std::size_t> data_length;
291
292 if (_currentVar.getDimCount() > 2)
293 {
294 // time
295 data_origin.push_back(getTimeStep());
296 data_length.push_back(1);
297 // 3rd dimension
298 if (_currentVar.getDimCount() > 3)
299 {
300 data_origin.push_back(getDim4());
301 data_length.push_back(1);
302 }
303 }
304
305 data_origin.push_back(0); // x-origin
306 data_origin.push_back(0); // y-origin
307 data_length.push_back(sizeLat);
308 data_length.push_back(sizeLon);
309 _currentVar.getVar(data_origin, data_length, data_array.data());
310
311 std::replace_if(
312 data_array.begin(), data_array.end(),
313 [](double const& x) { return x <= -9999; }, -9999);
314
315 double origin_x = (originLon < lastLon) ? originLon : lastLon;
316 double origin_y = (originLat < lastLat) ? originLat : lastLat;
317 MathLib::Point3d origin(std::array<double, 3>{{origin_x, origin_y, 0}});
318 double resolution = (doubleSpinBoxResolution->value());
319
320 if (originLat >
321 lastLat) // reverse lines in vertical direction if the original file
322 // has its origin in the northwest corner
323 this->reverseNorthSouth(data_array.data(), sizeLon, sizeLat);
324
325 GeoLib::RasterHeader const header = {sizeLon, sizeLat, 1,
326 origin, resolution, -9999};
327 if (this->radioMesh->isChecked())
328 {
330 MeshLib::UseIntensityAs useIntensity =
332 if (comboBoxMeshElemType->currentIndex() == 1)
333 {
334 meshElemType = MeshLib::MeshElemType::TRIANGLE;
335 }
336 else
337 {
338 meshElemType = MeshLib::MeshElemType::QUAD;
339 }
340 if ((comboBoxUseIntensity->currentIndex()) == 1)
341 {
343 }
344 else
345 {
347 }
349 data_array.data(), header, meshElemType, useIntensity,
350 _currentVar.getName());
351 }
352 else
353 {
354 vtkImageImport* image =
355 VtkRaster::loadImageFromArray(data_array.data(), header);
357 _currentRaster->setImage(image,
358 QString::fromStdString(this->getName()));
359 }
360}
361
363{
364 std::string name;
365 name.append(_currentPath);
366 name.erase(0, name.find_last_of("/") + 1);
367 name.erase(name.find_last_of("."));
368 return QString::fromStdString(name);
369}
370
372{
373 std::string name = (lineEditName->text()).toStdString();
374 QString const date = QString::number(dateTimeEditDim3->value());
375 name.append(" - ").append(date.toStdString());
376 return name;
377}
378
379void NetCdfConfigureDialog::reverseNorthSouth(double* data, std::size_t width,
380 std::size_t height)
381{
382 auto* cp_array = new double[width * height];
383
384 for (std::size_t i = 0; i < height; i++)
385 {
386 for (std::size_t j = 0; j < width; j++)
387 {
388 std::size_t old_index((width * height) - (width * (i + 1)));
389 std::size_t new_index(width * i);
390 cp_array[new_index + j] = data[old_index + j];
391 }
392 }
393
394 std::size_t length(height * width);
395 for (std::size_t i = 0; i < length; i++)
396 data[i] = cp_array[i];
397
398 delete[] cp_array;
399}
400
402{
403 if (isTrue) // output set to "mesh"
404 {
405 this->label_2->setEnabled(true);
406 this->label_3->setEnabled(false);
407 this->comboBoxMeshElemType->setEnabled(true);
408 this->comboBoxUseIntensity->setEnabled(false);
409 }
410 else // output set to "raster"
411 {
412 this->label_2->setEnabled(false);
413 this->label_3->setEnabled(true);
414 this->comboBoxMeshElemType->setEnabled(false);
415 this->comboBoxUseIntensity->setEnabled(true);
416 }
417}
static std::unique_ptr< MeshLib::Mesh > convert(GeoLib::Raster const &raster, MeshLib::MeshElemType elem_type, MeshLib::UseIntensityAs intensity_type, std::string const &array_name="Colour")
VtkGeoImageSource * _currentRaster
void on_comboBoxDim3_currentIndexChanged(int id)
void on_radioMesh_toggled(bool isTrue)
std::unique_ptr< MeshLib::Mesh > _currentMesh
void on_comboBoxVariable_currentIndexChanged(int id)
void reverseNorthSouth(double *data, std::size_t width, std::size_t height)
void on_comboBoxDim1_currentIndexChanged(int id)
NetCdfConfigureDialog(const std::string &fileName, QDialog *parent=nullptr)
void on_comboBoxDim2_currentIndexChanged(int id)
void getDimEdges(std::string const &name, unsigned &size, double &firstValue, double &lastValue)
void on_comboBoxDim4_currentIndexChanged(int id)
static VtkGeoImageSource * New()
Create new objects with New() because of VTKs reference counting.
static vtkImageImport * loadImageFromArray(double const *const data_array, GeoLib::RasterHeader header)
Returns a VtkImageAlgorithm from an array of pixel values and some image meta data.
Definition VtkRaster.cpp:71
UseIntensityAs
Selection of possible interpretations for intensities.
Definition MeshEnums.h:93
MeshElemType
Types of mesh elements supported by OpenGeoSys. Values are from VTKCellType enum.
Definition MeshEnums.h:37
Contains the relevant information when storing a geoscientific raster data.
Definition Raster.h:18