diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt index b2a020333ec..9b9b2add68f 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/CMakeLists.txt @@ -27,7 +27,7 @@ polyhedron_demo_plugin(mesh_segmentation_plugin Mesh_segmentation_plugin ${segme target_link_libraries(mesh_segmentation_plugin scene_polyhedron_item scene_surface_mesh_item) qt5_wrap_ui( mesh_plane_detectionUI_FILES Mesh_plane_detection_dialog.ui) -polyhedron_demo_plugin(mesh_plane_detection_plugin Mesh_plane_detection_plugin Mesh_plane_detection_impl ${mesh_plane_detectionUI_FILES}) +polyhedron_demo_plugin(mesh_plane_detection_plugin Mesh_plane_detection_plugin ${mesh_plane_detectionUI_FILES}) target_link_libraries(mesh_plane_detection_plugin scene_polyhedron_item) qt5_wrap_ui( mesh_simplificationUI_FILES Mesh_simplification_dialog.ui) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_plane_detection_dialog.ui b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_plane_detection_dialog.ui new file mode 100644 index 00000000000..9e7625e4af3 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_plane_detection_dialog.ui @@ -0,0 +1,130 @@ + + + Mesh_plane_detection_dialog + + + + 0 + 0 + 349 + 117 + + + + Mesh Plane Detection + + + + + + + + Minimum area + + + + + + + 5 + + + 0.000010000000000 + + + 1000000.000000000000000 + + + 0.010000000000000 + + + 0.010000000000000 + + + + + + + Maximum deviation from normal + + + + + + + ° + + + 1 + + + 90 + + + 30 + + + + + + + + + Qt::Vertical + + + + 20 + 13 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + Mesh_plane_detection_dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Mesh_plane_detection_dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_plane_detection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_plane_detection_plugin.cpp new file mode 100644 index 00000000000..3ab81b0ad04 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Mesh_plane_detection_plugin.cpp @@ -0,0 +1,260 @@ +#include +#include + +#include "Scene_polyhedron_item.h" +#include "Polyhedron_type.h" +#include "Scene.h" +#include "Color_map.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include + +#include "ui_Mesh_plane_detection_dialog.h" + +namespace PMP = CGAL::Polygon_mesh_processing; + +using namespace CGAL::Three; +class Polyhedron_demo_mesh_plane_detection_plugin : + public QObject, + public Polyhedron_demo_plugin_helper +{ + Q_OBJECT + Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface) + Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0") + + public: + + QList actions() const { + return QList() << actionPlaneDetection; + } + + bool applicable(QAction*) const { + return + qobject_cast(scene->item(scene->mainSelectionIndex())); + } + + void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface*) { + this->scene = scene_interface; + this->mw = mainWindow; + actionPlaneDetection = new QAction("Mesh Plane Detection", mw); + actionPlaneDetection->setProperty("subMenuName", "Triangulated Surface Mesh Segmentation"); + actionPlaneDetection->setObjectName("actionPlaneDetection"); + + // adding slot for itemAboutToBeDestroyed signal, aim is removing item from item-functor map. + if( Scene* scene = dynamic_cast(scene_interface) ) { + connect(scene, SIGNAL(itemAboutToBeDestroyed(CGAL::Three::Scene_item*)), this, SLOT(itemAboutToBeDestroyed(CGAL::Three::Scene_item*))); + } + + autoConnectActions(); + } + virtual void closure() + { + } + + template + void colorize_segmentation(Scene_polyhedron_item* item, SegmentPropertyMap& segment_ids, std::vector& color_vector); + + void check_and_set_ids(Polyhedron* polyhedron); + +public Q_SLOTS: + void on_actionPlaneDetection_triggered(); + void itemAboutToBeDestroyed(CGAL::Three::Scene_item*); +private: + QAction* actionPlaneDetection; + + + template + void detect_planes_in_mesh (Polyhedron& mesh, const double area_min, + const double angle_max, + OutputIterator output) + { + std::cerr << "Detecting planes with:" << std::endl + << " * Area min = " << area_min << std::endl + << " * Min cos angle = " << angle_max << std::endl; + std::vector label_region(mesh.size_of_facets(), 0); + int class_index = 0; + + std::vector facets (mesh.size_of_facets()); + for (typename Polyhedron::Facet_iterator f = mesh.facets_begin(); f != mesh.facets_end(); ++f) + facets[f->id()] = f; + + for (typename Polyhedron::Facet_iterator f = mesh.facets_begin(); f != mesh.facets_end(); ++f) + { + if (label_region[f->id()] != 0) + continue; + class_index++; + label_region[f->id()] = class_index; + double area = PMP::face_area (f, mesh, PMP::parameters::geom_traits(Kernel())); + + //characteristics of the seed + Kernel::Vector_3 normal_seed = PMP::compute_face_normal (f, mesh, PMP::parameters::geom_traits(Kernel())); + Kernel::Point_3 pt_seed = f->halfedge()->vertex()->point(); + Kernel::Plane_3 optimal_plane(pt_seed, normal_seed); + // Kernel::Plane_3 optimal_plane = f->plane(); + + //initialization containers + std::vector index_container (1, f->id()); + std::vector index_container_former_ring (1, f->id()); + std::list index_container_current_ring; + + //propagation + bool propagation = true; + do{ + + propagation = false; + + for (std::size_t k = 0; k < index_container_former_ring.size(); k++) + { + typename Polyhedron::Halfedge_around_facet_circulator + circ = facets[index_container_former_ring[k]]->facet_begin(), start = circ; + + do + { + if (circ->is_border_edge()) + continue; + + typename Polyhedron::Facet_handle + neighbor = circ->opposite()->facet(); + std::size_t neighbor_index = neighbor->id(); + if (label_region[neighbor_index] == 0) + { + Kernel::Vector_3 normal + = PMP::compute_face_normal (neighbor, mesh, PMP::parameters::geom_traits(Kernel())); + + if (std::fabs(normal * optimal_plane.orthogonal_vector()) > angle_max) + { + label_region[neighbor_index] = class_index; + propagation = true; + index_container_current_ring.push_back(neighbor_index); + area += PMP::face_area (neighbor, mesh, PMP::parameters::geom_traits(Kernel())); + } + } + } + while (++ circ != start); + } + + //update containers + index_container_former_ring.clear(); + for (std::list::iterator it = index_container_current_ring.begin(); + it != index_container_current_ring.end(); ++it) + { + index_container_former_ring.push_back(*it); + index_container.push_back(*it); + } + index_container_current_ring.clear(); + + } while (propagation); + + //Test the number of inliers -> reject if inferior to Nmin + if (area < area_min) + { + class_index--; + label_region[f->id()] = 0; + for (std::size_t k = 0; k < index_container.size(); k++) + label_region[index_container[k]] = 0; + } + } + std::cerr << class_index << " planes detected" << std::endl; + + std::copy (label_region.begin(), label_region.end(), output); + } + +}; + +void Polyhedron_demo_mesh_plane_detection_plugin::itemAboutToBeDestroyed(CGAL::Three::Scene_item*) +{ +} + +void Polyhedron_demo_mesh_plane_detection_plugin::on_actionPlaneDetection_triggered() +{ + const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex(); + + Scene_polyhedron_item* poly_item = + qobject_cast(scene->item(index)); + + if (poly_item) + { + Polyhedron& pmesh =*poly_item->polyhedron(); + + QDialog dialog(mw); + Ui::Mesh_plane_detection_dialog ui; + ui.setupUi(&dialog); + + // check user cancellation + if(dialog.exec() == QDialog::Rejected) + return; + + QTime time; + time.start(); + std::cerr << "Detecting planes... "; + QApplication::setOverrideCursor(Qt::WaitCursor); + QApplication::processEvents(); + + check_and_set_ids (&pmesh); + std::vector indices; + detect_planes_in_mesh (pmesh, + ui.minimumAreaDoubleSpinBox->value(), + std::fabs(std::cos (CGAL_PI * ui.maximumDeviationFromNormalSpinBox->value() / 180.)), + std::back_inserter (indices)); + + poly_item->set_color_vector_read_only(true); + colorize_segmentation (poly_item, indices, poly_item->color_vector()); + + std::cerr << "ok (" << time.elapsed() << " ms, " + << pmesh.size_of_halfedges() / 2 << " edges)" << std::endl; + + poly_item->invalidateOpenGLBuffers(); + scene->itemChanged(index); + QApplication::restoreOverrideCursor(); + } + +} + + +void Polyhedron_demo_mesh_plane_detection_plugin::check_and_set_ids(Polyhedron* polyhedron) +{ + std::size_t facet_id = 0; + for(Polyhedron::Facet_iterator facet_it = polyhedron->facets_begin(); + facet_it != polyhedron->facets_end(); ++facet_it, ++facet_id) + facet_it->id() = facet_id; +} + +template +void Polyhedron_demo_mesh_plane_detection_plugin::colorize_segmentation( + Scene_polyhedron_item* item, + SegmentPropertyMap& segment_ids, + std::vector& color_vector) +{ + item->setItemIsMulticolor(true); + Polyhedron* polyhedron = item->polyhedron(); + color_vector.clear(); + std::size_t max_segment = 0; + for(Polyhedron::Facet_iterator facet_it = polyhedron->facets_begin(); + facet_it != polyhedron->facets_end(); ++facet_it) + { + std::size_t segment_id = segment_ids[facet_it->id()]; + facet_it->set_patch_id(static_cast(segment_id)); + max_segment = (std::max)(max_segment, segment_id); + } + color_vector.push_back(QColor(0, 0, 0)); + for(std::size_t i = 1; i <= max_segment; ++i) + color_vector.push_back (QColor (CGAL::get_default_random().get_int (41, 255), + CGAL::get_default_random().get_int (35, 238), + CGAL::get_default_random().get_int (35, 255))); +} + +#include "Mesh_plane_detection_plugin.moc"