#include #include #include "Scene_surface_mesh_item.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_Remesh_planar_patches_dialog.h" namespace PMP = CGAL::Polygon_mesh_processing; template struct Mesh_map { typedef SM value_type; typedef SM& reference; typedef Scene_surface_mesh_item* key_type; typedef boost::lvalue_property_map_tag category; SM& operator[](Scene_surface_mesh_item* poly_item) const { return *poly_item->polyhedron(); } }; using namespace CGAL::Three; class Polyhedron_demo_remesh_planar_patches_plugin : public QObject, public Polyhedron_demo_plugin_interface { Q_OBJECT Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface) Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0" FILE "isotropic_remeshing_plugin.json") typedef Scene_surface_mesh_item::Face_graph Mesh; typedef boost::graph_traits::face_descriptor face_descriptor; typedef boost::graph_traits::edge_descriptor edge_descriptor; typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; public: void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*) { this->scene = scene_interface; this->mw = mainWindow; actionRemeshPlanarPatches_ = new QAction("Remesh Planar Patches", mw); actionRemeshPlanarPatches_->setProperty("subMenuName", "Polygon Mesh Processing"); if (actionRemeshPlanarPatches_) { connect(actionRemeshPlanarPatches_, SIGNAL(triggered()), this, SLOT(remeshing())); } } QList actions() const { return QList() << actionRemeshPlanarPatches_; } bool applicable(QAction*) const { if (scene->selectionIndices().size() == 1) return qobject_cast(scene->item(scene->mainSelectionIndex())); for(int index : scene->selectionIndices()) { if (qobject_cast(scene->item(index))) return true; } return false; } public Q_SLOTS: void remeshing() { if (scene->selectionIndices().size() > 1) { // Create dialog box QDialog dialog(mw); ui.setupUi(&dialog); connect(ui.buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept())); connect(ui.buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); ui.create_new_item_checkbox->setEnabled(false); ui.use_region_growing_checkbox->setEnabled(false); // Get values int i = dialog.exec(); if (i == QDialog::Rejected) { std::cout << "Remeshing aborted" << std::endl; return; } bool do_not_triangulate_faces = ui.notriangulation_checkbox->isChecked(); double cos_threshold = ui.cos_dspinbox->value(); std::vector meshes; for(int index : scene->selectionIndices()) { Scene_surface_mesh_item* poly_item = qobject_cast(scene->item(index)); if (poly_item != nullptr) meshes.push_back(poly_item); } PMP::decimate_meshes_with_common_interfaces(meshes, -cos_threshold, Mesh_map(), do_not_triangulate_faces); for (Scene_surface_mesh_item* poly_item : meshes) { poly_item->invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); } return; } const Scene_interface::Item_id index = scene->mainSelectionIndex(); Scene_surface_mesh_item* poly_item = qobject_cast(scene->item(index)); if (poly_item) { // Create dialog box QDialog dialog(mw); ui.setupUi(&dialog); connect(ui.buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept())); connect(ui.buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); // Get values int i = dialog.exec(); if (i == QDialog::Rejected) { std::cout << "Remeshing aborted" << std::endl; return; } bool do_not_triangulate_faces = ui.notriangulation_checkbox->isChecked(); bool create_new_item = ui.create_new_item_checkbox->isChecked(); double cos_threshold = ui.cos_dspinbox->value(); // wait cursor QApplication::setOverrideCursor(Qt::WaitCursor); QElapsedTimer time; time.start(); Mesh& pmesh = *poly_item->polyhedron(); if (!CGAL::is_triangle_mesh(pmesh)) { QApplication::restoreOverrideCursor(); if (QMessageBox::Ok == QMessageBox::question(mw, tr("Error - Triangulate Faces?"), tr("The input mesh is not a triangulated surface mesh.\n" "Do you wish to triangulate faces first, or cancel remeshing ?"), (QMessageBox::Ok | QMessageBox::Cancel), QMessageBox::Ok)) { QApplication::setOverrideCursor(Qt::WaitCursor); PMP::triangulate_faces(pmesh); } else { return; } } if (ui.use_region_growing_checkbox->isChecked()) { typedef boost::property_map >::type Patch_id_pmap; Patch_id_pmap in_fpmap = get(CGAL::face_patch_id_t(), pmesh); std::vector corner_id_map(num_vertices(pmesh), -1); std::vector ecm(num_edges(pmesh), false); boost::vector_property_map normal_map; std::size_t nb_regions = PMP::region_growing_of_planes_on_faces(pmesh, in_fpmap, CGAL::parameters::cosine_of_maximum_angle(cos_threshold). region_primitive_map(normal_map). maximum_distance(ui.dist_dspinbox->value()). postprocess_regions(ui.postprocess_regions_checkbox->isChecked())); std::size_t nb_corners = PMP::detect_corners_of_regions(pmesh, in_fpmap, nb_regions, CGAL::make_random_access_property_map(corner_id_map), CGAL::parameters::cosine_of_maximum_angle(cos_threshold). maximum_distance(ui.dist_dspinbox->value()). edge_is_constrained_map(CGAL::make_random_access_property_map(ecm))); if (create_new_item) { Scene_surface_mesh_item* new_item=new Scene_surface_mesh_item(); Mesh& out = *new_item->polyhedron(); Patch_id_pmap out_fpmap = get(CGAL::face_patch_id_t(), out); //TODO: use the return type PMP::remesh_almost_planar_patches(pmesh, out, nb_regions, nb_corners, in_fpmap, CGAL::make_random_access_property_map(corner_id_map), CGAL::make_random_access_property_map(ecm), CGAL::parameters::patch_normal_map(normal_map), CGAL::parameters::do_not_triangulate_faces(do_not_triangulate_faces).face_patch_map(out_fpmap)); new_item->setName(tr("%1_remeshed").arg(poly_item->name())); scene->setSelectedItem( scene->addItem(new_item) ); poly_item->setItemIsMulticolor(true); poly_item->computeItemColorVectorAutomatically(true); poly_item->invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); new_item->setItemIsMulticolor(true); new_item->computeItemColorVectorAutomatically(false); new_item->color_vector()=poly_item->color_vector(); // colors are not deterministic new_item->invalidateOpenGLBuffers(); Q_EMIT new_item->itemChanged(); } else { PMP::remesh_almost_planar_patches(pmesh, pmesh, nb_regions, nb_corners, in_fpmap, CGAL::make_random_access_property_map(corner_id_map), CGAL::make_random_access_property_map(ecm), CGAL::parameters::patch_normal_map(normal_map), CGAL::parameters::visitor([](Mesh& pmesh){pmesh.clear_without_removing_property_maps ();}) .do_not_triangulate_faces(do_not_triangulate_faces)); pmesh.remove_property_map(in_fpmap); poly_item->invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); } } else { if (create_new_item) { typedef boost::property_map >::type Patch_id_pmap; Scene_surface_mesh_item* new_item=new Scene_surface_mesh_item(); Mesh& out = *new_item->polyhedron(); Patch_id_pmap in_fpmap = get(CGAL::face_patch_id_t(), pmesh); Patch_id_pmap out_fpmap = get(CGAL::face_patch_id_t(), out); PMP::remesh_planar_patches(pmesh, out, CGAL::parameters::cosine_of_maximum_angle(cos_threshold) .face_patch_map(in_fpmap), CGAL::parameters::face_patch_map(out_fpmap) .do_not_triangulate_faces(do_not_triangulate_faces)); new_item->setName(tr("%1_remeshed").arg(poly_item->name())); scene->setSelectedItem( scene->addItem(new_item) ); poly_item->setItemIsMulticolor(true); poly_item->computeItemColorVectorAutomatically(true); poly_item->invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); new_item->setItemIsMulticolor(true); new_item->computeItemColorVectorAutomatically(false); new_item->color_vector()=poly_item->color_vector(); // colors are not deterministic new_item->invalidateOpenGLBuffers(); Q_EMIT new_item->itemChanged(); } else { PMP::remesh_planar_patches(pmesh, pmesh, CGAL::parameters::cosine_of_maximum_angle(cos_threshold), CGAL::parameters::visitor([](Mesh& pmesh){pmesh.clear_without_removing_property_maps ();}) .do_not_triangulate_faces(do_not_triangulate_faces)); poly_item->invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); } } std::cout << "ok (" << time.elapsed() << " ms)" << std::endl; // default cursor QApplication::restoreOverrideCursor(); } } private: Scene_interface *scene; QMainWindow* mw; QAction* actionRemeshPlanarPatches_; Ui::Remesh_planar_patches_dialog ui; }; // end Polyhedron_demo_remesh_planar_patches_plugin #include "Remesh_planar_patches_plugin.moc"