OGS
MeshView.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
4#include "MeshView.h"
5
6#include <QContextMenuEvent>
7#include <QFileDialog>
8#include <QHeaderView>
9#include <QMenu>
10#include <QObject>
11#include <QSettings>
12#include <memory>
13
19#include "Base/OGSError.h"
21#include "MeshItem.h"
22#include "MeshLayerEditDialog.h"
23#include "MeshLib/Mesh.h"
24#include "MeshLib/Node.h"
25#include "MeshMapping2DDialog.h"
26#include "MeshModel.h"
30#include "MeshValueEditDialog.h"
32#include "SaveMeshDialog.h"
34
35MeshView::MeshView(QWidget* parent /*= 0*/) : QTreeView(parent)
36{
37 setUniformRowHeights(true);
38 // resizeColumnsToContents();
39 // resizeRowsToContents();
40}
41
42MeshView::~MeshView() = default;
43
45{
46 setAlternatingRowColors(true);
47 setColumnWidth(0, 150);
48 std::size_t nColumns =
49 (this->model() != nullptr) ? this->model()->columnCount() : 0;
50 for (std::size_t i = 1; i < nColumns; i++)
51 {
52 resizeColumnToContents(i);
53 }
54}
55
56void MeshView::selectionChanged(const QItemSelection& selected,
57 const QItemSelection& deselected)
58{
59 Q_UNUSED(deselected);
60 if (!selected.isEmpty())
61 {
63 const QModelIndex idx = *(selected.indexes().begin());
64 const TreeItem* tree_item =
65 static_cast<TreeModel*>(this->model())->getItem(idx);
66
67 const auto* list_item = dynamic_cast<const MeshItem*>(tree_item);
68 if (list_item)
69 {
70 emit enableSaveButton(true);
71 emit enableRemoveButton(true);
72 emit meshSelected(*list_item->getMesh());
73 }
74 else
75 {
76 emit enableSaveButton(false);
77 emit enableRemoveButton(false);
78 emit elementSelected(
79 dynamic_cast<const MeshItem*>(tree_item->parentItem())
80 ->vtkSource(),
81 static_cast<unsigned>(tree_item->row()), true);
82 }
83 }
84}
85
90
92{
93 QModelIndex index(this->selectionModel()->currentIndex());
94 if (!index.isValid())
95 {
96 OGSError::box("No mesh selected.");
97 }
98 else
99 {
100 emit requestMeshRemoval(index);
101 emit enableSaveButton(false);
102 emit enableRemoveButton(false);
103 }
104}
105
106void MeshView::contextMenuEvent(QContextMenuEvent* event)
107{
108 QModelIndex const& index = this->selectionModel()->currentIndex();
109 MeshItem const* const item = dynamic_cast<MeshItem*>(
110 static_cast<TreeItem*>(index.internalPointer()));
111
112 if (item == nullptr)
113 {
114 return;
115 }
116
117 unsigned const mesh_dim(item->getMesh()->getDimension());
118
119 std::vector<MeshAction> actions;
120 actions.push_back({new QAction("Map mesh...", this), 1, 2});
121 connect(actions.back().action, SIGNAL(triggered()), this,
122 SLOT(openMap2dMeshDialog()));
123 actions.push_back(
124 {new QAction("Assign raster data to mesh...", this), 1, 2});
125 connect(actions.back().action, SIGNAL(triggered()), this,
127 actions.push_back({new QAction("Extend mesh to 3D...", this), 2, 3});
128 connect(actions.back().action, SIGNAL(triggered()), this,
129 SLOT(openMeshEditDialog()));
130 actions.push_back({new QAction("Add layer...", this), 1, 3});
131 connect(actions.back().action, SIGNAL(triggered()), this,
132 SLOT(openAddLayerDialog()));
133 actions.push_back({new QAction("Edit material groups...", this), 1, 3});
134 connect(actions.back().action, SIGNAL(triggered()), this,
135 SLOT(openValuesEditDialog()));
136 actions.push_back({new QAction("Extract surface...", this), 3, 3});
137 connect(actions.back().action, SIGNAL(triggered()), this,
138 SLOT(extractSurfaceMesh()));
139 actions.push_back(
140 {new QAction("Calculate element quality...", this), 2, 3});
141 connect(actions.back().action, SIGNAL(triggered()), this,
142 SLOT(checkMeshQuality()));
143 actions.push_back({new QAction("Convert to geometry", this), 1, 2});
144 connect(actions.back().action, SIGNAL(triggered()), this,
145 SLOT(convertMeshToGeometry()));
146 actions.push_back({new QAction("Export to Shapefile...", this), 2, 2});
147 connect(actions.back().action, SIGNAL(triggered()), this,
148 SLOT(exportToShapefile()));
149 actions.push_back({new QAction("Export to TetGen...", this), 3, 3});
150 connect(actions.back().action, SIGNAL(triggered()), this,
151 SLOT(exportToTetGen()));
152
153 QMenu menu(this);
154 for (MeshAction a : actions)
155 {
156 if (mesh_dim >= a.min_dim && mesh_dim <= a.max_dim)
157 {
158 menu.addAction(a.action);
159 }
160 }
161 menu.exec(event->globalPos());
162}
163
165{
166 MeshModel const* const model = static_cast<MeshModel*>(this->model());
167 QModelIndex const index = this->selectionModel()->currentIndex();
168 MeshLib::Mesh const* const mesh = model->getMesh(index);
169 if (mesh == nullptr)
170 {
171 return;
172 }
173
175 if (dlg.exec() != QDialog::Accepted)
176 {
177 return;
178 }
179
180 auto result = std::make_unique<MeshLib::Mesh>(*mesh);
181 result->setName(dlg.getNewMeshName());
182 if (dlg.useRasterMapping())
183 {
184 std::unique_ptr<GeoLib::Raster> raster{
186 if (!raster)
187 {
188 OGSError::box(QString::fromStdString(
189 "Error mapping mesh. Could not read raster file " +
190 dlg.getRasterPath()));
191 return;
192 }
194 *result, *raster, dlg.getNoDataReplacement(),
195 dlg.getIgnoreNoData()))
196 {
197 OGSError::box("Error mapping mesh.");
198 return;
199 }
200 }
201 else
202 {
204 dlg.getStaticValue());
205 }
206 static_cast<MeshModel*>(this->model())->addMesh(std::move(result));
207}
208
210{
211 MeshModel const* const model = static_cast<MeshModel*>(this->model());
212 QModelIndex const index = this->selectionModel()->currentIndex();
213 MeshLib::Mesh const* mesh = model->getMesh(index);
214 if (mesh == nullptr)
215 {
216 return;
217 }
218
219 RasterDataToMeshDialog dlg(mesh->getName());
220 if (dlg.exec() != QDialog::Accepted)
221 {
222 return;
223 }
224
225 auto result = std::make_unique<MeshLib::Mesh>(*mesh);
226 result->setName(dlg.getMeshName());
227 std::unique_ptr<GeoLib::Raster> raster{
229 if (!raster)
230 {
231 OGSError::box(QString::fromStdString("Could not read raster file " +
232 dlg.getRasterPath()));
233 return;
234 }
235 if (dlg.createNodeArray())
236 {
238 *result, *raster, dlg.getNoDataReplacement(), dlg.getArrayName());
239 }
240 else
241 {
243 *result, *raster, dlg.getNoDataReplacement(), dlg.getArrayName());
244 }
245 static_cast<MeshModel*>(this->model())->addMesh(std::move(result));
246}
247
249{
250 MeshModel const* const model = static_cast<MeshModel*>(this->model());
251 QModelIndex const index = this->selectionModel()->currentIndex();
252 MeshLib::Mesh const* const mesh = model->getMesh(index);
253
254 MeshLayerEditDialog meshLayerEdit(mesh);
255 connect(&meshLayerEdit, SIGNAL(mshEditFinished(MeshLib::Mesh*)), model,
256 SLOT(addMesh(MeshLib::Mesh*)));
257 meshLayerEdit.exec();
258}
259
261{
262 MeshModel const* const model = static_cast<MeshModel*>(this->model());
263 QModelIndex const index = this->selectionModel()->currentIndex();
264 auto* mesh = const_cast<MeshLib::Mesh*>(model->getMesh(index));
265
266 MeshValueEditDialog valueEdit(mesh);
267 connect(&valueEdit, SIGNAL(valueEditFinished(MeshLib::Mesh*)), model,
268 SLOT(updateMesh(MeshLib::Mesh*)));
269 valueEdit.exec();
270}
271
273{
274 QModelIndex const index = this->selectionModel()->currentIndex();
275 if (!index.isValid())
276 {
277 return;
278 }
279
280 MeshLib::Mesh const* const mesh =
281 static_cast<MeshModel*>(this->model())->getMesh(index);
282 if (mesh == nullptr)
283 {
284 return;
285 }
286
288 if (dlg.exec() != QDialog::Accepted)
289 {
290 return;
291 }
292
293 bool const copy_material_ids = false;
294 double const thickness(dlg.getThickness());
295 std::unique_ptr<MeshLib::Mesh> result(MeshToolsLib::addLayerToMesh(
296 *mesh, thickness, dlg.getName(), dlg.isTopLayer(), copy_material_ids,
297 std::nullopt));
298
299 if (result)
300 {
301 static_cast<MeshModel*>(model())->addMesh(std::move(result));
302 }
303 else
304 {
305 OGSError::box("Error adding layer to mesh.");
306 }
307}
308
310{
311 QModelIndex const index = this->selectionModel()->currentIndex();
312 if (!index.isValid())
313 {
314 return;
315 }
316
317 MeshLib::Mesh const* const mesh =
318 static_cast<MeshModel*>(this->model())->getMesh(index);
320 if (dlg.exec() != QDialog::Accepted)
321 {
322 return;
323 }
324
325 Eigen::Vector3d const& dir(dlg.getNormal());
326 int const tolerance(dlg.getTolerance());
327 std::unique_ptr<MeshLib::Mesh> sfc_mesh(
329 *mesh, dir, tolerance, "Bulk Mesh Node IDs",
330 "Bulk Mesh Element IDs", "Bulk Mesh Face IDs"));
331 if (sfc_mesh)
332 {
333 static_cast<MeshModel*>(model())->addMesh(std::move(sfc_mesh));
334 }
335 else
336 {
338 " No surfaces found to extract\n using the specified parameters.");
339 }
340}
341
343{
344 QModelIndex const index = this->selectionModel()->currentIndex();
345 MeshLib::Mesh const* const mesh =
346 static_cast<MeshModel*>(this->model())->getMesh(index);
348}
349
351{
352 QModelIndex const index = this->selectionModel()->currentIndex();
353 if (!index.isValid())
354 {
355 return;
356 }
357
358 QSettings const settings;
359 QFileInfo const fi(
360 settings.value("lastOpenedMeshFileDirectory").toString());
361 MeshLib::Mesh const* const mesh =
362 static_cast<MeshModel*>(this->model())->getMesh(index);
363 QString const fileName = QFileDialog::getSaveFileName(
364 nullptr, "Convert mesh to shapefile...",
366 QString::fromStdString(mesh->getName()),
367 "ESRI Shapefile (*.shp)");
368 if (!fileName.isEmpty())
369 {
371 if (!FileIO::SHPInterface::write2dMeshToSHP(fileName.toStdString(),
372 *mesh))
373 {
374 OGSError::box("Error exporting mesh\n to shapefile");
375 }
376 }
377}
378
380{
381 QModelIndex const index = this->selectionModel()->currentIndex();
382 if (!index.isValid())
383 {
384 return;
385 }
386
387 MeshLib::Mesh const* const mesh =
388 static_cast<MeshModel*>(this->model())->getMesh(index);
389 QSettings const settings;
390 QFileDialog dialog(
391 this, "Write TetGen input file to",
392 settings.value("lastOpenedTetgenFileDirectory").toString(),
393 "TetGen Geometry (*.smesh)");
394 dialog.setDefaultSuffix("smesh");
395 if (dialog.exec())
396 {
397 QString const filename = dialog.getSaveFileName();
398 if (!filename.isEmpty())
399 {
401 std::vector<MeshLib::Node> attr;
402 tg.writeTetGenSmesh(filename.toStdString(), *mesh, attr);
403 }
404 }
405}
406
408{
409 QModelIndex const index = this->selectionModel()->currentIndex();
410 if (!index.isValid())
411 {
412 OGSError::box("No mesh selected.");
413 return;
414 }
415
416 MeshLib::Mesh const* const mesh =
417 static_cast<MeshModel*>(this->model())->getMesh(index);
418 if (mesh == nullptr)
419 {
420 OGSError::box("No mesh selected.");
421 return;
422 }
423
424 SaveMeshDialog dlg(*mesh);
425 dlg.exec();
426}
427
429{
430 // QModelIndex const index = this->selectionModel()->currentIndex();
431 // MeshLib::Mesh const*const grid =
432 // static_cast<MeshModel*>(this->model())->getMesh(index);
433}
434
436{
437 QModelIndex const index = this->selectionModel()->currentIndex();
438 emit loadFEMCondFileRequested(index.data(0).toString().toStdString());
439}
440
442{
443 QModelIndex const index = this->selectionModel()->currentIndex();
444 MeshItem const* const item = static_cast<MeshItem*>(
445 static_cast<MeshModel*>(this->model())->getItem(index));
446 emit qualityCheckRequested(item->vtkSource());
447}
A dialog window for adding a layer to the top or bottom of a mesh.
std::string getName() const
Returns the name of the new mesh.
bool isTopLayer() const
Returns if the top layer button is selected (if false, bottom is selected).
double getThickness() const
Returns the thickness of the new layer.
static GeoLib::Raster * readRaster(std::string const &fname)
static bool write2dMeshToSHP(const std::string &file_name, const MeshLib::Mesh &mesh)
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)
static void setDir(const QString &path)
Sets the directory last used for saving a file.
static const QString getDir()
Returns the directory last used for saving a file.
A TreeItem containing a mesh and the associated vtk object used in the Mesh Model.
Definition MeshItem.h:19
MeshLib::Mesh const * getMesh() const
Returns the mesh.
Definition MeshItem.h:31
MeshLib::VtkMappedMeshSource * vtkSource() const
Returns the VTK object.
Definition MeshItem.h:33
A dialog window for editing meshes in various ways.
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Definition Mesh.h:79
const std::string getName() const
Get name of the mesh.
Definition Mesh.h:94
A dialog window for mapping a 2d mesh based on a raster file.
std::string getNewMeshName() const
std::string getRasterPath() const
double getNoDataReplacement() const
double getStaticValue() const
const MeshLib::Mesh * getMesh(const QModelIndex &idx) const
Returns the mesh with the given index.
Definition MeshModel.cpp:85
static bool layerMapping(MeshLib::Mesh const &mesh, const GeoLib::Raster &raster, double nodata_replacement=0.0, bool const ignore_nodata=false)
static bool mapToStaticValue(MeshLib::Mesh const &mesh, double value)
Maps the elevation of all mesh nodes to the specified static value.
static MeshLib::Mesh * getMeshSurface(const MeshLib::Mesh &subsfc_mesh, Eigen::Vector3d const &dir, double angle, std::string_view subsfc_node_id_prop_name="", std::string_view subsfc_element_id_prop_name="", std::string_view face_id_prop_name="")
A dialog window for changing the MaterialID for mesh elements.
void enableSaveButton(bool)
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override
Is called when the selection of this view changes.
Definition MeshView.cpp:56
~MeshView() override
void checkMeshQuality()
Calls the dialog for calculating an element quality metric.
Definition MeshView.cpp:441
void extractSurfaceMesh()
Definition MeshView.cpp:309
void meshSelected(MeshLib::Mesh const &)
void qualityCheckRequested(MeshLib::VtkMappedMeshSource *)
void contextMenuEvent(QContextMenuEvent *event) override
Definition MeshView.cpp:106
void openValuesEditDialog()
Opens a dialog for editing material groups.
Definition MeshView.cpp:260
MeshView(QWidget *parent=nullptr)
Definition MeshView.cpp:35
void openMap2dMeshDialog()
Opens a dialog for mapping 2d meshes.
Definition MeshView.cpp:164
void openMeshEditDialog()
Opens a dialog for editing meshes.
Definition MeshView.cpp:248
void writeToFile() const
Calls the FileDialog to save a mesh to a file.
Definition MeshView.cpp:407
void requestMeshToGeometryConversion(const MeshLib::Mesh *)
void addMesh()
Adds a new mesh.
Definition MeshView.cpp:86
void exportToTetGen()
Definition MeshView.cpp:379
void removeSelectedMeshComponent()
void openRasterDataToMeshDialog()
Opens a dialog for assigning raster data to the mesh.
Definition MeshView.cpp:209
void convertMeshToGeometry()
Definition MeshView.cpp:342
void openMeshFile(int)
void loadDIRECTSourceTerms()
Definition MeshView.cpp:435
void openAddLayerDialog()
Opens a dialog for adding a layer to the mesh.
Definition MeshView.cpp:272
void elementSelected(vtkUnstructuredGridAlgorithm const *const, unsigned, bool)
void requestMeshRemoval(const QModelIndex &)
void loadFEMCondFileRequested(const std::string)
void addDIRECTSourceTerms()
Definition MeshView.cpp:428
void removeMesh()
Remove the currently selected mesh.
Definition MeshView.cpp:91
void updateView()
Definition MeshView.cpp:44
void exportToShapefile() const
Definition MeshView.cpp:350
void enableRemoveButton(bool)
static void box(const QString &e)
Definition OGSError.cpp:13
A dialog window for transferring raster data onto a mesh.
std::string getArrayName() const
std::string getMeshName() const
std::string getRasterPath() const
A dialog window for managing properties for writing meshes to files.
A dialog window for managing properties for writing meshes to files.
Eigen::Vector3d const & getNormal() const
Objects nodes for the TreeModel.
Definition TreeItem.h:17
TreeItem * parentItem() const
Definition TreeItem.cpp:104
int row() const
Definition TreeItem.cpp:62
A hierarchical model for a tree implemented as a double-linked list.
Definition TreeModel.h:19
TreeItem * getItem(const QModelIndex &index) const
bool projectToNodes(MeshLib::Mesh &mesh, GeoLib::Raster const &raster, double const default_replacement, std::string const &array_name)
bool projectToElements(MeshLib::Mesh &mesh, GeoLib::Raster const &raster, double const default_replacement, std::string const &array_name)
MeshLib::Mesh * addLayerToMesh(MeshLib::Mesh const &mesh, double const thickness, std::string const &name, bool const on_top, bool const copy_material_ids, std::optional< int > const layer_id)