cgal/Polyhedron/demo/Polyhedron/Polyhedron_demo_pca_plugin.cpp

233 lines
7.2 KiB
C++

#include <QApplication>
#include <QAction>
#include <QMainWindow>
#include "Scene_polyhedron_item.h"
#include "Scene_plane_item.h"
#include "Polyhedron_type.h"
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
#include <CGAL/centroid.h>
#include <CGAL/bounding_box.h>
#include <CGAL/linear_least_squares_fitting_3.h>
#include <CGAL/Make_quad_soup.h> // output for plane fitting
#include <CGAL/Make_bar.h> // output for line fitting
#include "Kernel_type.h"
typedef Kernel::Plane_3 Plane;
typedef Kernel::Iso_cuboid_3 Iso_cuboid;
typedef Kernel::Triangle_3 Triangle;
typedef Kernel::Line_3 Line;
typedef Kernel::Vector_3 Vector;
typedef Kernel::Point_3 Point;
typedef Kernel::FT FT;
using namespace CGAL::Three;
class Polyhedron_demo_pca_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:
// used by Polyhedron_demo_plugin_helper
QStringList actionsNames() const {
return QStringList() << "actionFitPlane"
<< "actionFitLine";
}
void init(QMainWindow* mainWindow,
Scene_interface* scene_interface)
{
mw = mainWindow;
scene = scene_interface;
actions_map["actionFitPlane"] = new QAction("Fit Plane", mw);
actions_map["actionFitPlane"]->setProperty("subMenuName", "Principal Component Analysis");
actions_map["actionFitLine"] = new QAction("Fit Line", mw);
actions_map["actionFitLine"]->setProperty("subMenuName", "Principal Component Analysis");
connect(actions_map["actionFitPlane"], SIGNAL(triggered()),
this, SLOT(on_actionFitPlane_triggered()));
connect(actions_map["actionFitLine"], SIGNAL(triggered()),
this, SLOT(on_actionFitLine_triggered()));
}
bool applicable(QAction*) const {
return qobject_cast<Scene_polyhedron_item*>(scene->item(scene->mainSelectionIndex()));
}
public Q_SLOTS:
void on_actionFitPlane_triggered();
void on_actionFitLine_triggered();
}; // end Polyhedron_demo_pca_plugin
void Polyhedron_demo_pca_plugin::on_actionFitPlane_triggered()
{
const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
Scene_polyhedron_item* item =
qobject_cast<Scene_polyhedron_item*>(scene->item(index));
if(item)
{
Polyhedron* pMesh = item->polyhedron();
// get triangles from the mesh
std::list<Triangle> triangles;
Polyhedron::Facet_iterator f;
for(f = pMesh->facets_begin();
f != pMesh->facets_end();
++f)
{
const Point& a = f->halfedge()->vertex()->point();
const Point& b = f->halfedge()->next()->vertex()->point();
const Point& c = f->halfedge()->prev()->vertex()->point();
triangles.push_back(Triangle(a,b,c));
}
// fit plane to triangles
Plane plane;
std::cout << "Fit plane...";
CGAL::linear_least_squares_fitting_3(triangles.begin(),triangles.end(),plane,CGAL::Dimension_tag<2>());
std::cout << "ok" << std::endl;
// compute centroid
Point center_of_mass = CGAL::centroid(triangles.begin(),triangles.end());
// // compute bounding box diagonal
// Iso_cuboid bbox = CGAL::bounding_box(pMesh->points_begin(),pMesh->points_end());
// // compute scale (for rendering) using diagonal of bbox
// Point cmin = (bbox.min)();
// Point cmax = (bbox.max)();
// FT diag = std::sqrt(CGAL::squared_distance(cmin,cmax));
// Vector u1 = plane.base1();
// u1 = u1 / std::sqrt(u1*u1);
// u1 = u1 * 0.7 * diag;
// Vector u2 = plane.base2();
// u2 = u2 / std::sqrt(u2*u2);
// u2 = u2 * 0.7 * diag;
// std::list<Point> points;
// points.push_back(center_of_mass + u1);
// points.push_back(center_of_mass + u2);
// points.push_back(center_of_mass - u1);
// points.push_back(center_of_mass - u2);
// add best fit plane as new polyhedron
// Polyhedron *pFit = new Polyhedron;
// typedef std::list<Point>::iterator Iterator;
// Make_quad_soup<Polyhedron,Kernel,Iterator> quad;
// quad.run(points.begin(),points.end(),*pFit);
// Scene_polyhedron_item* new_item = new Scene_polyhedron_item(pFit);
Scene_plane_item* new_item = new Scene_plane_item(this->scene);
new_item->setPosition(center_of_mass.x(),
center_of_mass.y(),
center_of_mass.z());
const Vector& normal = plane.orthogonal_vector();
new_item->setNormal(normal.x(), normal.y(), normal.z());
new_item->setName(tr("%1 (plane fit)").arg(item->name()));
new_item->setColor(Qt::magenta);
new_item->setRenderingMode(item->renderingMode());
scene->addItem(new_item);
QApplication::restoreOverrideCursor();
}
}
void Polyhedron_demo_pca_plugin::on_actionFitLine_triggered()
{
const CGAL::Three::Scene_interface::Item_id index = scene->mainSelectionIndex();
Scene_polyhedron_item* item =
qobject_cast<Scene_polyhedron_item*>(scene->item(index));
if(item)
{
Polyhedron* pMesh = item->polyhedron();
// get triangles from the mesh
std::list<Triangle> triangles;
Polyhedron::Facet_iterator f;
for(f = pMesh->facets_begin();
f != pMesh->facets_end();
++f)
{
const Point& a = f->halfedge()->vertex()->point();
const Point& b = f->halfedge()->next()->vertex()->point();
const Point& c = f->halfedge()->prev()->vertex()->point();
triangles.push_back(Triangle(a,b,c));
}
// fit line to triangles
Line line;
std::cout << "Fit line...";
CGAL::linear_least_squares_fitting_3(triangles.begin(),triangles.end(),line,CGAL::Dimension_tag<2>());
std::cout << "ok" << std::endl;
// compute centroid
Point center_of_mass = CGAL::centroid(triangles.begin(),triangles.end());
// compute bounding box diagonal
Iso_cuboid bbox = CGAL::bounding_box(pMesh->points_begin(),pMesh->points_end());
// compute scale for rendering using diagonal of bbox
Point cmin = (bbox.min)();
Point cmax = (bbox.max)();
FT diag = std::sqrt(CGAL::squared_distance(cmin,cmax));
// construct a 3D bar
Vector u = line.to_vector();
u = u / std::sqrt(u*u);
Point a = center_of_mass + u * diag;
Point b = center_of_mass - u * diag;
Plane plane_a = line.perpendicular_plane(a);
Vector u1 = plane_a.base1();
u1 = u1 / std::sqrt(u1*u1);
u1 = u1 * 0.01 * diag;
Vector u2 = plane_a.base2();
u2 = u2 / std::sqrt(u2*u2);
u2 = u2 * 0.01 * diag;
Point points[8];
points[0] = a + u1;
points[1] = a + u2;
points[2] = a - u1;
points[3] = a - u2;
points[4] = b + u1;
points[5] = b + u2;
points[6] = b - u1;
points[7] = b - u2;
// add best fit line as new polyhedron bar
Polyhedron *pFit = new Polyhedron;
Make_bar<Polyhedron,Kernel> bar;
bar.run(points,*pFit);
Scene_polyhedron_item* new_item = new Scene_polyhedron_item(pFit);
new_item->setName(tr("%1 (line fit)").arg(item->name()));
new_item->setColor(Qt::magenta);
new_item->setRenderingMode(item->renderingMode());
scene->addItem(new_item);
QApplication::restoreOverrideCursor();
}
}
#include "Polyhedron_demo_pca_plugin.moc"