diff --git a/Optimal_bounding_box/include/CGAL/Optimal_bounding_box/oriented_bounding_box.h b/Optimal_bounding_box/include/CGAL/Optimal_bounding_box/oriented_bounding_box.h index 037df452478..61cabd171f8 100644 --- a/Optimal_bounding_box/include/CGAL/Optimal_bounding_box/oriented_bounding_box.h +++ b/Optimal_bounding_box/include/CGAL/Optimal_bounding_box/oriented_bounding_box.h @@ -361,7 +361,7 @@ void oriented_bounding_box(const PointRange& points, // @todo handle those cases (or call min_rectangle_2 with a projection) if(points.size() <= 3) { - std::cerr << "The oriented bounding box cannot (yet) be computed for a mesh with fewer than 4 vertices!\n"; + std::cerr << "The oriented bounding box cannot be computed with fewer than 4 vertices!\n"; return; } diff --git a/Polyhedron/demo/Polyhedron/Plugins/PCA/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/PCA/CMakeLists.txt index 8ede27ca7ed..7d6d3f383cd 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PCA/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/PCA/CMakeLists.txt @@ -25,9 +25,10 @@ polyhedron_demo_plugin(create_bbox_mesh_plugin Create_bbox_mesh_plugin) target_link_libraries(create_bbox_mesh_plugin PUBLIC scene_surface_mesh_item) polyhedron_demo_plugin(create_obb_mesh_plugin Create_obb_mesh_plugin) -target_link_libraries( - create_obb_mesh_plugin PUBLIC scene_surface_mesh_item scene_selection_item - scene_points_with_normal_item) +target_link_libraries(create_obb_mesh_plugin PUBLIC scene_surface_mesh_item + scene_polygon_soup_item + scene_selection_item + scene_points_with_normal_item) qt5_wrap_ui(volumesUI_FILES Basic_generator_widget.ui) polyhedron_demo_plugin( diff --git a/Polyhedron/demo/Polyhedron/Plugins/PCA/Create_bbox_mesh_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PCA/Create_bbox_mesh_plugin.cpp index 13bf84315e3..1fafba9d82c 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PCA/Create_bbox_mesh_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PCA/Create_bbox_mesh_plugin.cpp @@ -11,7 +11,6 @@ #include "Scene_surface_mesh_item.h" #include - using namespace CGAL::Three; class Create_bbox_mesh_plugin : @@ -24,96 +23,135 @@ class Create_bbox_mesh_plugin : public: void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*); + QList actions() const; - bool applicable(QAction*) const { - if(scene->mainSelectionIndex() != -1 - && scene->item(scene->mainSelectionIndex())->isFinite()) - return true; - return false;} + + bool applicable(QAction*) const + { + bool at_least_one_non_empty = false; + Q_FOREACH(int index, scene->selectionIndices()) + { + Scene_item* item = scene->item(index); + if(!item->isFinite()) + return false; + if(!item->isEmpty()) + at_least_one_non_empty = true; + } + + return at_least_one_non_empty; + } protected: bool bbox(bool extended = false); public Q_SLOTS: - void createBbox() { + void createBbox() + { QApplication::setOverrideCursor(Qt::WaitCursor); - if(!bbox()) - { - QApplication::restoreOverrideCursor(); - QMessageBox::warning(mw, "Error", "Bbox couldn't be computed, so there is no mesh created."); - } - else - QApplication::restoreOverrideCursor(); + const bool res = bbox(); + QApplication::restoreOverrideCursor(); + + if(!res) + QMessageBox::warning(mw, "Error", "Failed to compute the bounding box."); } - void createExtendedBbox() { + + void createExtendedBbox() + { QApplication::setOverrideCursor(Qt::WaitCursor); - if(!bbox(true)) - { - QApplication::restoreOverrideCursor(); - QMessageBox::warning(mw, "Error", "Bbox couldn't be computed, so there is no mesh created."); - } - else - QApplication::restoreOverrideCursor(); + const bool res = bbox(true); + QApplication::restoreOverrideCursor(); + + if(!res) + QMessageBox::warning(mw, "Error", "Failed to compute the extended bounding box"); } private: Scene_interface* scene; QMainWindow* mw; + QAction* actionBbox; QAction* actionExtendedBbox; +}; -}; // end Create_bbox_mesh_plugin - -void Create_bbox_mesh_plugin::init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*) +void +Create_bbox_mesh_plugin:: +init(QMainWindow* mainWindow, + Scene_interface* scene_interface, + Messages_interface*) { scene = scene_interface; mw = mainWindow; - actionBbox = new QAction(tr("Create &Bbox Mesh"), mainWindow); + + actionBbox = new QAction(tr("Create &Bounding Box"), mainWindow); actionBbox->setObjectName("createBboxMeshAction"); connect(actionBbox, SIGNAL(triggered()), this, SLOT(createBbox())); - actionExtendedBbox = new QAction(tr("Create &Extended Bbox Mesh"), mainWindow); + + actionExtendedBbox = new QAction(tr("Create &Extended Bounding Box"), mainWindow); actionExtendedBbox->setObjectName("createExtendedBboxMeshAction"); connect(actionExtendedBbox, SIGNAL(triggered()), this, SLOT(createExtendedBbox())); } -QList Create_bbox_mesh_plugin::actions() const { +QList +Create_bbox_mesh_plugin:: +actions() const +{ return QList() << actionBbox << actionExtendedBbox; } -bool Create_bbox_mesh_plugin::bbox(bool extended) +bool +Create_bbox_mesh_plugin:: +bbox(bool extended) { Scene_interface::Bbox bbox; - bool initialized = false; + int item_count = 0; + QString name; - Q_FOREACH(int index, scene->selectionIndices()) { + Q_FOREACH(int index, scene->selectionIndices()) + { Scene_item* item = scene->item(index); - if(item->isFinite() && ! item->isEmpty()) { - if(initialized) { + if(item->isFinite() && !item->isEmpty()) + { + if(item_count > 0) + { bbox = bbox + item->bbox(); - } else { - bbox = item->bbox(); - initialized = true; + if(item_count == 1) + name = name + " and others"; } + else + { + bbox = item->bbox(); + name = item->name(); + } + ++item_count; } } - std::cerr << "bbox dimensions: " << bbox.xmax() - bbox.xmin() - << "\n " << bbox.ymax() - bbox.ymin() - << "\n " << bbox.zmax() - bbox.zmin() + + if(item_count == 0) + return false; + + std::cout << "bbox: " << bbox.xmin() << " | " << bbox.xmax() + << "\n " << bbox.ymin() << " | " << bbox.ymax() + << "\n " << bbox.zmin() << " | " << bbox.zmax() << std::endl; - if(extended) { + if(extended) + { const double delta_x = ( bbox.xmax() - bbox.xmin() ) / 20.; const double delta_y = ( bbox.ymax() - bbox.ymin() ) / 20.; const double delta_z = ( bbox.zmax() - bbox.zmin() ) / 20.; - bbox = Scene_interface::Bbox( - bbox.xmin() - delta_x, - bbox.ymin() - delta_y, - bbox.zmin() - delta_z, - bbox.xmax() + delta_x, - bbox.ymax() + delta_y, - bbox.zmax() + delta_z); + bbox = Scene_interface::Bbox(bbox.xmin() - delta_x, + bbox.ymin() - delta_y, + bbox.zmin() - delta_z, + bbox.xmax() + delta_x, + bbox.ymax() + delta_y, + bbox.zmax() + delta_z); + + std::cout << "extended bbox: " << bbox.xmin() << " | " << bbox.xmax() + << "\n " << bbox.ymin() << " | " << bbox.ymax() + << "\n " << bbox.zmin() << " | " << bbox.zmax() + << std::endl; } if((bbox.min)(0) > (bbox.max)(0) || @@ -122,15 +160,18 @@ bool Create_bbox_mesh_plugin::bbox(bool extended) { return false; } + Scene_item* item; EPICK::Iso_cuboid_3 ic(bbox); SMesh* p = new SMesh; - CGAL::make_hexahedron(ic[0], ic[1], ic[2], ic[3], ic[4], ic[5], ic[6], ic[7],*p); + CGAL::make_hexahedron(ic[0], ic[1], ic[2], ic[3], ic[4], ic[5], ic[6], ic[7], *p); item = new Scene_surface_mesh_item(p); - item->setName("Scene bbox mesh"); + item->setName(name + (extended ? " (Extended Bbox)" : " (Bbox)")); item->setRenderingMode(Wireframe); + item->setColor(Qt::black); scene->addItem(item); + return true; } diff --git a/Polyhedron/demo/Polyhedron/Plugins/PCA/Create_obb_mesh_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PCA/Create_obb_mesh_plugin.cpp index 59d44164df3..7ca4e060a92 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PCA/Create_obb_mesh_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PCA/Create_obb_mesh_plugin.cpp @@ -9,6 +9,7 @@ #include #include "Scene_surface_mesh_item.h" +#include "Scene_polygon_soup_item.h" #include "Scene_polyhedron_selection_item.h" #include "Scene_points_with_normal_item.h" @@ -20,9 +21,9 @@ using namespace CGAL::Three; typedef Scene_surface_mesh_item Scene_facegraph_item; -class Create_obb_mesh_plugin : - public QObject, - public CGAL::Three::Polyhedron_demo_plugin_interface +class Create_obb_mesh_plugin + : public QObject, + public CGAL::Three::Polyhedron_demo_plugin_interface { Q_OBJECT Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface) @@ -30,32 +31,36 @@ class Create_obb_mesh_plugin : public: void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*); + QList actions() const; bool applicable(QAction*) const { - if(scene->mainSelectionIndex() != -1 - && scene->item(scene->mainSelectionIndex())->isFinite()) + bool at_least_one_non_empty = false; + Q_FOREACH(int index, scene->selectionIndices()) { - const Scene_interface::Item_id index = scene->mainSelectionIndex(); - - Scene_facegraph_item* item = qobject_cast(scene->item(index)); - - Scene_polyhedron_selection_item* selection_item = - qobject_cast(scene->item(index)); - - Scene_points_with_normal_item* point_set_item = - qobject_cast(scene->item(index)); - if(!item && !selection_item && !point_set_item) + Scene_item* item = scene->item(index); + if(!item->isFinite()) return false; - return true; + + Scene_facegraph_item* sm_item = qobject_cast(item); + Scene_polygon_soup_item* ps_item = qobject_cast(item); + Scene_polyhedron_selection_item* selection_item = qobject_cast(item); + Scene_points_with_normal_item* pts_item = qobject_cast(item); + if(!sm_item && !ps_item && !selection_item && !pts_item) + return false; + + if(!item->isEmpty()) + at_least_one_non_empty = true; } - return false; + + return at_least_one_non_empty; } protected: void gather_mesh_points(std::vector& points); - void obb(); + int dimensionality(const std::vector& points); + bool obb(); public Q_SLOTS: void createObb() @@ -69,87 +74,166 @@ private: Scene_interface* scene; QMainWindow* mw; QAction* actionObb; -}; // end Create_obb_mesh_plugin class +}; -void Create_obb_mesh_plugin::init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*) +void +Create_obb_mesh_plugin:: +init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*) { scene = scene_interface; mw = mainWindow; - actionObb = new QAction(tr("Create &Optimal Bbox Mesh"), mainWindow); + actionObb = new QAction(tr("Create &Optimal Bounding Box"), mainWindow); actionObb->setObjectName("createObbMeshAction"); connect(actionObb, SIGNAL(triggered()), this, SLOT(createObb())); } -QList Create_obb_mesh_plugin::actions() const +QList +Create_obb_mesh_plugin:: +actions() const { return QList() << actionObb; } -void Create_obb_mesh_plugin::gather_mesh_points(std::vector& points) +int +Create_obb_mesh_plugin:: +dimensionality(const std::vector& points) { - const Scene_interface::Item_id index = scene->mainSelectionIndex(); + if(points.empty()) + return -1; - Scene_facegraph_item* item = qobject_cast(scene->item(index)); + int d = 0; + Point_3 p0 = points[0], p1, p2; - Scene_polyhedron_selection_item* selection_item = - qobject_cast(scene->item(index)); - - Scene_points_with_normal_item* point_set_item = - qobject_cast(scene->item(index)); - - if(item || selection_item) + auto it = std::cbegin(points), end = std::cend(points); + while(it != end) { - typedef typename boost::property_map::type PointPMap; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - - std::vector selected_vertices; - - if(item != nullptr) + if(p0 != *it) { - FaceGraph& pmesh = *item->polyhedron(); - selected_vertices.assign(vertices(pmesh).begin(), vertices(pmesh).end()); - PointPMap pmap = get(CGAL::vertex_point, pmesh); - for(vertex_descriptor v : selected_vertices) - points.push_back(get(pmap, v)); - + p1 = *it; + d = 1; + break; } - else if(selection_item != nullptr) // using selection of faces - { - FaceGraph& pmesh = *selection_item->polyhedron(); - for(face_descriptor f : selection_item->selected_facets) - { - for(vertex_descriptor v : vertices_around_face(halfedge(f, pmesh), pmesh)) - selected_vertices.push_back(v); - } - - PointPMap pmap = get(CGAL::vertex_point, pmesh); - for(vertex_descriptor v : selected_vertices) - points.push_back(get(pmap, v)); - } - - CGAL_assertion(points.size() >= 3); + ++it; } - if(point_set_item) + while(it != end) { - Point_set* points_set = point_set_item->point_set(); - if(points_set == nullptr) - return; + if(!collinear(p0, p1, *it)) + { + p2 = *it; + d = 2; + break; + } + ++it; + } - std::cout << "points_set->size()= " << points_set->size() << std::endl; - for(const Point_3& p : points_set->points()) - points.push_back(p); + while(it != end) + { + if(!coplanar(p0, p1, p2, *it)) + { + d = 3; + break; + } + ++it; + } + + return d; +} + +void +Create_obb_mesh_plugin:: +gather_mesh_points(std::vector& points) +{ + Q_FOREACH(int index, scene->selectionIndices()) + { + Scene_item* item = scene->item(index); + + // Surface Mesh + Scene_facegraph_item* sm_item = qobject_cast(item); + if(sm_item) + { + FaceGraph* sm_ptr = sm_item->polyhedron(); + if(sm_ptr == nullptr) + continue; + + for(auto v : vertices(*sm_ptr)) + points.push_back(get(CGAL::vertex_point, *sm_ptr, v)); + + continue; + } + + // Polygon soup + Scene_polygon_soup_item* ps_item = qobject_cast(item); + if(ps_item) + { + for(const Point_3& p : ps_item->points()) + points.push_back(p); + + continue; + } + + // Selection + Scene_polyhedron_selection_item* selection_item = qobject_cast(item); + if(selection_item != nullptr) + { + FaceGraph* sm_ptr = selection_item->polyhedron(); + if(sm_ptr == nullptr) + continue; + + auto vpm = get(CGAL::vertex_point, *sm_ptr); + + for(auto f : selection_item->selected_facets) + { + // @todo avoid duplication + for(auto v : vertices_around_face(halfedge(f, *sm_ptr), *sm_ptr)) + points.push_back(get(vpm, v)); + } + + for(auto e : selection_item->selected_edges) + { + points.push_back(get(vpm, source(e, *sm_ptr))); + points.push_back(get(vpm, target(e, *sm_ptr))); + } + + for(auto v : selection_item->selected_vertices) + points.push_back(get(vpm, v)); + + continue; + } + + // Point set + Scene_points_with_normal_item* pts_item = qobject_cast(item); + if(pts_item) + { + Point_set* pts_ptr = pts_item->point_set(); + if(pts_ptr == nullptr) + return; + + for(const Point_3& p : pts_ptr->points()) + points.push_back(p); + + continue; + } } } -void Create_obb_mesh_plugin::obb() +bool +Create_obb_mesh_plugin:: +obb() { // gather point coordinates std::vector points; gather_mesh_points(points); - // find obb + const int d = dimensionality(points); + if(d != 3) + { + std::cerr << "Dimensionality of the point set is: " << d << std::endl; + QMessageBox::warning(mw, "Error", "At least 4 non-coplanar points are required to compute an OBB."); + return false; + } + + // compute the OBB std::array obb_points; CGAL::oriented_bounding_box(points, obb_points); @@ -157,11 +241,36 @@ void Create_obb_mesh_plugin::obb() SMesh* p = new SMesh; CGAL::make_hexahedron(obb_points[0], obb_points[1], obb_points[2], obb_points[3], obb_points[4], obb_points[5], obb_points[6], obb_points[7], *p); - item = new Scene_facegraph_item(p); - item->setName("Optimal bbox mesh"); + std::cout << "Optimal bounding box: " << obb_points[0] + << "\n " << obb_points[7] + << std::endl; + + QString name; + Q_FOREACH(int index, scene->selectionIndices()) + { + Scene_item* item = scene->item(index); + if(!item->isEmpty()) + { + if(name.size() > 0) + { + name = name + " and others"; + break; + } + else + { + name = item->name(); + } + } + } + + item = new Scene_facegraph_item(p); + item->setName(name + " (OBB)"); item->setRenderingMode(Wireframe); + item->setColor(Qt::black); scene->addItem(item); + + return true; } #include "Create_obb_mesh_plugin.moc"