From 36891b758960151bcc8dc2767650032c6cfa2318 Mon Sep 17 00:00:00 2001 From: papush! Date: Thu, 25 Nov 2021 14:59:13 +0100 Subject: [PATCH] ui rework --- src/main.cpp | 23 ++++++++-- src/main_window.cpp | 75 +++++++++++++++++++++++++++----- src/main_window.h | 8 +++- src/mesh_processor.cpp | 99 ++++++++++++++++++------------------------ src/mesh_processor.h | 8 +++- src/my_mesh.h | 4 +- 6 files changed, 142 insertions(+), 75 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 91fe2e8..fc77854 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,22 @@ #include +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); + QObject::connect(&main_window, &MainWindow::fillHolesDumbClicked, + mesh_processor, &MeshProcessor::fillHolesDumb); + QObject::connect(&main_window, &MainWindow::fillHolesImplicitClicked, + mesh_processor, &MeshProcessor::fillHolesImplicit); + QObject::connect(&main_window, &MainWindow::smoothClicked, + mesh_processor, &MeshProcessor::smooth); + QObject::connect(&main_window, &MainWindow::patchViewToggled, + mesh_processor, &MeshProcessor::setPatchView); + return mesh_processor; +} + + int main(int argc, char *argv[]) { using namespace std; QSurfaceFormat format; @@ -17,18 +33,17 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); MeshProcessor *mesh_processor = nullptr; MainWindow main_window; - MeshViewer *mesh_viewer = &main_window.mesh_viewer; if (argc > 2) { qWarning("Utilisation : %s [MAILLAGE]", argv[0]); return 1; } else if (argc == 2) { - mesh_processor = new MeshProcessor(argv[1], *mesh_viewer); + mesh_processor = create_mesh_processor(argv[1], main_window); } QObject::connect(&main_window, &MainWindow::open, [&](const QString &path) { if (mesh_processor) delete mesh_processor; - mesh_processor = new MeshProcessor(path, - *mesh_viewer); + mesh_processor = create_mesh_processor + (path, main_window); }); main_window.show(); return app.exec(); diff --git a/src/main_window.cpp b/src/main_window.cpp index 012e27a..47bf221 100644 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -3,20 +3,21 @@ #include #include +#include +#include +#include MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent), toolbar(this), mesh_viewer() { - connect(&mesh_viewer, &MeshViewer::initialized, [&]() { - open_action->setEnabled(true); - }); setCentralWidget(&mesh_viewer); - addToolBar(Qt::RightToolBarArea, &toolbar); - open_action = toolbar.addAction("Ouvrir…", [&](){ - emit open(QFileDialog::getOpenFileName(this, "Ouvrir un maillage")); - }); + // addToolBar(Qt::RightToolBarArea, &toolbar); + + // open_action = toolbar.addAction("Ouvrir…", [&](){ + // emit open(QFileDialog::getOpenFileName(this, "Ouvrir un maillage")); + // }); // toolbar_actions.append(toolbar.addAction("Fractionner", [&](){ // QVector> fragments = shatter(mesh); // mesh_viewer.removeOpenGLMesh(glm); @@ -28,8 +29,62 @@ MainWindow::MainWindow(QWidget *parent) // mesh_viewer.addOpenGLMeshFromOpenMesh(&fragment, mat); // } // })); - open_action->setEnabled(false); - for (QAction *a : toolbar_actions) { - a->setEnabled(false); + + QMenuBar *menu_bar = new QMenuBar(); + setMenuBar(menu_bar); + + // File menu + QMenu *file_menu = new QMenu("Fichier"); + open_action = file_menu->addAction("Ouvrir…", [&](){ + emit open(QFileDialog::getOpenFileName(this, "Ouvrir un maillage")); + }); + save_action = file_menu->addAction("Enregistrer sous…", [&]() { + emit save(QFileDialog::getSaveFileName(this, + "Enregistrer un maillage")); + }); + menu_bar->addMenu(file_menu); + if (!mesh_viewer.isInitialized()) { + open_action->setEnabled(false); + connect(&mesh_viewer, &MeshViewer::initialized, [&]() { + open_action->setEnabled(true); + }); } + + addToolBar(Qt::RightToolBarArea, &toolbar); + + // Hole filling tools + QGroupBox *hole_box = new QGroupBox("Remplissage de trous"); + QLayout *hole_vbox = new QVBoxLayout(); + hole_box->setLayout(hole_vbox); + QPushButton *fill_holes_dumb = new QPushButton("Remplir bêtement"); + connect(fill_holes_dumb, &QPushButton::clicked, + this, &MainWindow::fillHolesDumbClicked); + hole_vbox->addWidget(fill_holes_dumb); + QPushButton *fill_holes_implicit = new QPushButton("Remplir bêtement"); + connect(fill_holes_implicit, &QPushButton::clicked, + this, &MainWindow::fillHolesImplicitClicked); + hole_vbox->addWidget(fill_holes_implicit); + toolbar.addWidget(hole_box); + + // Smoothing tools + QGroupBox *smooth_box = new QGroupBox("Adoucissement"); + QLayout *smooth_vbox = new QVBoxLayout(); + smooth_box->setLayout(smooth_vbox); + QPushButton *smooth = new QPushButton("Adoucir"); + connect(smooth, &QPushButton::clicked, + this, &MainWindow::smoothClicked); + smooth_vbox->addWidget(smooth); + toolbar.addWidget(smooth_box); + + // Curvature tools + QGroupBox *curvature_box = new QGroupBox("Analyse de courbure"); + QLayout *curvature_vbox = new QVBoxLayout(); + curvature_box->setLayout(curvature_vbox); + QPushButton *patch_mode = new QPushButton( + "Afficher le patch de la sélection"); + patch_mode->setCheckable(true); + connect(patch_mode, &QPushButton::toggled, + this, &MainWindow::patchViewToggled); + curvature_vbox->addWidget(patch_mode); + toolbar.addWidget(curvature_box); } diff --git a/src/main_window.h b/src/main_window.h index 62a3a9e..76832de 100644 --- a/src/main_window.h +++ b/src/main_window.h @@ -3,6 +3,7 @@ #include #include +#include #include "mesh_viewer.h" #include "my_mesh.h" @@ -13,10 +14,15 @@ class MainWindow : public QMainWindow { QToolBar toolbar; QAction *open_action; - QList toolbar_actions; + QAction *save_action; signals: void open(const QString &path); + void save(const QString &path); + void fillHolesDumbClicked(); + void fillHolesImplicitClicked(); + void smoothClicked(); + void patchViewToggled(bool checked); public: MeshViewer mesh_viewer; diff --git a/src/mesh_processor.cpp b/src/mesh_processor.cpp index d9610a4..cec4ad4 100644 --- a/src/mesh_processor.cpp +++ b/src/mesh_processor.cpp @@ -1,31 +1,13 @@ #include "quad_patch_tesselator.h" #include "mesh_processor.h" #include "util.h" +#include "hole_filling.h" #include "smoothing.h" #include "curvature.h" #include #include -static std::vector> findHoles(MyMesh &mesh) { - std::vector> holes; - std::set ignore; - for (HalfedgeHandle it : mesh.halfedges()) { - if (mesh.is_boundary(it) - && ignore.find(it) == ignore.end()) { - holes.emplace_back(); - holes.back().push_back(it); - ignore.insert(it); - for (HalfedgeHandle it2 : HalfedgeLoopRange(mesh, it)) { - holes.back().push_back(it2); - ignore.insert(it2); - } - } - } - return holes; -} - - MeshProcessor::MeshProcessor(const QString &path, MeshViewer &mesh_viewer) :mesh_viewer(mesh_viewer) { OpenMesh::IO::Options options; @@ -34,65 +16,68 @@ MeshProcessor::MeshProcessor(const QString &path, MeshViewer &mesh_viewer) qWarning() << "Failed to read" << path; return; } - mesh.update_normals(); - // courbure = new Courbures(mesh); - // courbure->compute_KH(); - // courbure->set_K_colors(); - mesh.holes = findHoles(mesh); - fillHoles(); - // smooth(mesh); - if (mesh_viewer.isInitialized()) { - mesh_viewer.addMesh(mesh); - } else { - connect(&mesh_viewer, &MeshViewer::initialized, - [&]() { mesh_viewer.addMesh(mesh); }); + for (VertexHandle vh : mesh.vertices()) { + mesh.set_color(vh, MyMesh::Color(.5, .5, .5)); + } + courbure = new Courbures(mesh); + try { + courbure->compute_KH(); + courbure->set_K_colors(); + } catch (std::runtime_error &e) { + qWarning() << "Curvature computation failed"; } connect(&mesh_viewer, &MeshViewer::clicked, this, &MeshProcessor::click); + updateView(); } MeshProcessor::~MeshProcessor() { if (mesh_viewer.isInitialized()) { mesh_viewer.removeMesh(mesh); - } else { - connect(&mesh_viewer, &MeshViewer::initialized, - [&]() { mesh_viewer.removeMesh(mesh); }); } if (courbure) delete courbure; } -void fillHoleDumb(MyMesh &mesh, std::vector &hole) { - mesh.request_vertex_status(); - mesh.request_edge_status(); - mesh.request_face_status(); - - Point center(0, 0, 0); - size_t length = 0; - for (HalfedgeHandle it : hole) { - VertexHandle vert = mesh.to_vertex_handle(it); - center += mesh.point(vert); - length++; - } - center /= length; - VertexHandle center_handle = mesh.new_vertex_dirty(center); - - for (HalfedgeHandle it : hole) { - mesh.add_face(mesh.from_vertex_handle(it), - mesh.to_vertex_handle(it), - center_handle); +void MeshProcessor::updateView() const { + if (mesh_viewer.isInitialized()) { + mesh_viewer.removeMesh(mesh); + mesh_viewer.addMesh(mesh); + mesh_viewer.updateForReal(); + } else { + connect(&mesh_viewer, &MeshViewer::initialized, [&]() { + mesh_viewer.addMesh(mesh); + mesh_viewer.updateForReal(); + }); } } -void MeshProcessor::fillHoles() { - for (auto hole : mesh.holes) { - fillHoleDumb(mesh, hole); - } +void MeshProcessor::fillHolesDumb() { + ::fillHolesDumb(mesh); + updateView(); +} + + +void MeshProcessor::fillHolesImplicit() { + ::fillHolesImplicit(mesh); + updateView(); +} + + +void MeshProcessor::smooth() { + ::smooth(mesh); + updateView(); +} + + +void MeshProcessor::setPatchView(bool on) { + view_patches = on; } void MeshProcessor::click(QVector3D position) { + if (!view_patches) return; Eigen::Vector3d pos {position.x(), position.y(), position.z()}; MyMesh::VertexIter it = mesh.vertices_begin(); VertexHandle min_vert = *it; diff --git a/src/mesh_processor.h b/src/mesh_processor.h index 60154fc..06c07e1 100644 --- a/src/mesh_processor.h +++ b/src/mesh_processor.h @@ -13,6 +13,9 @@ class MeshProcessor : public QObject { Courbures *courbure = nullptr; MeshViewer &mesh_viewer; + bool view_patches = false; + + void updateView() const; public: MyMesh mesh; @@ -22,7 +25,10 @@ public: ~MeshProcessor(); public slots: - void fillHoles(); + void fillHolesDumb(); + void fillHolesImplicit(); + void smooth(); + void setPatchView(bool on); void click(QVector3D position); }; diff --git a/src/my_mesh.h b/src/my_mesh.h index 79db8d0..f0f2114 100644 --- a/src/my_mesh.h +++ b/src/my_mesh.h @@ -17,14 +17,14 @@ struct MyTraits : public OpenMesh::DefaultTraits { VertexAttributes(OpenMesh::Attributes::Normal | OpenMesh::Attributes::Color); HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge); FaceAttributes(OpenMesh::Attributes::Normal); - EdgeAttributes(OpenMesh::Attributes::Color); + // EdgeAttributes(OpenMesh::Attributes::Color); }; class MyMesh : public OpenMesh::TriMesh_ArrayKernelT { public: + Color default_color {.5, .5, .5}; QMatrix4x4 transform; std::vector> holes; - // QColor color = {127, 127, 127}; }; typedef MyMesh::FaceHandle FaceHandle;