From 1d0664d93d7e0166eddb37a857015806b193759d Mon Sep 17 00:00:00 2001 From: wmayer Date: Sun, 3 May 2020 15:06:03 +0200 Subject: [PATCH] Mesh: add GUI to perform mesh decimation --- src/Mod/Mesh/Gui/CMakeLists.txt | 5 + src/Mod/Mesh/Gui/Command.cpp | 32 ++++++ src/Mod/Mesh/Gui/DlgDecimating.cpp | 169 +++++++++++++++++++++++++++++ src/Mod/Mesh/Gui/DlgDecimating.h | 80 ++++++++++++++ src/Mod/Mesh/Gui/DlgDecimating.ui | 139 ++++++++++++++++++++++++ src/Mod/Mesh/Gui/Workbench.cpp | 1 + 6 files changed, 426 insertions(+) create mode 100644 src/Mod/Mesh/Gui/DlgDecimating.cpp create mode 100644 src/Mod/Mesh/Gui/DlgDecimating.h create mode 100644 src/Mod/Mesh/Gui/DlgDecimating.ui diff --git a/src/Mod/Mesh/Gui/CMakeLists.txt b/src/Mod/Mesh/Gui/CMakeLists.txt index 92b93206874e..45dfd95be052 100644 --- a/src/Mod/Mesh/Gui/CMakeLists.txt +++ b/src/Mod/Mesh/Gui/CMakeLists.txt @@ -34,6 +34,7 @@ set(Mesh_MOC_HDRS DlgRegularSolidImp.h DlgSettingsMeshView.h DlgSettingsImportExportImp.h + DlgDecimating.h DlgSmoothing.h MeshEditor.h PropertyEditorMesh.h @@ -51,6 +52,7 @@ set(Dialogs_UIC_SRCS DlgRegularSolid.ui DlgSettingsMeshView.ui DlgSettingsImportExport.ui + DlgDecimating.ui DlgSmoothing.ui RemoveComponents.ui RemeshGmsh.ui @@ -76,6 +78,9 @@ SET(Dialogs_SRCS DlgSettingsImportExport.ui DlgSettingsImportExportImp.cpp DlgSettingsImportExportImp.h + DlgDecimating.ui + DlgDecimating.cpp + DlgDecimating.h DlgSmoothing.ui DlgSmoothing.cpp DlgSmoothing.h diff --git a/src/Mod/Mesh/Gui/Command.cpp b/src/Mod/Mesh/Gui/Command.cpp index 671deb537674..ca2c317d1e85 100644 --- a/src/Mod/Mesh/Gui/Command.cpp +++ b/src/Mod/Mesh/Gui/Command.cpp @@ -74,6 +74,7 @@ #include "RemoveComponents.h" #include "RemeshGmsh.h" #include "DlgSmoothing.h" +#include "DlgDecimating.h" #include "ViewProviderMeshFaceSet.h" #include "ViewProviderCurvature.h" #include "MeshEditor.h" @@ -1437,6 +1438,36 @@ bool CmdMeshSmoothing::isActive(void) //-------------------------------------------------------------------------------------- +DEF_STD_CMD_A(CmdMeshDecimating) + +CmdMeshDecimating::CmdMeshDecimating() + :Command("Mesh_Decimating") +{ + sAppModule = "Mesh"; + sGroup = QT_TR_NOOP("Mesh"); + sMenuText = QT_TR_NOOP("Decimation..."); + sToolTipText = QT_TR_NOOP("Decimates a mesh"); + sWhatsThis = QT_TR_NOOP("Decimates a mesh"); + sStatusTip = QT_TR_NOOP("Decimates a mesh"); +} + +void CmdMeshDecimating::activated(int) +{ + Gui::Control().showDialog(new MeshGui::TaskDecimating()); +} + +bool CmdMeshDecimating::isActive(void) +{ +#if 1 + if (Gui::Control().activeDialog()) + return false; +#endif + // Check for the selected mesh feature (all Mesh types) + return getSelection().countObjectsOfType(Mesh::Feature::getClassTypeId()) > 0; +} + +//-------------------------------------------------------------------------------------- + DEF_STD_CMD_A(CmdMeshHarmonizeNormals) CmdMeshHarmonizeNormals::CmdMeshHarmonizeNormals() @@ -1842,6 +1873,7 @@ void CreateMeshCommands(void) rcCmdMgr.addCommand(new CmdMeshHarmonizeNormals()); rcCmdMgr.addCommand(new CmdMeshFlipNormals()); rcCmdMgr.addCommand(new CmdMeshSmoothing()); + rcCmdMgr.addCommand(new CmdMeshDecimating()); rcCmdMgr.addCommand(new CmdMeshBoundingBox()); rcCmdMgr.addCommand(new CmdMeshBuildRegularSolid()); rcCmdMgr.addCommand(new CmdMeshFillupHoles()); diff --git a/src/Mod/Mesh/Gui/DlgDecimating.cpp b/src/Mod/Mesh/Gui/DlgDecimating.cpp new file mode 100644 index 000000000000..2d1a81e47daf --- /dev/null +++ b/src/Mod/Mesh/Gui/DlgDecimating.cpp @@ -0,0 +1,169 @@ +/*************************************************************************** + * Copyright (c) 2020 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#include "PreCompiled.h" +#include "DlgDecimating.h" +#include "ui_DlgDecimating.h" + +#include +#include +#include +#include + +using namespace MeshGui; + +/* TRANSLATOR MeshGui::DlgDecimating */ + +DlgDecimating::DlgDecimating(QWidget* parent, Qt::WindowFlags fl) + : QWidget(parent, fl) + , numberOfTriangles(0) + , ui(new Ui_DlgDecimating) +{ + ui->setupUi(this); + ui->spinBoxReduction->setMinimumWidth(60); + ui->checkAbsolueNumber->setEnabled(false); + on_checkAbsolueNumber_toggled(false); +} + +DlgDecimating::~DlgDecimating() +{ +} + +bool DlgDecimating::isAbsoluteNumber() const +{ + return ui->checkAbsolueNumber->isChecked(); +} + +int DlgDecimating::targetNumberOfTriangles() const +{ + if (ui->checkAbsolueNumber->isChecked()) { + return ui->spinBoxReduction->value(); + } + else { + return numberOfTriangles * (1.0 - reduction()); + } +} + +void DlgDecimating::setNumberOfTriangles(int num) +{ + numberOfTriangles = num; + ui->checkAbsolueNumber->setEnabled(num > 0); + if (num <= 0) + ui->checkAbsolueNumber->setChecked(false); +} + +void DlgDecimating::on_checkAbsolueNumber_toggled(bool on) +{ + ui->sliderReduction->setDisabled(on); + ui->groupBoxTolerance->setDisabled(on); + + if (on) { + disconnect(ui->sliderReduction, SIGNAL(valueChanged(int)), ui->spinBoxReduction, SLOT(setValue(int))); + disconnect(ui->spinBoxReduction, SIGNAL(valueChanged(int)), ui->sliderReduction, SLOT(setValue(int))); + ui->spinBoxReduction->setRange(1, numberOfTriangles); + ui->spinBoxReduction->setValue(numberOfTriangles * (1.0 - reduction())); + ui->spinBoxReduction->setSuffix(QString()); + ui->checkAbsolueNumber->setText(tr("Absolute number (Maximum: %1)").arg(numberOfTriangles)); + } + else { + ui->spinBoxReduction->setRange(0, 100); + ui->spinBoxReduction->setValue(ui->sliderReduction->value()); + ui->spinBoxReduction->setSuffix(QString::fromLatin1("%")); + ui->checkAbsolueNumber->setText(tr("Absolute number")); + connect(ui->sliderReduction, SIGNAL(valueChanged(int)), ui->spinBoxReduction, SLOT(setValue(int))); + connect(ui->spinBoxReduction, SIGNAL(valueChanged(int)), ui->sliderReduction, SLOT(setValue(int))); + } +} + +double DlgDecimating::tolerance() const +{ + return ui->spinBoxTolerance->value(); +} + +/** + * Returns the level of reduction in the range [0, 1]. 0 means no reduction, 1 means full + * reduction. + */ +double DlgDecimating::reduction() const +{ + double max = static_cast(ui->sliderReduction->maximum()); + double min = static_cast(ui->sliderReduction->minimum()); + double val = static_cast(ui->sliderReduction->value()); + return (val - min)/(max - min); +} + +// --------------------------------------- + +/* TRANSLATOR MeshGui::TaskDecimating */ + +TaskDecimating::TaskDecimating() +{ + widget = new DlgDecimating(); + Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox( + QPixmap(), widget->windowTitle(), false, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); + + std::vector meshes = Gui::Selection().getObjectsOfType(); + if (meshes.size() == 1) { + Mesh::Feature* mesh = meshes.front(); + const Mesh::MeshObject& mm = mesh->Mesh.getValue(); + widget->setNumberOfTriangles(static_cast(mm.countFacets())); + } +} + +TaskDecimating::~TaskDecimating() +{ + // automatically deleted in the sub-class +} + +bool TaskDecimating::accept() +{ + std::vector meshes = Gui::Selection().getObjectsOfType(); + if (meshes.empty()) + return true; + Gui::Selection().clearSelection(); + + Gui::WaitCursor wc; + Gui::Command::openCommand("Mesh Decimating"); + + float tolerance = widget->tolerance(); + float reduction = widget->reduction(); + bool absolute = widget->isAbsoluteNumber(); + int targetSize = 0; + if (absolute) + targetSize = widget->targetNumberOfTriangles(); + for (std::vector::const_iterator it = meshes.begin(); it != meshes.end(); ++it) { + Mesh::Feature* mesh = *it; + Mesh::MeshObject* mm = mesh->Mesh.startEditing(); + if (absolute) + mm->decimate(targetSize); + else + mm->decimate(tolerance, reduction); + mesh->Mesh.finishEditing(); + } + + Gui::Command::commitCommand(); + return true; +} + +#include "moc_DlgDecimating.cpp" diff --git a/src/Mod/Mesh/Gui/DlgDecimating.h b/src/Mod/Mesh/Gui/DlgDecimating.h new file mode 100644 index 000000000000..47fdc15ce834 --- /dev/null +++ b/src/Mod/Mesh/Gui/DlgDecimating.h @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (c) 2020 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef MESHGUI_DLGDECIMATING_H +#define MESHGUI_DLGDECIMATING_H + +#include +#include +#include +#include + +namespace MeshGui { +class Ui_DlgDecimating; +class DlgDecimating : public QWidget +{ + Q_OBJECT + +public: + DlgDecimating(QWidget* parent = 0, Qt::WindowFlags fl = 0); + ~DlgDecimating(); + void setNumberOfTriangles(int); + double tolerance() const; + double reduction() const; + bool isAbsoluteNumber() const; + int targetNumberOfTriangles() const; + +private Q_SLOTS: + void on_checkAbsolueNumber_toggled(bool); + +private: + int numberOfTriangles; + std::unique_ptr ui; +}; + +/** + * Embed the panel into a task dialog. + */ +class TaskDecimating : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDecimating(); + ~TaskDecimating(); + +public: + bool accept(); + + virtual QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; } + virtual bool isAllowedAlterDocument(void) const + { return true; } + +private: + DlgDecimating* widget; +}; + +} + +#endif // MESHGUI_DLGDECIMATING_H diff --git a/src/Mod/Mesh/Gui/DlgDecimating.ui b/src/Mod/Mesh/Gui/DlgDecimating.ui new file mode 100644 index 000000000000..3cff4892d2ad --- /dev/null +++ b/src/Mod/Mesh/Gui/DlgDecimating.ui @@ -0,0 +1,139 @@ + + + MeshGui::DlgDecimating + + + + 0 + 0 + 412 + 214 + + + + Decimating + + + + + + Reduction + + + + + + + + None + + + + + + + 100 + + + 5 + + + 50 + + + Qt::Horizontal + + + QSlider::TicksAbove + + + 10 + + + + + + + Full + + + + + + + + + Absolute number + + + + + + + Qt::Horizontal + + + + 170 + 20 + + + + + + + + % + + + 100 + + + 50 + + + + + + + + + + Tolerance + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 16 + + + + + + + + 0.050000000000000 + + + 0.100000000000000 + + + + + + + + + + + + diff --git a/src/Mod/Mesh/Gui/Workbench.cpp b/src/Mod/Mesh/Gui/Workbench.cpp index aa9fb337ec81..91d2c0f284dd 100644 --- a/src/Mod/Mesh/Gui/Workbench.cpp +++ b/src/Mod/Mesh/Gui/Workbench.cpp @@ -218,6 +218,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Mesh_SegmentationBestFit" << "Separator" << "Mesh_Smoothing" + << "Mesh_Decimating" << "Mesh_Scale" << "Separator" << "Mesh_BuildRegularSolid"