Merge pull request #7494 from MaelRL/Polyhedron_demo-Bbox-GF

AABB / OBB plugins improvements
This commit is contained in:
Laurent Rineau 2023-06-07 17:34:05 +02:00
commit 0f57af63a4
4 changed files with 275 additions and 124 deletions

View File

@ -361,7 +361,7 @@ void oriented_bounding_box(const PointRange& points,
// @todo handle those cases (or call min_rectangle_2 with a projection) // @todo handle those cases (or call min_rectangle_2 with a projection)
if(points.size() <= 3) 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; return;
} }

View File

@ -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) target_link_libraries(create_bbox_mesh_plugin PUBLIC scene_surface_mesh_item)
polyhedron_demo_plugin(create_obb_mesh_plugin Create_obb_mesh_plugin) polyhedron_demo_plugin(create_obb_mesh_plugin Create_obb_mesh_plugin)
target_link_libraries( target_link_libraries(create_obb_mesh_plugin PUBLIC scene_surface_mesh_item
create_obb_mesh_plugin PUBLIC scene_surface_mesh_item scene_selection_item scene_polygon_soup_item
scene_points_with_normal_item) scene_selection_item
scene_points_with_normal_item)
qt5_wrap_ui(volumesUI_FILES Basic_generator_widget.ui) qt5_wrap_ui(volumesUI_FILES Basic_generator_widget.ui)
polyhedron_demo_plugin( polyhedron_demo_plugin(

View File

@ -11,7 +11,6 @@
#include "Scene_surface_mesh_item.h" #include "Scene_surface_mesh_item.h"
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h> #include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
using namespace CGAL::Three; using namespace CGAL::Three;
class Create_bbox_mesh_plugin : class Create_bbox_mesh_plugin :
@ -24,96 +23,135 @@ class Create_bbox_mesh_plugin :
public: public:
void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*); void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*);
QList<QAction*> actions() const; QList<QAction*> actions() const;
bool applicable(QAction*) const {
if(scene->mainSelectionIndex() != -1 bool applicable(QAction*) const
&& scene->item(scene->mainSelectionIndex())->isFinite()) {
return true; bool at_least_one_non_empty = false;
return 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: protected:
bool bbox(bool extended = false); bool bbox(bool extended = false);
public Q_SLOTS: public Q_SLOTS:
void createBbox() { void createBbox()
{
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::WaitCursor);
if(!bbox()) const bool res = bbox();
{ QApplication::restoreOverrideCursor();
QApplication::restoreOverrideCursor();
QMessageBox::warning(mw, "Error", "Bbox couldn't be computed, so there is no mesh created."); if(!res)
} QMessageBox::warning(mw, "Error", "Failed to compute the bounding box.");
else
QApplication::restoreOverrideCursor();
} }
void createExtendedBbox() {
void createExtendedBbox()
{
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::WaitCursor);
if(!bbox(true)) const bool res = bbox(true);
{ QApplication::restoreOverrideCursor();
QApplication::restoreOverrideCursor();
QMessageBox::warning(mw, "Error", "Bbox couldn't be computed, so there is no mesh created."); if(!res)
} QMessageBox::warning(mw, "Error", "Failed to compute the extended bounding box");
else
QApplication::restoreOverrideCursor();
} }
private: private:
Scene_interface* scene; Scene_interface* scene;
QMainWindow* mw; QMainWindow* mw;
QAction* actionBbox; QAction* actionBbox;
QAction* actionExtendedBbox; QAction* actionExtendedBbox;
};
}; // end Create_bbox_mesh_plugin void
Create_bbox_mesh_plugin::
void Create_bbox_mesh_plugin::init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*) init(QMainWindow* mainWindow,
Scene_interface* scene_interface,
Messages_interface*)
{ {
scene = scene_interface; scene = scene_interface;
mw = mainWindow; mw = mainWindow;
actionBbox = new QAction(tr("Create &Bbox Mesh"), mainWindow);
actionBbox = new QAction(tr("Create &Bounding Box"), mainWindow);
actionBbox->setObjectName("createBboxMeshAction"); actionBbox->setObjectName("createBboxMeshAction");
connect(actionBbox, SIGNAL(triggered()), connect(actionBbox, SIGNAL(triggered()),
this, SLOT(createBbox())); this, SLOT(createBbox()));
actionExtendedBbox = new QAction(tr("Create &Extended Bbox Mesh"), mainWindow);
actionExtendedBbox = new QAction(tr("Create &Extended Bounding Box"), mainWindow);
actionExtendedBbox->setObjectName("createExtendedBboxMeshAction"); actionExtendedBbox->setObjectName("createExtendedBboxMeshAction");
connect(actionExtendedBbox, SIGNAL(triggered()), connect(actionExtendedBbox, SIGNAL(triggered()),
this, SLOT(createExtendedBbox())); this, SLOT(createExtendedBbox()));
} }
QList<QAction*> Create_bbox_mesh_plugin::actions() const { QList<QAction*>
Create_bbox_mesh_plugin::
actions() const
{
return QList<QAction*>() << actionBbox << actionExtendedBbox; return QList<QAction*>() << actionBbox << actionExtendedBbox;
} }
bool Create_bbox_mesh_plugin::bbox(bool extended) bool
Create_bbox_mesh_plugin::
bbox(bool extended)
{ {
Scene_interface::Bbox bbox; 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); Scene_item* item = scene->item(index);
if(item->isFinite() && ! item->isEmpty()) { if(item->isFinite() && !item->isEmpty())
if(initialized) { {
if(item_count > 0)
{
bbox = bbox + item->bbox(); bbox = bbox + item->bbox();
} else { if(item_count == 1)
bbox = item->bbox(); name = name + " and others";
initialized = true;
} }
else
{
bbox = item->bbox();
name = item->name();
}
++item_count;
} }
} }
std::cerr << "bbox dimensions: " << bbox.xmax() - bbox.xmin()
<< "\n " << bbox.ymax() - bbox.ymin() if(item_count == 0)
<< "\n " << bbox.zmax() - bbox.zmin() return false;
std::cout << "bbox: " << bbox.xmin() << " | " << bbox.xmax()
<< "\n " << bbox.ymin() << " | " << bbox.ymax()
<< "\n " << bbox.zmin() << " | " << bbox.zmax()
<< std::endl; << std::endl;
if(extended) { if(extended)
{
const double delta_x = ( bbox.xmax() - bbox.xmin() ) / 20.; const double delta_x = ( bbox.xmax() - bbox.xmin() ) / 20.;
const double delta_y = ( bbox.ymax() - bbox.ymin() ) / 20.; const double delta_y = ( bbox.ymax() - bbox.ymin() ) / 20.;
const double delta_z = ( bbox.zmax() - bbox.zmin() ) / 20.; const double delta_z = ( bbox.zmax() - bbox.zmin() ) / 20.;
bbox = Scene_interface::Bbox( bbox = Scene_interface::Bbox(bbox.xmin() - delta_x,
bbox.xmin() - delta_x, bbox.ymin() - delta_y,
bbox.ymin() - delta_y, bbox.zmin() - delta_z,
bbox.zmin() - delta_z, bbox.xmax() + delta_x,
bbox.xmax() + delta_x, bbox.ymax() + delta_y,
bbox.ymax() + delta_y, bbox.zmax() + delta_z);
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) || if((bbox.min)(0) > (bbox.max)(0) ||
@ -122,15 +160,18 @@ bool Create_bbox_mesh_plugin::bbox(bool extended)
{ {
return false; return false;
} }
Scene_item* item; Scene_item* item;
EPICK::Iso_cuboid_3 ic(bbox); EPICK::Iso_cuboid_3 ic(bbox);
SMesh* p = new SMesh; 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 = new Scene_surface_mesh_item(p);
item->setName("Scene bbox mesh"); item->setName(name + (extended ? " (Extended Bbox)" : " (Bbox)"));
item->setRenderingMode(Wireframe); item->setRenderingMode(Wireframe);
item->setColor(Qt::black);
scene->addItem(item); scene->addItem(item);
return true; return true;
} }

View File

@ -9,6 +9,7 @@
#include <QApplication> #include <QApplication>
#include "Scene_surface_mesh_item.h" #include "Scene_surface_mesh_item.h"
#include "Scene_polygon_soup_item.h"
#include "Scene_polyhedron_selection_item.h" #include "Scene_polyhedron_selection_item.h"
#include "Scene_points_with_normal_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; typedef Scene_surface_mesh_item Scene_facegraph_item;
class Create_obb_mesh_plugin : class Create_obb_mesh_plugin
public QObject, : public QObject,
public CGAL::Three::Polyhedron_demo_plugin_interface public CGAL::Three::Polyhedron_demo_plugin_interface
{ {
Q_OBJECT Q_OBJECT
Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface) Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
@ -30,32 +31,36 @@ class Create_obb_mesh_plugin :
public: public:
void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*); void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*);
QList<QAction*> actions() const; QList<QAction*> actions() const;
bool applicable(QAction*) const bool applicable(QAction*) const
{ {
if(scene->mainSelectionIndex() != -1 bool at_least_one_non_empty = false;
&& scene->item(scene->mainSelectionIndex())->isFinite()) Q_FOREACH(int index, scene->selectionIndices())
{ {
const Scene_interface::Item_id index = scene->mainSelectionIndex(); Scene_item* item = scene->item(index);
if(!item->isFinite())
Scene_facegraph_item* item = qobject_cast<Scene_facegraph_item*>(scene->item(index));
Scene_polyhedron_selection_item* selection_item =
qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index));
Scene_points_with_normal_item* point_set_item =
qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
if(!item && !selection_item && !point_set_item)
return false; return false;
return true;
Scene_facegraph_item* sm_item = qobject_cast<Scene_facegraph_item*>(item);
Scene_polygon_soup_item* ps_item = qobject_cast<Scene_polygon_soup_item*>(item);
Scene_polyhedron_selection_item* selection_item = qobject_cast<Scene_polyhedron_selection_item*>(item);
Scene_points_with_normal_item* pts_item = qobject_cast<Scene_points_with_normal_item*>(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: protected:
void gather_mesh_points(std::vector<Point_3>& points); void gather_mesh_points(std::vector<Point_3>& points);
void obb(); int dimensionality(const std::vector<Point_3>& points);
bool obb();
public Q_SLOTS: public Q_SLOTS:
void createObb() void createObb()
@ -69,87 +74,166 @@ private:
Scene_interface* scene; Scene_interface* scene;
QMainWindow* mw; QMainWindow* mw;
QAction* actionObb; 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; scene = scene_interface;
mw = mainWindow; mw = mainWindow;
actionObb = new QAction(tr("Create &Optimal Bbox Mesh"), mainWindow); actionObb = new QAction(tr("Create &Optimal Bounding Box"), mainWindow);
actionObb->setObjectName("createObbMeshAction"); actionObb->setObjectName("createObbMeshAction");
connect(actionObb, SIGNAL(triggered()), this, SLOT(createObb())); connect(actionObb, SIGNAL(triggered()), this, SLOT(createObb()));
} }
QList<QAction*> Create_obb_mesh_plugin::actions() const QList<QAction*>
Create_obb_mesh_plugin::
actions() const
{ {
return QList<QAction*>() << actionObb; return QList<QAction*>() << actionObb;
} }
void Create_obb_mesh_plugin::gather_mesh_points(std::vector<Point_3>& points) int
Create_obb_mesh_plugin::
dimensionality(const std::vector<Point_3>& points)
{ {
const Scene_interface::Item_id index = scene->mainSelectionIndex(); if(points.empty())
return -1;
Scene_facegraph_item* item = qobject_cast<Scene_facegraph_item*>(scene->item(index)); int d = 0;
Point_3 p0 = points[0], p1, p2;
Scene_polyhedron_selection_item* selection_item = auto it = std::cbegin(points), end = std::cend(points);
qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index)); while(it != end)
Scene_points_with_normal_item* point_set_item =
qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
if(item || selection_item)
{ {
typedef typename boost::property_map<FaceGraph, boost::vertex_point_t>::type PointPMap; if(p0 != *it)
typedef typename boost::graph_traits<FaceGraph>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<FaceGraph>::face_descriptor face_descriptor;
std::vector<vertex_descriptor> selected_vertices;
if(item != nullptr)
{ {
FaceGraph& pmesh = *item->polyhedron(); p1 = *it;
selected_vertices.assign(vertices(pmesh).begin(), vertices(pmesh).end()); d = 1;
PointPMap pmap = get(CGAL::vertex_point, pmesh); break;
for(vertex_descriptor v : selected_vertices)
points.push_back(get(pmap, v));
} }
else if(selection_item != nullptr) // using selection of faces ++it;
{
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);
} }
if(point_set_item) while(it != end)
{ {
Point_set* points_set = point_set_item->point_set(); if(!collinear(p0, p1, *it))
if(points_set == nullptr) {
return; p2 = *it;
d = 2;
break;
}
++it;
}
std::cout << "points_set->size()= " << points_set->size() << std::endl; while(it != end)
for(const Point_3& p : points_set->points()) {
points.push_back(p); if(!coplanar(p0, p1, p2, *it))
{
d = 3;
break;
}
++it;
}
return d;
}
void
Create_obb_mesh_plugin::
gather_mesh_points(std::vector<Point_3>& points)
{
Q_FOREACH(int index, scene->selectionIndices())
{
Scene_item* item = scene->item(index);
// Surface Mesh
Scene_facegraph_item* sm_item = qobject_cast<Scene_facegraph_item*>(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<Scene_polygon_soup_item*>(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<Scene_polyhedron_selection_item*>(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<Scene_points_with_normal_item*>(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 // gather point coordinates
std::vector<Point_3> points; std::vector<Point_3> points;
gather_mesh_points(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<Point_3, 8> obb_points; std::array<Point_3, 8> obb_points;
CGAL::oriented_bounding_box(points, obb_points); CGAL::oriented_bounding_box(points, obb_points);
@ -157,11 +241,36 @@ void Create_obb_mesh_plugin::obb()
SMesh* p = new SMesh; SMesh* p = new SMesh;
CGAL::make_hexahedron(obb_points[0], obb_points[1], obb_points[2], obb_points[3], 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); 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->setRenderingMode(Wireframe);
item->setColor(Qt::black);
scene->addItem(item); scene->addItem(item);
return true;
} }
#include "Create_obb_mesh_plugin.moc" #include "Create_obb_mesh_plugin.moc"