diff --git a/CMakeLists.txt b/CMakeLists.txt index a7119a5..a0dbf01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,8 +33,10 @@ target_sources(${PROJECT_NAME} PRIVATE src/quad_patch.h src/quad_patch_tesselator.cpp src/quad_patch_tesselator.h + src/hole_filling.cpp src/hole_filling.h - src/hole_filling.cpp) + src/double_input.cpp + src/double_input.h) target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Gui Qt5::Widgets OpenMeshCore diff --git a/src/double_input.cpp b/src/double_input.cpp new file mode 100644 index 0000000..d70f64f --- /dev/null +++ b/src/double_input.cpp @@ -0,0 +1,58 @@ +#include "double_input.h" + + +double DoubleInput::intToDouble(int value) const { + return static_cast(value) / _slider_resolution + * (_max - _min) + _min; +} + + +int DoubleInput::doubleToInt(double value) const { + return (value - _min) / (_max - _min) * _slider_resolution; +} + + +void DoubleInput::onSpinBoxValueChanged(double value) { + emit valueChanged(value); + if (_propagate) { + _propagate = false; + _slider->setValue(doubleToInt(value)); + } else { + _propagate = true; + } +} + + +void DoubleInput::onSliderValueChanged(int value) { + if (_propagate) { + _propagate = false; + _spin_box->setValue(intToDouble(value)); + } else { + _propagate = true; + } +} + + +DoubleInput::DoubleInput(QObject *parent, double min, double max, + double value, + int slider_resolution) + :QObject(parent), + _min(min), + _max(max), + _slider_resolution(slider_resolution), + _spin_box(new QDoubleSpinBox()), + _slider(new QSlider(Qt::Horizontal)) { + _spin_box->setRange(_min, _max); + _spin_box->setValue(value); + _slider->setMaximum(_slider_resolution); + _slider->setValue(doubleToInt(value)); + connect(_slider, &QSlider::valueChanged, + this, &DoubleInput::onSliderValueChanged); + connect(_spin_box, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &DoubleInput::onSpinBoxValueChanged); +} + + +void DoubleInput::setValue(double value) { + _spin_box->setValue(value); +} diff --git a/src/double_input.h b/src/double_input.h new file mode 100644 index 0000000..9371c19 --- /dev/null +++ b/src/double_input.h @@ -0,0 +1,41 @@ +#ifndef DOUBLE_INPUT_H +#define DOUBLE_INPUT_H + +#include +#include +#include + + +class DoubleInput : public QObject { + Q_OBJECT + + const double _min; + const double _max; + const int _slider_resolution; + QDoubleSpinBox *_spin_box; + QSlider *_slider; + bool _propagate = true; + + double intToDouble(int value) const; + int doubleToInt(double value) const; + +private slots: + void onSpinBoxValueChanged(double value); + void onSliderValueChanged(int value); + +public: + DoubleInput(QObject *parent, double min, double max, double value, + int slider_resolution=100); + QWidget *spinBox() { return _spin_box; } + QWidget *slider() { return _slider; } + double value() const { return _spin_box->value(); } + +signals: + void valueChanged(double value); + +public slots: + void setValue(double value); +}; + + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 65c1689..7dc8c80 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,9 @@ static MeshProcessor *create_mesh_processor(const QString &path, MainWindow &main_window) { MeshViewer &mesh_viewer = main_window.mesh_viewer; - MeshProcessor *mesh_processor = new MeshProcessor(path, mesh_viewer); + MeshProcessor *mesh_processor = new MeshProcessor(path, mesh_viewer, + main_window.fillHolesImplicitScale(), + main_window.fillHolesImplicitDiscr()); QObject::connect(&main_window, &MainWindow::fillHolesDumbClicked, mesh_processor, &MeshProcessor::fillHolesDumb); QObject::connect(&main_window, &MainWindow::fillHolesImplicitClicked, diff --git a/src/main_window.cpp b/src/main_window.cpp index b60148e..5b93ee1 100644 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -1,5 +1,6 @@ #include "main_window.h" #include "mesh_processor.h" +#include "double_input.h" #include #include @@ -8,7 +9,6 @@ #include #include #include -#include MainWindow::MainWindow(QWidget *parent) @@ -71,61 +71,24 @@ MainWindow::MainWindow(QWidget *parent) this, &MainWindow::fillHolesImplicitClicked); hole_layout->addWidget(fill_holes_implicit, 1, 0); - const double implicit_scale_min = 0; - const double implicit_scale_max = 10; QLabel *implicit_scale_text = new QLabel("Échelle du remplissage implicite", this); hole_layout->addWidget(implicit_scale_text, 2, 0); - QDoubleSpinBox *implicit_scale_sb = new QDoubleSpinBox(this); - implicit_scale_sb->setMinimum(implicit_scale_min); - implicit_scale_sb->setMaximum(implicit_scale_max); - hole_layout->addWidget(implicit_scale_sb, 3, 0); - QSlider *implicit_scale = new QSlider(Qt::Horizontal, this); - connect(implicit_scale, &QSlider::valueChanged, - [=](int v) { - double val = v / 100. * (implicit_scale_max - - implicit_scale_min) - + implicit_scale_min; - fillHolesImplicitScaleChanged(val); - if (val != implicit_scale_sb->value()) { - implicit_scale_sb->setValue(val); - } - }); - connect(implicit_scale_sb, QOverload::of(&QDoubleSpinBox::valueChanged), - [=](double v) { - if (v != implicit_scale_sb->value()) { - implicit_scale->setValue(v); - } - }); - hole_layout->addWidget(implicit_scale, 3, 1); + fill_holes_implicit_scale = new DoubleInput(this, 0, 10, 4); + connect(fill_holes_implicit_scale, &DoubleInput::valueChanged, + this, &MainWindow::fillHolesImplicitScaleChanged); + hole_layout->addWidget(fill_holes_implicit_scale->slider(), 3, 0); + hole_layout->addWidget(fill_holes_implicit_scale->spinBox(), 3, 1); - const double implicit_discr_min = 0; - const double implicit_discr_max = .1; QLabel *implicit_discr_text = new QLabel("Taux de discrétisation du remplissage implicite", this); hole_layout->addWidget(implicit_discr_text, 4, 0); - QDoubleSpinBox *implicit_discr_sb = new QDoubleSpinBox(this); - implicit_discr_sb->setMinimum(implicit_discr_min); - implicit_discr_sb->setMaximum(implicit_discr_max); - hole_layout->addWidget(implicit_discr_sb, 5, 0); - QSlider *implicit_discr = new QSlider(Qt::Horizontal, this); - connect(implicit_discr, &QSlider::valueChanged, - [=](int v) { - double val = v / 100. * (implicit_discr_max - - implicit_discr_min) - + implicit_discr_min; - fillHolesImplicitDiscrChanged(val); - if (val != implicit_discr_sb->value()) { - implicit_discr_sb->setValue(val); - } - }); - connect(implicit_discr_sb, QOverload::of(&QDoubleSpinBox::valueChanged), - [=](double v) { - if (v != implicit_discr_sb->value()) { - implicit_discr->setValue(v); - } - }); - hole_layout->addWidget(implicit_discr, 5, 1); + fill_holes_implicit_discr = new DoubleInput(this, .02, .1, 1/40.); + connect(fill_holes_implicit_discr, &DoubleInput::valueChanged, + this, &MainWindow::fillHolesImplicitDiscrChanged); + hole_layout->addWidget(fill_holes_implicit_discr->slider(), 5, 0); + hole_layout->addWidget(fill_holes_implicit_discr->spinBox(), 5, 1); + toolbar.addWidget(hole_box); diff --git a/src/main_window.h b/src/main_window.h index c6e3a82..033e680 100644 --- a/src/main_window.h +++ b/src/main_window.h @@ -1,12 +1,14 @@ #ifndef MAIN_WINDOW_H #define MAIN_WINDOW_H +#include "mesh_viewer.h" +#include "my_mesh.h" +#include "double_input.h" + #include #include #include - -#include "mesh_viewer.h" -#include "my_mesh.h" +#include class MainWindow : public QMainWindow { @@ -15,6 +17,8 @@ class MainWindow : public QMainWindow { QToolBar toolbar; QAction *open_action; QAction *save_action; + DoubleInput *fill_holes_implicit_scale; + DoubleInput *fill_holes_implicit_discr; signals: void open(const QString &path); @@ -30,6 +34,12 @@ public: MeshViewer mesh_viewer; MainWindow(QWidget *parent=nullptr); + double fillHolesImplicitScale() const { + return fill_holes_implicit_scale->value(); + } + double fillHolesImplicitDiscr() const { + return fill_holes_implicit_discr->value(); + } }; diff --git a/src/mesh_processor.cpp b/src/mesh_processor.cpp index 0cc40a3..b278a4b 100644 --- a/src/mesh_processor.cpp +++ b/src/mesh_processor.cpp @@ -8,8 +8,12 @@ #include -MeshProcessor::MeshProcessor(const QString &path, MeshViewer &mesh_viewer) - :mesh_viewer(mesh_viewer) { +MeshProcessor::MeshProcessor(const QString &path, MeshViewer &mesh_viewer, + double implicit_hole_filling_scale, + double implicit_hole_filling_discr) + :mesh_viewer(mesh_viewer), + implicit_hole_filling_scale(implicit_hole_filling_scale), + implicit_hole_filling_discr(implicit_hole_filling_discr) { OpenMesh::IO::Options options; options.set(OpenMesh::IO::Options::VertexColor); if (!OpenMesh::IO::read_mesh(mesh, path.toUtf8().constData(), options)) { @@ -60,12 +64,16 @@ void MeshProcessor::fillHolesDumb() { void MeshProcessor::fillHolesImplicit() { - std::vector fillings = + for (MyMesh &filling : fillings) { + mesh_viewer.removeMesh(filling); + } + std::vector new_fillings = ::fillHolesImplicit(mesh, implicit_hole_filling_scale, implicit_hole_filling_discr); - for (MyMesh &filling : fillings) { - mesh_viewer.addMesh(filling); + for (MyMesh &filling : new_fillings) { + fillings.push_back(filling); + mesh_viewer.addMesh(fillings[fillings.size() - 1]); } updateView(); } @@ -73,11 +81,17 @@ void MeshProcessor::fillHolesImplicit() { void MeshProcessor::setImplicitHoleFillingScale(float scale) { implicit_hole_filling_scale = scale; + if (fillings.size() > 0) { + fillHolesImplicit(); + } } void MeshProcessor::setImplicitHoleFillingDiscr(float discr) { implicit_hole_filling_discr = discr; + if (fillings.size() > 0) { + fillHolesImplicit(); + } } diff --git a/src/mesh_processor.h b/src/mesh_processor.h index 0250081..5566f69 100644 --- a/src/mesh_processor.h +++ b/src/mesh_processor.h @@ -14,8 +14,9 @@ class MeshProcessor : public QObject { Courbures *courbure = nullptr; MeshViewer &mesh_viewer; bool view_patches = false; - float implicit_hole_filling_scale = 4; - float implicit_hole_filling_discr = 1./40; + double implicit_hole_filling_scale; + double implicit_hole_filling_discr; + std::vector fillings; void updateView() const; @@ -23,7 +24,9 @@ public: MyMesh mesh; MyMesh patch; - MeshProcessor(const QString &path, MeshViewer &mesh_viewer); + MeshProcessor(const QString &path, MeshViewer &mesh_viewer, + double implicit_hole_filling_scale, + double implicit_hole_filling_discr); ~MeshProcessor(); public slots: