diff --git a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.cpp b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.cpp index aa43ed2f17..697ddbc62a 100644 --- a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.cpp +++ b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.cpp @@ -1,254 +1,156 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkRemeshingView.h" -// MITK #include #include #include #include #include #include #include -// Qt -#include - -// VTK #include #include -// C++ Standard Library -#include -#include - QmitkRemeshingView::QmitkRemeshingView() { } QmitkRemeshingView::~QmitkRemeshingView() { } void QmitkRemeshingView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.surfaceComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.surfaceComboBox->SetPredicate(mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object")))); - QIntValidator* posIntValidator = new QIntValidator(0, std::numeric_limits::max(), parent); - m_Controls.maxNumVerticesLineEdit->setValidator(posIntValidator); - - this->EnableWidgets(m_Controls.surfaceComboBox->GetSelectedNode().IsNotNull()); - this->OnAdvancedSettingsButtonToggled(false); - connect(m_Controls.surfaceComboBox, SIGNAL(OnSelectionChanged(const mitk::DataNode *)), this, SLOT(OnSelectedSurfaceChanged(const mitk::DataNode *))); - connect(m_Controls.numVerticesSlider, SIGNAL(valueChanged(int)), this, SLOT(OnNumberOfVerticesChanged(int))); - connect(m_Controls.numVerticesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnNumberOfVerticesChanged(int))); - connect(m_Controls.gradationSlider, SIGNAL(valueChanged(double)), this, SLOT(OnGradationChanged(double))); - connect(m_Controls.gradationSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnGradationChanged(double))); - connect(m_Controls.advancedSettingsButton, SIGNAL(toggled(bool)), this, SLOT(OnAdvancedSettingsButtonToggled(bool))); - connect(m_Controls.maxNumVerticesLineEdit, SIGNAL(editingFinished()), this, SLOT(OnMaxNumVerticesLineEditEditingFinished())); - connect(m_Controls.edgeSplittingSlider, SIGNAL(valueChanged(double)), this, SLOT(OnEdgeSplittingChanged(double))); - connect(m_Controls.edgeSplittingSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnEdgeSplittingChanged(double))); - connect(m_Controls.subsamplingSlider, SIGNAL(valueChanged(int)), this, SLOT(OnSubsamplingChanged(int))); - connect(m_Controls.subsamplingSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnSubsamplingChanged(int))); - connect(m_Controls.optimizationLevelSlider, SIGNAL(valueChanged(int)), this, SLOT(OnOptimizationLevelChanged(int))); - connect(m_Controls.optimizationLevelSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnOptimizationLevelChanged(int))); + connect(m_Controls.densitySlider, SIGNAL(valueChanged(int)), this, SLOT(OnDensityChanged(int))); + connect(m_Controls.densitySpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnDensityChanged(int))); connect(m_Controls.remeshPushButton, SIGNAL(clicked()), this, SLOT(OnRemeshButtonClicked())); this->OnSelectedSurfaceChanged(m_Controls.surfaceComboBox->GetSelectedNode()); } -void QmitkRemeshingView::EnableWidgets(bool enable) -{ - m_Controls.surfaceComboBox->setEnabled(enable); - m_Controls.numVerticesSlider->setEnabled(enable); - m_Controls.numVerticesSpinBox->setEnabled(enable); - m_Controls.gradationSlider->setEnabled(enable); - m_Controls.gradationSpinBox->setEnabled(enable); - m_Controls.maxNumVerticesLineEdit->setEnabled(enable); - m_Controls.edgeSplittingSlider->setEnabled(enable); - m_Controls.edgeSplittingSpinBox->setEnabled(enable); - m_Controls.subsamplingSlider->setEnabled(enable); - m_Controls.subsamplingSpinBox->setEnabled(enable); - m_Controls.optimizationLevelSlider->setEnabled(enable); - m_Controls.optimizationLevelSpinBox->setEnabled(enable); - m_Controls.forceManifoldCheckBox->setEnabled(enable); - m_Controls.boundaryFixingCheckBox->setEnabled(enable); - m_Controls.remeshPushButton->setEnabled(enable); -} - -void QmitkRemeshingView::OnAdvancedSettingsButtonToggled(bool toggled) -{ - m_Controls.maxNumVerticesLabel->setVisible(toggled); - m_Controls.maxNumVerticesLineEdit->setVisible(toggled); - m_Controls.edgeSplittingLabel->setVisible(toggled); - m_Controls.edgeSplittingSlider->setVisible(toggled); - m_Controls.edgeSplittingSpinBox->setVisible(toggled); - m_Controls.subsamplingLabel->setVisible(toggled); - m_Controls.subsamplingSlider->setVisible(toggled); - m_Controls.subsamplingSpinBox->setVisible(toggled); - m_Controls.optimizationLevelLabel->setVisible(toggled); - m_Controls.optimizationLevelSlider->setVisible(toggled); - m_Controls.optimizationLevelSpinBox->setVisible(toggled); - m_Controls.forceManifoldCheckBox->setVisible(toggled); - m_Controls.boundaryFixingCheckBox->setVisible(toggled); -} - -void QmitkRemeshingView::OnEdgeSplittingChanged(double edgeSplitting) -{ - if (edgeSplitting != m_Controls.edgeSplittingSlider->value()) - m_Controls.edgeSplittingSlider->setValue(edgeSplitting); - - if (edgeSplitting != m_Controls.edgeSplittingSpinBox->value()) - m_Controls.edgeSplittingSpinBox->setValue(edgeSplitting); -} - -void QmitkRemeshingView::OnGradationChanged(double gradation) -{ - if (gradation != m_Controls.gradationSlider->value()) - m_Controls.gradationSlider->setValue(gradation); - - if (gradation != m_Controls.gradationSpinBox->value()) - m_Controls.gradationSpinBox->setValue(gradation); -} - -void QmitkRemeshingView::OnMaxNumVerticesLineEditEditingFinished() +void QmitkRemeshingView::OnSelectedSurfaceChanged(const mitk::DataNode *node) { - int maximum = m_Controls.maxNumVerticesLineEdit->text().toInt(); - - if (m_Controls.numVerticesSpinBox->maximum() != maximum) + if (node != nullptr) { - m_Controls.numVerticesSlider->setMaximum(maximum); - m_Controls.numVerticesSpinBox->setMaximum(maximum); + m_MaxNumberOfVertices = static_cast(static_cast(node->GetData())->GetVtkPolyData()->GetNumberOfPoints()); + this->EnableWidgets(true); + } + else + { + m_MaxNumberOfVertices = 0; + this->EnableWidgets(false); } } -void QmitkRemeshingView::OnNumberOfVerticesChanged(int numVertices) -{ - if (numVertices != m_Controls.numVerticesSlider->value()) - m_Controls.numVerticesSlider->setValue(numVertices); - - if (numVertices != m_Controls.numVerticesSpinBox->value()) - m_Controls.numVerticesSpinBox->setValue(numVertices); -} - -void QmitkRemeshingView::OnOptimizationLevelChanged(int optimizationLevel) +void QmitkRemeshingView::OnDensityChanged(int density) { - if (optimizationLevel != m_Controls.optimizationLevelSlider->value()) - m_Controls.optimizationLevelSlider->setValue(optimizationLevel); + if (density != m_Controls.densitySlider->value()) + m_Controls.densitySlider->setValue(density); - if (optimizationLevel != m_Controls.optimizationLevelSpinBox->value()) - m_Controls.optimizationLevelSpinBox->setValue(optimizationLevel); + if (density != m_Controls.densitySpinBox->value()) + m_Controls.densitySpinBox->setValue(density); } void QmitkRemeshingView::OnRemeshButtonClicked() { mitk::DataNode::Pointer selectedNode = m_Controls.surfaceComboBox->GetSelectedNode(); mitk::Surface::ConstPointer surface = static_cast(selectedNode->GetData()); - int numVertices = m_Controls.numVerticesSpinBox->value(); - double gradation = m_Controls.gradationSpinBox->value(); - int subsampling = m_Controls.subsamplingSpinBox->value(); - double edgeSplitting = m_Controls.edgeSplittingSpinBox->value(); - int optimizationLevel = m_Controls.optimizationLevelSpinBox->value(); - bool forceManifold = m_Controls.forceManifoldCheckBox->isChecked(); - bool boundaryFixing = m_Controls.boundaryFixingCheckBox->isChecked(); - // mitk::Surface::Pointer remeshedSurface = mitk::ACVD::Remesh(surface, 0, numVertices, gradation, subsampling, edgeSplitting, optimizationLevel, forceManifold, boundaryFixing); + int density = m_Controls.densitySpinBox->value(); + int numVertices = std::max(100, static_cast(m_MaxNumberOfVertices * (density * 0.01))); + + double gradation = m_Controls.remeshingComboBox->currentText() == QStringLiteral("Adaptive") + ? 1.0 + : 0.0; + + const QString quality = m_Controls.qualityComboBox->currentText(); + int subsampling; + + if (QStringLiteral("High (slow)") == quality) + { + subsampling = 50; + } + else if (QStringLiteral("Maximum (very slow)") == quality) + { + subsampling = 500; + } + else // The default is "Medium (fast)". + { + subsampling = 10; + } + + bool boundaryFixing = m_Controls.preserveEdgesCheckBox->isChecked(); mitk::ACVD::RemeshFilter::Pointer remesher = mitk::ACVD::RemeshFilter::New(); remesher->SetInput(surface); remesher->SetTimeStep(0); remesher->SetNumVertices(numVertices); remesher->SetGradation(gradation); remesher->SetSubsampling(subsampling); - remesher->SetEdgeSplitting(edgeSplitting); - remesher->SetOptimizationLevel(optimizationLevel); - remesher->SetForceManifold(forceManifold); + remesher->SetEdgeSplitting(0.0); + remesher->SetOptimizationLevel(1.0); + remesher->SetForceManifold(false); remesher->SetBoundaryFixing(boundaryFixing); try { remesher->Update(); } catch(const mitk::Exception& exception) { MITK_ERROR << exception.GetDescription(); return; } mitk::Surface::Pointer remeshedSurface = remesher->GetOutput(); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); - newNode->SetName(QString("%1 (%2, %3)").arg(selectedNode->GetName().c_str()).arg(remeshedSurface->GetVtkPolyData()->GetNumberOfPoints()).arg(gradation).toStdString()); + newNode->SetName(QString("%1 (%2%)").arg(selectedNode->GetName().c_str()).arg(density).toStdString()); newNode->SetProperty("material.representation", mitk::VtkRepresentationProperty::New(VTK_WIREFRAME)); newNode->SetData(remeshedSurface); this->GetDataStorage()->Add(newNode, selectedNode); } -void QmitkRemeshingView::OnSelectedSurfaceChanged(const mitk::DataNode *node) -{ - if (node != nullptr) - { - int numVertices = static_cast(static_cast(node->GetData())->GetVtkPolyData()->GetNumberOfPoints()); - int minimum = numVertices < 100 ? numVertices : 100; - int maximum = numVertices == minimum ? numVertices * 10 : numVertices; - int step = std::max(1, maximum / 10); - - this->SetNumberOfVertices(minimum, maximum, step, numVertices); - this->EnableWidgets(true); - } - else - { - this->EnableWidgets(false); - this->SetNumberOfVertices(0, 0, 0, 0); - } -} - -void QmitkRemeshingView::OnSubsamplingChanged(int subsampling) +void QmitkRemeshingView::EnableWidgets(bool enable) { - if (subsampling != m_Controls.subsamplingSlider->value()) - m_Controls.subsamplingSlider->setValue(subsampling); + m_Controls.surfaceComboBox->setEnabled(enable); + m_Controls.densitySlider->setEnabled(enable); + m_Controls.densitySpinBox->setEnabled(enable); + m_Controls.remeshingComboBox->setEnabled(enable); + m_Controls.qualityComboBox->setEnabled(enable); + m_Controls.preserveEdgesCheckBox->setEnabled(enable); + m_Controls.remeshPushButton->setEnabled(enable); - if (subsampling != m_Controls.subsamplingSpinBox->value()) - m_Controls.subsamplingSpinBox->setValue(subsampling); + m_Controls.explanationLabel->setVisible(enable); } void QmitkRemeshingView::SetFocus() { m_Controls.surfaceComboBox->setFocus(); } -void QmitkRemeshingView::SetNumberOfVertices(int minimum, int maximum, int step, int value) -{ - m_Controls.numVerticesSlider->setMinimum(minimum); - m_Controls.numVerticesSlider->setMaximum(maximum); - m_Controls.numVerticesSlider->setSingleStep(1); - m_Controls.numVerticesSlider->setPageStep(step); - - m_Controls.numVerticesSpinBox->setMinimum(minimum); - m_Controls.numVerticesSpinBox->setMaximum(maximum); - m_Controls.numVerticesSpinBox->setSingleStep(step); - m_Controls.numVerticesSpinBox->setValue(value); - - m_Controls.maxNumVerticesLineEdit->setText(QString("%1").arg(maximum)); -} diff --git a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.h b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.h index ab5fc54a47..59979f8458 100644 --- a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.h +++ b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingView.h @@ -1,54 +1,46 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkRemeshingView_h #define QmitkRemeshingView_h #include -#include #include class QmitkRemeshingView : public QmitkAbstractView { Q_OBJECT public: QmitkRemeshingView(); ~QmitkRemeshingView(); void CreateQtPartControl(QWidget* parent) override; void SetFocus() override; private slots: - void OnAdvancedSettingsButtonToggled(bool toggled); - void OnEdgeSplittingChanged(double edgeSplitting); - void OnGradationChanged(double gradation); - void OnMaxNumVerticesLineEditEditingFinished(); - void OnNumberOfVerticesChanged(int numVertices); - void OnOptimizationLevelChanged(int optimizationLevel); - void OnRemeshButtonClicked(); void OnSelectedSurfaceChanged(const mitk::DataNode *node); - void OnSubsamplingChanged(int subsampling); + void OnDensityChanged(int numVertices); + void OnRemeshButtonClicked(); private: void EnableWidgets(bool enable); - void SetNumberOfVertices(int minimum, int maximum, int step, int value); Ui::QmitkRemeshingViewControls m_Controls; - QThread m_Thread; + int m_MaxNumberOfVertices; }; #endif diff --git a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingViewControls.ui b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingViewControls.ui index ce63997fb1..0fbd4a62dc 100644 --- a/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.remeshing/src/internal/QmitkRemeshingViewControls.ui @@ -1,440 +1,247 @@ QmitkRemeshingViewControls true 0 0 - 260 - 423 + 253 + 573 Remeshing - - - - - - 0 - 0 - - - - Surface - - - - - - - true - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Vertices - - - - - - - - 0 - 0 - - - - 10000 - - - 100 - - + + + + 0 - - Qt::Horizontal - + + + Medium (fast) + + + + + High (slow) + + + + + Maximum (very slow) + + - + + + % + - 0 + 1 - 10000 + 100 - 100 + 1 - 0 + 100 - - + + - + 0 0 - Gradation - - - - - - - 1.000000000000000 - - - 0.100000000000000 - - - 1.000000000000000 - - - 10.000000000000000 - - - Qt::Horizontal - - - - - - - 1 - - - 10.000000000000000 + Preserve Edges - - 0.100000000000000 - - - 1.000000000000000 + + true - - - - - - - 0 - 0 - - - - - 0 - 32 - - - - Advanced settings - - - Qt::ToolButtonTextBesideIcon - - - Qt::Vertical - - - true - - - - - - + 0 0 - Max. # of vertices + Surface - - - 0 - - - 10 - - - - - - - - 0 - 0 - - - - Subsampling + + + true - - - - 0 0 - - 500 - - - 10 - - - 50 - - - 50 - - - Qt::Horizontal - - - - - - - 0 - - - 500 - - - 10 - - - 50 - - - + + - + 0 0 - Force manifold - - - false + Density - - + + 0 0 - - Boundary fixing - - - false - - - - - - - 10 - - + 1 - - - - - - Optimization Level - - - - - - 10 + 100 - 1 + 10 - 1 + 100 Qt::Horizontal - - + + 0 0 - Edge splitting + Remeshing - - - - 0.000000000000000 - - - 0.010000000000000 - - - 1.000000000000000 - - - 10.000000000000000 - - - Qt::Horizontal - + + + + + Adaptive + + + + + Regular + + - - - - 2 - - - 10.000000000000000 - - - 0.100000000000000 + + + + + 0 + 0 + - - 0.000000000000000 + + Quality true Remesh :/Remeshing/RemeshingIcon.png:/Remeshing/RemeshingIcon.png 24 24 + + + + <html><head/><body><p><span style=" font-weight:600;">Density:</span> The density of the resulting surface compared to the input surface. For example, a density of 50% will effectively halve the number of vertices. It's not uncommen to choose values as low as 10% for overly dense input surfaces. The minimum number of output vertices is at least 100, though.</p><p><span style=" font-weight:600;">Remeshing:</span> Adaptive remeshing results in higher density in curvy areas and less density in flat areas. This remeshing strategy can preserve fine shape details even when the overall density is heavily reduced. Regular remeshing evenly distributes the density regardless of the local shape of the surface.</p><p><span style=" font-weight:600;">Quality</span>: While medium quality is sufficient for the vast majority of use cases, you can increase this setting to further optimize the mesh quality in terms of uniformly shaped triangles. However, computation time and memory consumption increase dramatically compared to very small improvements.</p><p><span style=" font-weight:600;">Preserve Edges:</span> If the input surface contains holes or edges, they will be preserved very accurately by default at the cost of less uniform triangles at their direct neighborhood.</p></body></html> + + + true + + + Qt::Vertical 20 40 - - ctkDoubleSlider - QWidget -
ctkDoubleSlider.h
-
- - ctkExpandButton - QToolButton -
ctkExpandButton.h
-
QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
surfaceComboBox - numVerticesSpinBox - gradationSpinBox - advancedSettingsButton - maxNumVerticesLineEdit - edgeSplittingSpinBox - subsamplingSpinBox - optimizationLevelSpinBox - forceManifoldCheckBox - boundaryFixingCheckBox + densitySpinBox + preserveEdgesCheckBox remeshPushButton