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)
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;
}

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)
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(

View File

@ -11,7 +11,6 @@
#include "Scene_surface_mesh_item.h"
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
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<QAction*> 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<QAction*> Create_bbox_mesh_plugin::actions() const {
QList<QAction*>
Create_bbox_mesh_plugin::
actions() const
{
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;
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;
}

View File

@ -9,6 +9,7 @@
#include <QApplication>
#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<QAction*> 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_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)
Scene_item* item = scene->item(index);
if(!item->isFinite())
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:
void gather_mesh_points(std::vector<Point_3>& points);
void obb();
int dimensionality(const std::vector<Point_3>& 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<QAction*> Create_obb_mesh_plugin::actions() const
QList<QAction*>
Create_obb_mesh_plugin::
actions() const
{
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 =
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)
auto it = std::cbegin(points), end = std::cend(points);
while(it != end)
{
typedef typename boost::property_map<FaceGraph, boost::vertex_point_t>::type PointPMap;
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)
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<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
std::vector<Point_3> 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;
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"