OGS
MeshLayerEditDialog.cpp
Go to the documentation of this file.
1
15#include "MeshLayerEditDialog.h"
16
17#include <QCheckBox>
18#include <QDoubleValidator>
19#include <QElapsedTimer>
20#include <QFileDialog>
21#include <QFileInfo>
22#include <QGridLayout>
23#include <QGroupBox>
24#include <QIntValidator>
25#include <QLineEdit>
26#include <QPushButton>
27#include <QRadioButton>
28#include <QSettings>
29#include <QVBoxLayout>
30
32#include "Base/OGSError.h"
33#include "BaseLib/Logging.h"
34#include "BaseLib/StringTools.h"
36#include "MeshLib/Mesh.h"
38
40 QDialog* parent)
41 : QDialog(parent),
42 _msh(mesh),
43 _n_layers(0),
44 _layerEdit(new QLineEdit("1", this)),
45 _noDataReplacementEdit(nullptr),
46 _minThicknessEdit(nullptr),
47 _nextButton(new QPushButton("Next", this)),
48 _layerBox(nullptr),
49 _radioButtonBox(nullptr),
50 _ogsMeshButton(nullptr),
51 _layerSelectionLayout(new QGridLayout(_layerBox)),
52 _use_rasters(true)
53{
54 setupUi(this);
55
56 this->gridLayoutLayerMapping->addWidget(
57 new QLabel("Please specify the number of layers to add:", this), 0, 0);
58 this->gridLayoutLayerMapping->addWidget(_layerEdit, 0, 1);
59 this->gridLayoutLayerMapping->addWidget(_nextButton, 0, 2);
60 _layerEdit->setValidator(new QIntValidator(1, 999, _layerEdit));
61 connect(_nextButton, SIGNAL(pressed()), this, SLOT(nextButtonPressed()));
62
63 // configure group box + layout
64 this->_layerSelectionLayout->setMargin(10);
65 this->_layerSelectionLayout->setColumnMinimumWidth(2, 10);
66 this->_layerSelectionLayout->setColumnStretch(0, 80);
67 this->_layerSelectionLayout->setColumnStretch(1, 200);
68 this->_layerSelectionLayout->setColumnStretch(2, 10);
69}
70
72
74{
75 _n_layers = static_cast<unsigned>(_layerEdit->text().toInt());
76
77 if (_n_layers < 1)
78 {
79 OGSError::box("Add the number of layers to add (at least 1)");
80 return;
81 }
82
83 _layerEdit->setEnabled(false);
84 _nextButton->setEnabled(false);
85
86 auto* _radiobuttonLayout(new QVBoxLayout(_radioButtonBox));
87 QRadioButton* selectButton1(
88 new QRadioButton("Add layers based on raster files", _radioButtonBox));
89 QRadioButton* selectButton2(
90 new QRadioButton("Add layers with static thickness", _radioButtonBox));
91 _radioButtonBox = new QGroupBox(this);
92 _radiobuttonLayout->addWidget(selectButton1);
93 _radiobuttonLayout->addWidget(selectButton2);
94 _radioButtonBox->setLayout(_radiobuttonLayout);
95 gridLayoutLayerMapping->addWidget(_radioButtonBox, 2, 0, 1, 3);
96 connect(selectButton1, SIGNAL(pressed()), this, SLOT(createWithRasters()));
97 connect(selectButton2, SIGNAL(pressed()), this, SLOT(createStatic()));
98}
99
101{
102 this->_use_rasters = true;
103 this->_radioButtonBox->setEnabled(false);
104 const QString selectText =
105 (_n_layers > 0) ? "Please specify a raster file for mapping each layer:"
106 : "Please specify raster file for surface mapping:";
107 this->_layerBox = new QGroupBox(this);
108 this->_layerBox->setTitle(selectText);
109
110 for (unsigned i = 0; i <= _n_layers; ++i)
111 {
112 QString text("");
113 if (i == 0)
114 {
115 text = "Surface";
116 }
117 else if (i == _n_layers)
118 {
119 text = "Layer" + QString::number(_n_layers) + "-Bottom";
120 }
121 else
122 {
123 text = "Layer" + QString::number(i + 1) + "-Top";
124 }
125 auto* edit(new QLineEdit(this));
126 QPushButton* button(new QPushButton("...", _layerBox));
127
128 this->_edits.push_back(edit);
129 this->_fileButtonMap.insert(button, edit);
130 connect(button, SIGNAL(clicked()), this, SLOT(getFileName()));
131
132 this->_layerSelectionLayout->addWidget(new QLabel(text, _layerBox), i,
133 0);
134 this->_layerSelectionLayout->addWidget(_edits[i], i, 1);
135 this->_layerSelectionLayout->addWidget(button, i, 2);
136 }
137 this->_layerBox->setLayout(this->_layerSelectionLayout);
138 this->gridLayoutLayerMapping->addWidget(_layerBox, 4, 0, 1, 3);
139 if (this->_n_layers > 0)
140 {
142 }
143}
144
146{
147 this->_use_rasters = false;
148 this->_radioButtonBox->setEnabled(false);
149 this->_layerBox = new QGroupBox(this);
150 this->_layerBox->setTitle("Please specify a thickness or each layer");
151
152 for (unsigned i = 0; i < this->_n_layers; ++i)
153 {
154 QString text("Layer" + QString::number(i) + "-Thickness");
155 QLineEdit* staticLayerEdit = new QLineEdit("10", this);
156 staticLayerEdit->setValidator(new QDoubleValidator(staticLayerEdit));
157 _edits.push_back(staticLayerEdit);
158 this->_layerSelectionLayout->addWidget(new QLabel(text, _layerBox), i,
159 0);
160 this->_layerSelectionLayout->addWidget(_edits[i], i, 1);
161 }
162 this->_layerBox->setLayout(this->_layerSelectionLayout);
163 this->gridLayoutLayerMapping->addWidget(_layerBox, 4, 0, 1, 3);
165}
166
168{
169 auto* meshToolSelectionBox(new QGroupBox(this));
170 meshToolSelectionBox->setTitle("Output element type");
171 auto* meshToolSelectionLayout(new QGridLayout(meshToolSelectionBox));
172 _ogsMeshButton = new QRadioButton("Prisms", meshToolSelectionBox);
173 QRadioButton* tetgenMeshButton =
174 new QRadioButton("Tetrahedra", meshToolSelectionBox);
175 tetgenMeshButton->setFixedWidth(150);
176 auto* minThicknessLabel = new QLabel(meshToolSelectionBox);
177 minThicknessLabel->setText("Minimum thickness of layers:");
178 _minThicknessEdit = new QLineEdit(meshToolSelectionBox);
179 _minThicknessEdit->setText("1.0");
180 auto* min_thickness_validator =
181 new QDoubleValidator(0, 1000000, 15, _minThicknessEdit);
182 _minThicknessEdit->setValidator(min_thickness_validator);
183 _minThicknessEdit->setMaximumWidth(100);
184 _minThicknessEdit->setFixedWidth(100);
185 meshToolSelectionLayout->addWidget(_ogsMeshButton, 0, 0);
186 meshToolSelectionLayout->addWidget(tetgenMeshButton, 0, 1);
187 meshToolSelectionLayout->addWidget(minThicknessLabel, 1, 0);
188 meshToolSelectionLayout->addWidget(_minThicknessEdit, 1, 1);
189 meshToolSelectionBox->setLayout(meshToolSelectionLayout);
190 _ogsMeshButton->setChecked(true);
191
192 gridLayoutLayerMapping->addWidget(meshToolSelectionBox, 5, 0, 1, 3);
193}
194
196{
197 const unsigned nLayers = _layerEdit->text().toInt();
198
200
201 QElapsedTimer myTimer0;
202 myTimer0.start();
203 if (_use_rasters)
204 {
205 float minimum_thickness(_minThicknessEdit->text().toFloat());
206 if (minimum_thickness <= 0)
207 {
208 minimum_thickness = std::numeric_limits<float>::epsilon();
209 }
210 std::vector<std::string> raster_paths;
211 for (int i = nLayers; i >= 0; --i)
212 {
213 raster_paths.push_back(this->_edits[i]->text().toStdString());
214 }
215
216 auto const rasters = FileIO::readRasters(raster_paths);
217 if (rasters && mapper.createLayers(*_msh, *rasters, minimum_thickness))
218 {
219 INFO("Mesh construction time: {:d} ms.", myTimer0.elapsed());
220 return mapper.getMesh("SubsurfaceMesh").release();
221 }
222 return nullptr;
223 }
224
225 std::vector<float> layer_thickness;
226 for (unsigned i = 0; i < nLayers; ++i)
227 {
228 layer_thickness.push_back(this->_edits[i]->text().toFloat());
229 }
230 INFO("Mesh construction time: {:d} ms.", myTimer0.elapsed());
232 layer_thickness);
233}
234
236{
237 QSettings settings;
238 QString filename = QFileDialog::getSaveFileName(
239 this, "Write TetGen input file to",
240 settings.value("lastOpenedTetgenFileDirectory").toString(),
241 "TetGen Geometry (*.smesh)");
242 if (filename.isEmpty())
243 {
244 return nullptr;
245 }
246
247 const unsigned nLayers = _layerEdit->text().toInt();
248 MeshLib::Mesh* tg_mesh(nullptr);
249 QElapsedTimer myTimer0;
250 myTimer0.start();
251
252 if (_use_rasters)
253 {
254 float minimum_thickness(_minThicknessEdit->text().toFloat());
255 if (minimum_thickness <= 0)
256 {
257 minimum_thickness = std::numeric_limits<float>::epsilon();
258 }
259 std::vector<std::string> raster_paths;
260 for (int i = nLayers; i >= 0; --i)
261 {
262 raster_paths.push_back(this->_edits[i]->text().toStdString());
263 }
264 LayeredVolume lv;
265
266 auto const rasters = FileIO::readRasters(raster_paths);
267 if (rasters && lv.createLayers(*_msh, *rasters, minimum_thickness))
268 {
269 tg_mesh = lv.getMesh("SubsurfaceMesh").release();
270 }
271
272 if (tg_mesh)
273 {
274 std::vector<MeshLib::Node> tg_attr(lv.getAttributePoints());
275 FileIO::TetGenInterface tetgen_interface;
276 tetgen_interface.writeTetGenSmesh(filename.toStdString(), *tg_mesh,
277 tg_attr);
278 }
279 }
280 else
281 {
282 std::vector<float> layer_thickness;
283 for (unsigned i = 0; i < nLayers; ++i)
284 {
285 layer_thickness.push_back(this->_edits[i]->text().toFloat());
286 }
288 *_msh, layer_thickness);
289 std::vector<MeshLib::Node> tg_attr;
290 FileIO::TetGenInterface tetgen_interface;
291 tetgen_interface.writeTetGenSmesh(filename.toStdString(), *tg_mesh,
292 tg_attr);
293 }
294 INFO("Mesh construction time: {:d} ms.", myTimer0.elapsed());
295
296 return tg_mesh;
297}
298
300{
301 if (this->_edits.isEmpty())
302 {
304 "Please specify the number and\n type of layers and press 'Next'");
305 return;
306 }
307
308 bool all_paths_set(true);
309 if (_n_layers == 0)
310 {
311 if (_edits[0]->text().isEmpty())
312 {
313 all_paths_set = false;
314 }
315 }
316 else
317 {
318 int start_idx = (_use_rasters) ? 1 : 0;
319 for (int i = start_idx; i < _edits.size(); ++i)
320 {
321 if (_edits[i]->text().isEmpty())
322 {
323 all_paths_set = false;
324 }
325 }
326 }
327
328 if (!all_paths_set)
329 {
330 OGSError::box("Please specify raster files for all layers.");
331 return;
332 }
333
334 MeshLib::Mesh* new_mesh(nullptr);
335 if (_ogsMeshButton->isChecked())
336 {
337 new_mesh = createPrismMesh();
338 }
339 else
340 {
341 new_mesh = createTetMesh();
342 }
343
344 if (new_mesh)
345 {
346 emit mshEditFinished(new_mesh);
347 }
348 else
349 {
350 OGSError::box("Error creating mesh");
351 }
352
353 this->done(QDialog::Accepted);
354}
355
357{
358 this->done(QDialog::Rejected);
359}
360
362{
363 auto* button = dynamic_cast<QPushButton*>(this->sender());
364 QSettings settings;
365 QString filename = QFileDialog::getOpenFileName(
366 this, "Select raster file to open",
367 settings.value("lastOpenedRasterFileDirectory").toString(),
368 "ASCII raster files (*.asc *.grd *.xyz);;All files (* *.*)");
369 _fileButtonMap[button]->setText(filename);
370 QFileInfo fi(filename);
371 settings.setValue("lastOpenedRasterFileDirectory", fi.absolutePath());
372}
Definition of the AsciiRasterInterface class.
Definition of the LayeredVolume class.
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:35
Definition of the MeshLayerEditDialog class.
Definition of the Mesh class.
Definition of the OGSError class.
Definition of string helper functions.
Definition of the TetGenInterface class.
static bool writeTetGenSmesh(const std::string &file_name, const GeoLib::GEOObjects &geo_objects, const std::string &geo_name, const std::vector< GeoLib::Point > &attribute_points)
virtual bool createLayers(MeshLib::Mesh const &mesh, std::vector< GeoLib::Raster const * > const &rasters, double minimum_thickness, double noDataReplacementValue=0.0) final
std::unique_ptr< MeshLib::Mesh > getMesh(std::string const &mesh_name) const
Returns a mesh of the subsurface representation.
Creates a volume geometry from 2D mesh layers based on raster data.
std::vector< MeshLib::Node > getAttributePoints() const
MeshLayerEditDialog(const MeshLib::Mesh *mesh, QDialog *parent=nullptr)
~MeshLayerEditDialog() override
void mshEditFinished(MeshLib::Mesh *)
QRadioButton * _ogsMeshButton
MeshLib::Mesh * createPrismMesh()
QMap< QPushButton *, QLineEdit * > _fileButtonMap
void reject() override
Instructions if the Cancel-Button has been pressed.
MeshLib::Mesh * createTetMesh()
QGridLayout * _layerSelectionLayout
QVector< QLineEdit * > _edits
void accept() override
Instructions if the OK-Button has been pressed.
const MeshLib::Mesh * _msh
Manipulating and adding prism element layers to an existing 2D mesh.
static MeshLib::Mesh * createStaticLayers(MeshLib::Mesh const &mesh, std::vector< float > const &layer_thickness_vector, std::string const &mesh_name="SubsurfaceMesh")
static void box(const QString &e)
Definition OGSError.cpp:23
std::optional< std::vector< GeoLib::Raster const * > > readRasters(std::vector< std::string > const &raster_paths)