From 26b107b6377c9a54542f47eeb241b4d846ea9cae Mon Sep 17 00:00:00 2001 From: Julian Heinze <julian.heinze@ufz.de> Date: Thu, 11 May 2023 11:56:56 +0200 Subject: [PATCH] New Dialog for the creation of VoxelGrids from a 3D mesh --- .../DataExplorer/DataView/CMakeLists.txt | 2 + .../DataExplorer/DataView/Vtu2Grid.ui | 204 ++++++++++++++++++ .../DataExplorer/DataView/Vtu2GridDialog.cpp | 203 +++++++++++++++++ .../DataExplorer/DataView/Vtu2GridDialog.h | 53 +++++ Applications/DataExplorer/mainwindow.cpp | 11 + Applications/DataExplorer/mainwindow.h | 1 + Applications/DataExplorer/mainwindow.ui | 22 ++ 7 files changed, 496 insertions(+) create mode 100644 Applications/DataExplorer/DataView/Vtu2Grid.ui create mode 100644 Applications/DataExplorer/DataView/Vtu2GridDialog.cpp create mode 100644 Applications/DataExplorer/DataView/Vtu2GridDialog.h diff --git a/Applications/DataExplorer/DataView/CMakeLists.txt b/Applications/DataExplorer/DataView/CMakeLists.txt index 61bec31972b..7fd696947a8 100644 --- a/Applications/DataExplorer/DataView/CMakeLists.txt +++ b/Applications/DataExplorer/DataView/CMakeLists.txt @@ -45,6 +45,7 @@ set(SOURCES StationTreeView.cpp SurfaceExtractionDialog.cpp TranslateDataDialog.cpp + Vtu2GridDialog.cpp ) set(HEADERS @@ -98,6 +99,7 @@ set(HEADERS StationTreeModel.h StationTreeView.h SurfaceExtractionDialog.h + Vtu2GridDialog.h ) # Visual Studio folder diff --git a/Applications/DataExplorer/DataView/Vtu2Grid.ui b/Applications/DataExplorer/DataView/Vtu2Grid.ui new file mode 100644 index 00000000000..0b278ad3143 --- /dev/null +++ b/Applications/DataExplorer/DataView/Vtu2Grid.ui @@ -0,0 +1,204 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Vtu2Grid</class> + <widget class="QDialog" name="Vtu2Grid"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>253</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="geometry"> + <rect> + <x>30</x> + <y>200</y> + <width>341</width> + <height>32</height> + </rect> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + <widget class="QComboBox" name="meshListBox"> + <property name="geometry"> + <rect> + <x>100</x> + <y>30</y> + <width>274</width> + <height>28</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel" name="meshListLabel"> + <property name="geometry"> + <rect> + <x>0</x> + <y>30</y> + <width>110</width> + <height>28</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>110</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>110</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string> Select mesh:</string> + </property> + </widget> + <widget class="QGroupBox" name="VoxelSizeBox"> + <property name="geometry"> + <rect> + <x>70</x> + <y>90</y> + <width>281</width> + <height>69</height> + </rect> + </property> + <property name="title"> + <string>Voxel size</string> + </property> + <widget class="QLabel" name="xLengthLabel"> + <property name="geometry"> + <rect> + <x>12</x> + <y>32</y> + <width>16</width> + <height>17</height> + </rect> + </property> + <property name="text"> + <string>x:</string> + </property> + </widget> + <widget class="QLineEdit" name="xlineEdit"> + <property name="geometry"> + <rect> + <x>31</x> + <y>32</y> + <width>51</width> + <height>25</height> + </rect> + </property> + </widget> + <widget class="QLabel" name="yLengthLabel"> + <property name="geometry"> + <rect> + <x>100</x> + <y>32</y> + <width>16</width> + <height>17</height> + </rect> + </property> + <property name="text"> + <string>y:</string> + </property> + </widget> + <widget class="QLineEdit" name="ylineEdit"> + <property name="geometry"> + <rect> + <x>120</x> + <y>32</y> + <width>51</width> + <height>25</height> + </rect> + </property> + </widget> + <widget class="QLabel" name="zLengthLabel"> + <property name="geometry"> + <rect> + <x>190</x> + <y>32</y> + <width>16</width> + <height>17</height> + </rect> + </property> + <property name="text"> + <string>z:</string> + </property> + </widget> + <widget class="QLineEdit" name="zlineEdit"> + <property name="geometry"> + <rect> + <x>210</x> + <y>32</y> + <width>51</width> + <height>25</height> + </rect> + </property> + </widget> + </widget> + <widget class="QLabel" name="expectedVoxelLabel"> + <property name="geometry"> + <rect> + <x>40</x> + <y>170</y> + <width>291</width> + <height>21</height> + </rect> + </property> + <property name="text"> + <string>Expected Voxel: </string> + </property> + </widget> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>Vtu2Grid</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>Vtu2Grid</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Applications/DataExplorer/DataView/Vtu2GridDialog.cpp b/Applications/DataExplorer/DataView/Vtu2GridDialog.cpp new file mode 100644 index 00000000000..8bafad4d53b --- /dev/null +++ b/Applications/DataExplorer/DataView/Vtu2GridDialog.cpp @@ -0,0 +1,203 @@ +/** + * \file + * \date 2023-05-11 + * \brief Implementation of the Vtu2GridDialog class. + * + * \copyright + * Copyright (c) 2012-2023, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#include "Vtu2GridDialog.h" + +#include <vtkXMLUnstructuredGridWriter.h> + +#include <QStringList> +#include <QStringListModel> +#include <string> + +#include "Base/StrictDoubleValidator.h" +#include "GeoLib/AABB.h" +#include "MeshLib/IO/writeMeshToFile.h" +#include "MeshLib/Mesh.h" +#include "MeshLib/Node.h" +#include "MeshLib/Vtk/VtkMappedMeshSource.h" +#include "MeshModel.h" +#include "MeshToolsLib/MeshGenerators/MeshGenerator.h" +#include "MeshToolsLib/MeshGenerators/VoxelGridFromMesh.h" + +Vtu2GridDialog::Vtu2GridDialog(MeshModel& mesh_model, QDialog* parent) + : QDialog(parent), _mesh_model(mesh_model) +{ + setupUi(this); + QStringList MeshList; + + for (int model_index = 0; model_index < mesh_model.rowCount(); + ++model_index) + { + auto const* mesh = mesh_model.getMesh(mesh_model.index(model_index, 0)); + MeshList.append(QString::fromStdString(mesh->getName())); + } + + if (MeshList.empty()) + { + MeshList.append("[No Mesh available.]"); + this->expectedVoxelLabel->setText("Expected Voxel: undefined"); + } + + _allMeshes.setStringList(MeshList); + this->meshListBox->addItems(_allMeshes.stringList()); + this->xlineEdit->setFocus(); +} + +void Vtu2GridDialog::updateExpectedVoxel() +{ + QString const xin = this->xlineEdit->text(); + QString const yin = this->ylineEdit->text(); + QString const zin = this->zlineEdit->text(); + bool ok; + double const xinput = xin.toDouble(); + double const yinput = (yin.toDouble(&ok)) ? yin.toDouble() : xin.toDouble(); + double const zinput = (zin.toDouble(&ok)) ? zin.toDouble() : xin.toDouble(); + + if (_allMeshes.stringList()[0] == "[No Mesh available.]") + { + this->expectedVoxelLabel->setText("approximated Voxel: undefined"); + return; + } + if (xin.isEmpty() || xinput == 0) + { + this->expectedVoxelLabel->setText("approximated Voxel: undefined"); + return; + } + + auto* const _mesh( + _mesh_model.getMesh(this->meshListBox->currentText().toStdString())); + auto const& nodes = _mesh->getNodes(); + GeoLib::AABB const aabb(nodes.cbegin(), nodes.cend()); + + auto const min = aabb.getMinPoint(); + auto const max = aabb.getMaxPoint(); + + double const expectedVoxel = (max[0] - min[0]) * (max[1] - min[1]) * + (max[2] - min[2]) / xinput / yinput / zinput; + + int const exponent = std::floor(std::log10(abs(expectedVoxel))); + this->expectedVoxelLabel->setText( + "approximated Voxel = " + + QString::number(std::round(expectedVoxel / std::pow(10, exponent))) + + " x 10^" + QString::number(exponent)); +} + +void Vtu2GridDialog::on_xlineEdit_textChanged() +{ + updateExpectedVoxel(); +} + +void Vtu2GridDialog::on_ylineEdit_textChanged() +{ + updateExpectedVoxel(); +} + +void Vtu2GridDialog::on_zlineEdit_textChanged() +{ + updateExpectedVoxel(); +} + +void Vtu2GridDialog::accept() +{ + using namespace MeshToolsLib::MeshGenerator; + if (this->meshListBox->currentText().toStdString() == + "[No Mesh available.]") + { + OGSError::box( + "Please specify the input meshes. It has to be a 3D mesh."); + return; + } + + QString const xin = this->xlineEdit->text(); + QString const yin = this->ylineEdit->text(); + QString const zin = this->zlineEdit->text(); + + bool ok; + if (!xin.toDouble(&ok)) + { + OGSError::box( + "At least the x-length of a voxel must be specified.\n If " + "y-/z-input " + "are not specified, equal to 0, or not a real number, they are " + "treated as " + "the x-input."); + return; + } + double const xinput = xin.toDouble(); + double const yinput = (yin.toDouble(&ok)) ? yin.toDouble() : xin.toDouble(); + double const zinput = (zin.toDouble(&ok)) ? zin.toDouble() : xin.toDouble(); + std::array<double, 3> const cellsize = {xinput, yinput, zinput}; + + auto _mesh( + _mesh_model.getMesh(this->meshListBox->currentText().toStdString())); + + if (_mesh->MeshLib::Mesh::getDimension() < 3) + { + OGSError::box("The dimension of the mesh has to be 3."); + return; + } + + vtkNew<MeshLib::VtkMappedMeshSource> vtkSource; + vtkSource->SetMesh(_mesh); + vtkSource->Update(); + vtkSmartPointer<vtkUnstructuredGrid> mesh = vtkSource->GetOutput(); + + double* const bounds = mesh->GetBounds(); + MathLib::Point3d const min( + std::array<double, 3>{bounds[0], bounds[2], bounds[4]}); + MathLib::Point3d const max( + std::array<double, 3>{bounds[1], bounds[3], bounds[5]}); + std::array<double, 3> ranges = {max[0] - min[0], max[1] - min[1], + max[2] - min[2]}; + if (ranges[0] < 0 || ranges[1] < 0 || ranges[2] < 0) + { + OGSError::box( + "The range (max-min of the bounding box) is not allowed to be < 0"); + } + std::array<std::size_t, 3> const dims = + VoxelGridFromMesh::getNumberOfVoxelPerDimension(ranges, cellsize); + std::unique_ptr<MeshLib::Mesh> grid( + generateRegularHexMesh(dims[0], dims[1], dims[2], cellsize[0], + cellsize[1], cellsize[2], min, "grid")); + + std::vector<int> const tmp_ids = + VoxelGridFromMesh::assignCellIds(mesh, min, dims, cellsize); + std::vector<int>& cell_ids = + *grid->getProperties().createNewPropertyVector<int>( + VoxelGridFromMesh::cell_id_name, MeshLib::MeshItemType::Cell, 1); + std::copy(tmp_ids.cbegin(), tmp_ids.cend(), std::back_inserter(cell_ids)); + + if (!VoxelGridFromMesh::removeUnusedGridCells(mesh, grid)) + { + return; + } + + VoxelGridFromMesh::mapMeshArraysOntoGrid(mesh, grid); + + if (mesh == nullptr) + { + OGSError::box("The VoxelGrid is faulty"); // write name of layer. + return; + } + + _mesh_model.addMesh(grid.release()); + this->done(QDialog::Accepted); +} + +std::vector<std::string> Vtu2GridDialog::getSelectedObjects(QStringList list) +{ + std::vector<std::string> indexList; + std::transform(list.begin(), list.end(), std::back_inserter(indexList), + [](auto const& index) { return index.toStdString(); }); + return indexList; +} \ No newline at end of file diff --git a/Applications/DataExplorer/DataView/Vtu2GridDialog.h b/Applications/DataExplorer/DataView/Vtu2GridDialog.h new file mode 100644 index 00000000000..db326bd8574 --- /dev/null +++ b/Applications/DataExplorer/DataView/Vtu2GridDialog.h @@ -0,0 +1,53 @@ +/** + * \file + * \date 2023-04-26 + * \brief Definition of the Vtu2GridDialog class. + * + * \copyright + * Copyright (c) 2012-2023, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#pragma once + +#include <QDialog> +#include <QStringListModel> +#include <memory> + +#include "MeshLib/Elements/ElementErrorCode.h" +#include "ui_Vtu2Grid.h" + +class MeshModel; + +/* + * \brief A dialog window for calling methods to create a 3D Voxelgrid from + * multiple 2D vtu meshes + */ +class Vtu2GridDialog : public QDialog, private Ui_Vtu2Grid +{ + Q_OBJECT + +public: + explicit Vtu2GridDialog(MeshModel& mesh_model, + QDialog* parent = nullptr); + +private: + std::vector<std::string> getSelectedObjects(QStringList list); + MeshModel& _mesh_model; + QStringListModel _allMeshes; + +private slots: + /// Instructions if the OK-Button has been pressed. + void accept() override; + /// Instructions if the Cancel-Button has been pressed. + void reject() override { this->done(QDialog::Rejected); }; + /// Instructions if the ">>-button" has been pressed. + /// Instructions if the ↑-button" has been pressed. + void updateExpectedVoxel(); + void on_xlineEdit_textChanged(); + void on_ylineEdit_textChanged(); + void on_zlineEdit_textChanged(); +}; diff --git a/Applications/DataExplorer/mainwindow.cpp b/Applications/DataExplorer/mainwindow.cpp index 3acba16408a..91c8c3bb2e2 100644 --- a/Applications/DataExplorer/mainwindow.cpp +++ b/Applications/DataExplorer/mainwindow.cpp @@ -80,6 +80,7 @@ #include "DataView/MeshElementRemovalDialog.h" #include "DataView/MeshQualitySelectionDialog.h" #include "DataView/TranslateDataDialog.h" +#include "DataView/Vtu2GridDialog.h" #ifdef OGS_USE_NETCDF #include "VtkVis/NetCdfConfigureDialog.h" #endif // OGS_USE_NETCDF @@ -1364,6 +1365,16 @@ void MainWindow::showLayers2GridDialog() dlg.exec(); } +void MainWindow::showVtu2GridDialog() +{ + if (_meshModel == nullptr) + { + OGSError::box("The supplied mesh_model is not existing."); + } + auto dlg = Vtu2GridDialog(*_meshModel); + dlg.exec(); +} + void MainWindow::convertPointsToStations(std::string const& geo_name) { std::string stn_name = geo_name + " Stations"; diff --git a/Applications/DataExplorer/mainwindow.h b/Applications/DataExplorer/mainwindow.h index 5dc98f3e78b..7d2ed2a33ed 100644 --- a/Applications/DataExplorer/mainwindow.h +++ b/Applications/DataExplorer/mainwindow.h @@ -107,6 +107,7 @@ protected slots: void showMeshQualitySelectionDialog( MeshLib::VtkMappedMeshSource* mshSource); void showVisalizationPrefsDialog(); + void showVtu2GridDialog(); void updateDataViews(); void writeGeometryToFile(QString gliName, QString fileName); void writeStationListToFile(QString listName, QString fileName); diff --git a/Applications/DataExplorer/mainwindow.ui b/Applications/DataExplorer/mainwindow.ui index 6f783972260..06e2393a585 100644 --- a/Applications/DataExplorer/mainwindow.ui +++ b/Applications/DataExplorer/mainwindow.ui @@ -132,6 +132,7 @@ <addaction name="actionDiagram_Viewer"/> <addaction name="actionFEM_Test"/> <addaction name="actionTranslating_Data"/> + <addaction name="action3D_mesh_to_Voxelgrid"/> <addaction name="actionCreate_a_Voxelgrid"/> </widget> <widget class="QMenu" name="menuHelp"> @@ -476,6 +477,11 @@ <string>Translating Data</string> </property> </action> + <action name="action3D_mesh_to_Voxelgrid"> + <property name="text"> + <string>3D mesh to Voxelgrid</string> + </property> + </action> <action name="actionCreate_a_Voxelgrid"> <property name="text"> <string>Create a Voxelgrid from Layers</string> @@ -779,6 +785,22 @@ </hint> </hints> </connection> + <connection> + <sender>action3D_mesh_to_Voxelgrid</sender> + <signal>triggered()</signal> + <receiver>MainWindowClass</receiver> + <slot>showVtu2GridDialog()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>400</x> + <y>372</y> + </hint> + </hints> + </connection> <connection> <sender>actionCreate_Structured_Mesh</sender> <signal>triggered()</signal> -- GitLab