diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Point_set/CMakeLists.txt index 9c56ba4df2a..df97b278ef6 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/CMakeLists.txt @@ -18,6 +18,10 @@ if(EIGEN3_FOUND) polyhedron_demo_plugin(point_set_average_spacing_plugin Point_set_average_spacing_plugin KEYWORDS PointSetProcessing Classification) target_link_libraries(point_set_average_spacing_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler) + qt5_wrap_ui(point_set_shape_detectionUI_FILES Point_set_shape_detection_plugin.ui) + polyhedron_demo_plugin(point_set_shape_detection_plugin Point_set_shape_detection_plugin ${point_set_shape_detectionUI_FILES} KEYWORDS PointSetProcessing Classification) + target_link_libraries(point_set_shape_detection_plugin PUBLIC scene_surface_mesh_item scene_points_with_normal_item scene_polygon_soup_item scene_callback_signaler) + else(EIGEN3_FOUND) message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Surface reconstruction plugin will not be available.") message(STATUS "NOTICE: Eigen 3.1 (or greater) was not found. Normal estimation plugins will not be available.") @@ -39,10 +43,6 @@ endif() polyhedron_demo_plugin(point_set_selection_plugin Point_set_selection_plugin ${point_set_selectionUI_FILES} KEYWORDS PointSetProcessing Classification) target_link_libraries(point_set_selection_plugin PUBLIC scene_points_with_normal_item scene_polylines_item scene_edit_box_item) - qt5_wrap_ui(point_set_shape_detectionUI_FILES Point_set_shape_detection_plugin.ui) - polyhedron_demo_plugin(point_set_shape_detection_plugin Point_set_shape_detection_plugin ${point_set_shape_detectionUI_FILES} KEYWORDS PointSetProcessing Classification) - target_link_libraries(point_set_shape_detection_plugin PUBLIC scene_surface_mesh_item scene_points_with_normal_item scene_polygon_soup_item scene_callback_signaler) - qt5_wrap_ui(point_set_simplificationUI_FILES Point_set_simplification_plugin.ui) polyhedron_demo_plugin(point_set_simplification_plugin Point_set_simplification_plugin ${point_set_simplificationUI_FILES} KEYWORDS PointSetProcessing) target_link_libraries(point_set_simplification_plugin PUBLIC scene_points_with_normal_item scene_callback_signaler) @@ -76,10 +76,10 @@ endif() features_detection_plugin point_set_smoothing_plugin point_set_average_spacing_plugin + point_set_shape_detection_plugin point_set_bilateral_smoothing_plugin point_set_outliers_removal_plugin point_set_selection_plugin - point_set_shape_detection_plugin point_set_simplification_plugin point_set_upsampling_plugin point_set_wlop_plugin diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_shape_detection_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_shape_detection_plugin.cpp index deac2b9c0d0..5b074f6c61c 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_shape_detection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_shape_detection_plugin.cpp @@ -72,7 +72,7 @@ struct build_from_pair }; -class Point_set_demo_point_set_shape_detection_dialog : public QDialog, private Ui::PointSetShapeDetectionDialog +class Point_set_demo_point_set_shape_detection_dialog : public QDialog, public Ui::PointSetShapeDetectionDialog { Q_OBJECT public: @@ -114,6 +114,7 @@ class Polyhedron_demo_point_set_shape_detection_plugin : QAction* actionDetect; QAction* actionEstimateParameters; + QAction* actionDetectShapesSM; typedef Point_set_3::Point_map PointPMap; typedef Point_set_3::Vector_map NormalPMap; @@ -128,24 +129,35 @@ public: actionDetect->setObjectName("actionDetect"); actionEstimateParameters = new QAction(tr("Point Set Shape Detection (parameter estimation)"), mainWindow); actionEstimateParameters->setObjectName("actionEstimateParameters"); + actionDetectShapesSM = new QAction(tr("Surface Mesh Shape Detection"), mainWindow); + actionDetectShapesSM->setObjectName("actionDetectShapesSM"); autoConnectActions(); } - bool applicable(QAction*) const { + bool applicable(QAction* action) const { + Scene_points_with_normal_item* item = qobject_cast(scene->item(scene->mainSelectionIndex())); - if (item && item->has_normals()) - return true; + Scene_surface_mesh_item* sm_item = + qobject_cast(scene->item(scene->mainSelectionIndex())); + + if (action->objectName() == "actionDetectShapesSM") { + if (sm_item) + return true; + else return false; + } + if (item && item->has_normals()) return true; return false; } QList actions() const { - return QList() << actionDetect << actionEstimateParameters; + return QList() << actionDetect << actionEstimateParameters << actionDetectShapesSM; } public Q_SLOTS: void on_actionDetect_triggered(); void on_actionEstimateParameters_triggered(); + void on_actionDetectShapesSM_triggered(); private: @@ -161,6 +173,83 @@ private: ransac.template add_shape_factory(); } + void detect_shapes_with_region_growing_sm ( + Scene_surface_mesh_item* sm_item, + Point_set_demo_point_set_shape_detection_dialog& dialog) { + + using Face_range = typename SMesh::Face_range; + + using Neighbor_query = + CGAL::Shape_detection::Polygon_mesh::One_ring_neighbor_query; + using Region_type = + CGAL::Shape_detection::Polygon_mesh::Least_squares_plane_fit_region; + using Sorting = + CGAL::Shape_detection::Polygon_mesh::Least_squares_plane_fit_sorting; + + using Vertex_to_point_map = typename Region_type::Vertex_to_point_map; + using Region_growing = CGAL::Shape_detection::Region_growing; + + CGAL::Random rand(time(0)); + const SMesh& mesh = *(sm_item->polyhedron()); + scene->setSelectedItem(-1); + const Face_range face_range = faces(mesh); + + // Set parameters. + const double max_distance_to_plane = + dialog.epsilon(); + const double max_accepted_angle = + (std::acos(dialog.normal_tolerance()) * 180.0) / CGAL_PI; + const std::size_t min_region_size = + dialog.min_points(); + + // Region growing. + Neighbor_query neighbor_query(mesh); + const Vertex_to_point_map vertex_to_point_map(get(CGAL::vertex_point, mesh)); + Region_type region_type( + mesh, + max_distance_to_plane, max_accepted_angle, min_region_size, + vertex_to_point_map); + + Region_growing region_growing( + face_range, neighbor_query, region_type); + + std::vector< std::vector > regions; + region_growing.detect(std::back_inserter(regions)); + + std::cerr << "* " << regions.size() << + " regions have been found" + << std::endl; + + // Output result as a new colored item. + Scene_surface_mesh_item *colored_item = new Scene_surface_mesh_item; + colored_item->setName(QString("%1 (region growing)").arg(sm_item->name())); + SMesh& fg = *(colored_item->polyhedron()); + + fg = mesh; + const Face_range fr = faces(fg); + + colored_item->setItemIsMulticolor(true); + colored_item->computeItemColorVectorAutomatically(false); + auto& color_vector = colored_item->color_vector(); + color_vector.clear(); + + for (std::size_t i = 0; i < regions.size(); ++i) { + for (const std::size_t idx : regions[i]) { + const auto fit = fr.begin() + idx; + fg.property_map("f:patch_id").first[*fit] = + static_cast(i); + } + CGAL::Random rnd(static_cast(i)); + color_vector.push_back(QColor( + 64 + rnd.get_int(0, 192), + 64 + rnd.get_int(0, 192), + 64 + rnd.get_int(0, 192))); + } + + colored_item->invalidateOpenGLBuffers(); + scene->addItem(colored_item); + } + void detect_shapes_with_region_growing ( Scene_points_with_normal_item* item, Point_set_demo_point_set_shape_detection_dialog& dialog) { @@ -813,6 +902,48 @@ private: }; // end Polyhedron_demo_point_set_shape_detection_plugin +void Polyhedron_demo_point_set_shape_detection_plugin::on_actionDetectShapesSM_triggered() { + + const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex(); + + Scene_surface_mesh_item* sm_item = + qobject_cast(scene->item(index)); + + if(sm_item) { + + // Get a surface mesh. + SMesh* mesh = sm_item->polyhedron(); + if(mesh == NULL) return; + + Point_set_demo_point_set_shape_detection_dialog dialog; + + dialog.ransac->setEnabled(false); + dialog.m_regularize->setEnabled(false); + dialog.m_generate_structured->setEnabled(false); + dialog.label_4->setEnabled(false); + dialog.m_cluster_epsilon_field->setEnabled(false); + dialog.groupBox_3->setEnabled(false); + + if(!dialog.exec()) return; + QApplication::setOverrideCursor(Qt::WaitCursor); + if (dialog.region_growing()) { + detect_shapes_with_region_growing_sm(sm_item, dialog); + } + + dialog.ransac->setEnabled(true); + dialog.m_regularize->setEnabled(true); + dialog.m_generate_structured->setEnabled(true); + dialog.label_4->setEnabled(true); + dialog.m_cluster_epsilon_field->setEnabled(true); + dialog.groupBox_3->setEnabled(true); + + // Update scene. + scene->itemChanged(index); + QApplication::restoreOverrideCursor(); + sm_item->setVisible(false); + } +} + void Polyhedron_demo_point_set_shape_detection_plugin::on_actionDetect_triggered() { const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex(); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_shape_detection_plugin.ui b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_shape_detection_plugin.ui index a98d02d7ff7..185d418fffc 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_shape_detection_plugin.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Point_set_shape_detection_plugin.ui @@ -191,7 +191,7 @@ - Minimum Number of Points: + Minimum Number of Items: @@ -317,7 +317,7 @@ - Generate N Point subsets + Generate N point subsets diff --git a/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh.cpp b/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh.cpp index a73c448e723..9b161f1d1b2 100644 --- a/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh.cpp +++ b/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh.cpp @@ -70,8 +70,8 @@ bool test_region_growing_on_polygon_mesh(int argc, char *argv[]) { region_growing.detect(std::back_inserter(regions)); // Test data. - assert(regions.size() >= 328 && regions.size() <= 332); - if (regions.size() < 328 || regions.size() > 332) + assert(regions.size() >= 327 && regions.size() <= 331); + if (regions.size() < 327 || regions.size() > 331) return false; for (const auto& region : regions) @@ -81,8 +81,8 @@ bool test_region_growing_on_polygon_mesh(int argc, char *argv[]) { std::vector unassigned_faces; region_growing.unassigned_items(std::back_inserter(unassigned_faces)); - assert(unassigned_faces.size() >= 869 && unassigned_faces.size() <= 889); - if (unassigned_faces.size() < 869 || unassigned_faces.size() > 889) + assert(unassigned_faces.size() >= 908 && unassigned_faces.size() <= 928); + if (unassigned_faces.size() < 908 || unassigned_faces.size() > 928) return false; return true; diff --git a/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh_with_sorting.cpp b/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh_with_sorting.cpp index 6748576568d..6cfe0900a82 100644 --- a/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh_with_sorting.cpp +++ b/Shape_detection/test/Shape_detection/test_region_growing_on_polygon_mesh_with_sorting.cpp @@ -77,7 +77,7 @@ int main(int argc, char *argv[]) { region_growing.detect(std::back_inserter(regions)); region_growing.release_memory(); - assert(regions.size() >= 323 && regions.size() <= 327); + assert(regions.size() >= 324 && regions.size() <= 328); const bool exact_exact_test_success = (regions.size() >= 323 && regions.size() <= 327); std::cout << "exact_exact_test_success: " << exact_exact_test_success << std::endl;