cgal/Polyhedron/demo/Polyhedron/Scene_surface_mesh_item.cpp

600 lines
21 KiB
C++

#include "Scene_surface_mesh_item.h"
#include <queue>
#include <boost/graph/properties.hpp>
#include <boost/graph/graph_traits.hpp>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <boost/container/flat_map.hpp>
#include <CGAL/boost/graph/properties_Surface_mesh.h>
#include <CGAL/Surface_mesh/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
#include "triangulate_primitive.h"
typedef boost::graph_traits<Scene_surface_mesh_item::SMesh>::face_descriptor face_descriptor;
typedef boost::graph_traits<Scene_surface_mesh_item::SMesh>::halfedge_descriptor halfedge_descriptor;
typedef boost::graph_traits<Scene_surface_mesh_item::SMesh>::vertex_descriptor vertex_descriptor;
struct Scene_surface_mesh_item_priv{
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef CGAL::Surface_mesh<Point> SMesh;
typedef boost::graph_traits<SMesh>::face_descriptor face_descriptor;
Scene_surface_mesh_item_priv(const Scene_surface_mesh_item& other, Scene_surface_mesh_item* parent):
smesh_(new SMesh(*other.d->smesh_)),
idx_data_(other.d->idx_data_),
idx_edge_data_(other.d->idx_edge_data_)
{
item = parent;
}
Scene_surface_mesh_item_priv(SMesh* sm, Scene_surface_mesh_item *parent):
smesh_(sm)
{
item = parent;
}
~Scene_surface_mesh_item_priv()
{
delete smesh_;
}
void initializeBuffers(CGAL::Three::Viewer_interface *) const;
void addFlatData(Point, Kernel::Vector_3, CGAL::Color *) const;
//! \param fd a face_descriptor of the facet that needs to be triangulated.
//! \param fnormals a property_map containing the normals of the mesh.
//! \param p_cdt a reference to an empty CDT that will be filled by this function.
//! \param v2v a reference to an empty flat_map that will be filled by this function.
//!
//!
//! \brief triangulate_facet Triangulates a facet.
//! \param fd a face_descriptor of the facet that needs to be triangulated.
//! \param fnormals a property_map containing the normals of the mesh.
//! \param fcolors a property_map containing the colors of the mesh
//! \param im a property_map containing the indices of the vertices of the mesh
//! \param index if true, the function will fill the index vector. If false, the function will
//! fill the flat data vectors.
void
triangulate_facet(face_descriptor fd,
SMesh::Property_map<face_descriptor, Kernel::Vector_3 > *fnormals,
SMesh::Property_map<face_descriptor, CGAL::Color> *fcolors,
boost::property_map< SMesh, boost::vertex_index_t >::type* im,
bool index) const;
void compute_elements();
void checkFloat() const;
enum VAOs {
Flat_facets = 0,
Smooth_facets,
Edges,
NbOfVaos
};
enum VBOs {
Flat_vertices = 0,
Smooth_vertices,
Flat_normals,
Smooth_normals,
VColors,
FColors,
NbOfVbos
};
mutable bool floated;
mutable bool has_vcolors;
mutable bool has_fcolors;
SMesh* smesh_;
mutable bool is_filled;
mutable bool isinit;
mutable std::vector<unsigned int> idx_data_;
std::vector<unsigned int> idx_edge_data_;
mutable std::vector<cgal_gl_data> smooth_vertices;
mutable std::vector<cgal_gl_data> smooth_normals;
mutable std::vector<cgal_gl_data> flat_vertices;
mutable std::vector<cgal_gl_data> flat_normals;
mutable std::vector<cgal_gl_data> f_colors;
mutable std::vector<cgal_gl_data> v_colors;
mutable QOpenGLShaderProgram *program;
mutable bool are_buffers_filled;
Scene_surface_mesh_item *item;
};
Scene_surface_mesh_item::Scene_surface_mesh_item(const Scene_surface_mesh_item& other)
: CGAL::Three::Scene_item(Scene_surface_mesh_item_priv::NbOfVbos,Scene_surface_mesh_item_priv::NbOfVaos)
{
d = new Scene_surface_mesh_item_priv(other, this);
}
Scene_surface_mesh_item::Scene_surface_mesh_item(SMesh* sm)
: CGAL::Three::Scene_item(Scene_surface_mesh_item_priv::NbOfVbos,Scene_surface_mesh_item_priv::NbOfVaos)
{
d = new Scene_surface_mesh_item_priv(sm, this);
d->floated = false;
d->checkFloat();
SMesh::Property_map<vertex_descriptor, Kernel::Vector_3 > vnormals =
d->smesh_->add_property_map<vertex_descriptor, Kernel::Vector_3 >("v:normal").first;
SMesh::Property_map<face_descriptor, Kernel::Vector_3 > fnormals =
d->smesh_->add_property_map<face_descriptor, Kernel::Vector_3 >("v:normal").first;
CGAL::Polygon_mesh_processing::compute_face_normals(*d->smesh_,fnormals);
typedef boost::graph_traits<SMesh>::face_descriptor face_descriptor;
CGAL::Polygon_mesh_processing::compute_vertex_normals(*d->smesh_,vnormals);
boost::property_map< SMesh, boost::vertex_index_t >::type
im = get(boost::vertex_index, *d->smesh_);
d->idx_data_.reserve(num_faces(*d->smesh_) * 3);
typedef boost::graph_traits<SMesh>::face_descriptor face_descriptor;
typedef boost::graph_traits<SMesh>::halfedge_descriptor halfedge_descriptor;
typedef boost::graph_traits<SMesh>::edge_descriptor edge_descriptor;
BOOST_FOREACH(face_descriptor fd, faces(*d->smesh_))
{
if(is_triangle(halfedge(fd,*d->smesh_),*d->smesh_))
{
BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_face(halfedge(fd, *d->smesh_),*d->smesh_))
{
d->idx_data_.push_back(im[source(hd, *d->smesh_)]);
}
}
else if(is_quad(halfedge(fd,*d->smesh_),*d->smesh_))
{
halfedge_descriptor hd = halfedge(fd,*d->smesh_);
//1st half
d->idx_data_.push_back(im[source(hd, *d->smesh_)]);
d->idx_data_.push_back(im[source(next(hd, *d->smesh_), *d->smesh_)]);
d->idx_data_.push_back(im[source(next(next(hd, *d->smesh_), *d->smesh_), *d->smesh_)]);
//2nd half
d->idx_data_.push_back(im[source(hd, *d->smesh_)]);
d->idx_data_.push_back(im[source(next(next(hd, *d->smesh_), *d->smesh_), *d->smesh_)]);
d->idx_data_.push_back(im[source(prev(hd, *d->smesh_), *d->smesh_)]);
}
else
{
d->triangulate_facet(fd, &fnormals, 0, &im, true);
}
}
d->idx_edge_data_.reserve(num_edges(*d->smesh_) * 2);
BOOST_FOREACH(edge_descriptor ed, edges(*d->smesh_))
{
d->idx_edge_data_.push_back(im[source(ed, *d->smesh_)]);
d->idx_edge_data_.push_back(im[target(ed, *d->smesh_)]);
}
d->has_vcolors = false;
d->has_fcolors = false;
d->compute_elements();
}
Scene_surface_mesh_item*
Scene_surface_mesh_item::clone() const
{ return new Scene_surface_mesh_item(*this); }
void Scene_surface_mesh_item_priv::addFlatData(Point p, Kernel::Vector_3 n, CGAL::Color *c) const
{
flat_vertices.push_back((cgal_gl_data)p.x());
flat_vertices.push_back((cgal_gl_data)p.y());
flat_vertices.push_back((cgal_gl_data)p.z());
flat_normals.push_back((cgal_gl_data)n.x());
flat_normals.push_back((cgal_gl_data)n.y());
flat_normals.push_back((cgal_gl_data)n.z());
if(c != NULL)
{
f_colors.push_back((float)c->red()/255);
f_colors.push_back((float)c->green()/255);
f_colors.push_back((float)c->blue()/255);
}
}
void Scene_surface_mesh_item_priv::compute_elements()
{
SMesh::Property_map<vertex_descriptor, SMesh::Point> positions =
smesh_->points();
SMesh::Property_map<vertex_descriptor, Kernel::Vector_3 > vnormals =
smesh_->property_map<vertex_descriptor, Kernel::Vector_3 >("v:normal").first;
SMesh::Property_map<face_descriptor, Kernel::Vector_3 > fnormals =
smesh_->add_property_map<face_descriptor, Kernel::Vector_3 >("v:normal").first;
SMesh::Property_map<vertex_descriptor, CGAL::Color> vcolors =
smesh_->property_map<vertex_descriptor, CGAL::Color >("v:color").first;
SMesh::Property_map<face_descriptor, CGAL::Color> fcolors =
smesh_->property_map<face_descriptor, CGAL::Color >("f:color").first;
assert(positions.data() != NULL);
assert(vnormals.data() != NULL);
if(smesh_->property_map<vertex_descriptor, CGAL::Color >("v:color").second)
has_vcolors = true;
if(smesh_->property_map<face_descriptor, CGAL::Color >("f:color").second)
has_fcolors = true;
//compute the Flat data
flat_vertices.clear();
flat_normals.clear();
BOOST_FOREACH(face_descriptor fd, faces(*smesh_))
{
if(is_triangle(halfedge(fd,*smesh_),*smesh_))
{
BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_face(halfedge(fd, *smesh_),*smesh_))
{
Point p = positions[source(hd, *smesh_)];
flat_vertices.push_back((cgal_gl_data)p.x());
flat_vertices.push_back((cgal_gl_data)p.y());
flat_vertices.push_back((cgal_gl_data)p.z());
Kernel::Vector_3 n = fnormals[fd];
flat_normals.push_back((cgal_gl_data)n.x());
flat_normals.push_back((cgal_gl_data)n.y());
flat_normals.push_back((cgal_gl_data)n.z());
if(has_fcolors)
{
CGAL::Color c = fcolors[fd];
f_colors.push_back((float)c.red()/255);
f_colors.push_back((float)c.green()/255);
f_colors.push_back((float)c.blue()/255);
}
}
}
else if(is_quad(halfedge(fd, *smesh_), *smesh_))
{
//1st half
halfedge_descriptor hd = halfedge(fd, *smesh_);
Point p = positions[source(hd, *smesh_)];
Kernel::Vector_3 n = fnormals[fd];
CGAL::Color *c;
if(has_fcolors)
c= &fcolors[fd];
else
c = 0;
addFlatData(p,n,c);
hd = halfedge(next(halfedge(fd, *smesh_),*smesh_), *smesh_);
addFlatData(positions[source(hd, *smesh_)]
,fnormals[fd]
,c);
hd = halfedge(next(next(halfedge(fd, *smesh_),*smesh_), *smesh_), *smesh_);
addFlatData(positions[source(hd, *smesh_)]
,fnormals[fd]
,c);
//2nd half
hd = halfedge(fd, *smesh_);
addFlatData(positions[source(hd, *smesh_)]
,fnormals[fd]
,c);
hd = halfedge(next(next(halfedge(fd, *smesh_),*smesh_), *smesh_), *smesh_);
addFlatData(positions[source(hd, *smesh_)]
,fnormals[fd]
,c);
hd = halfedge(prev(halfedge(fd, *smesh_), *smesh_), *smesh_);
addFlatData(positions[source(hd, *smesh_)]
,fnormals[fd]
, c);
}
else
{
triangulate_facet(fd, &fnormals, &fcolors, 0, false);
}
}
if(has_vcolors)
{
BOOST_FOREACH(vertex_descriptor vd, vertices(*smesh_))
{
CGAL::Color c = vcolors[vd];
v_colors.push_back((float)c.red()/255);
v_colors.push_back((float)c.green()/255);
v_colors.push_back((float)c.blue()/255);
}
}
if(floated)
{
BOOST_FOREACH(vertex_descriptor vd, vertices(*smesh_))
{
Point p = positions[vd];
smooth_vertices.push_back((cgal_gl_data)p.x());
smooth_vertices.push_back((cgal_gl_data)p.y());
smooth_vertices.push_back((cgal_gl_data)p.z());
Kernel::Vector_3 n = vnormals[vd];
smooth_normals.push_back((cgal_gl_data)n.x());
smooth_normals.push_back((cgal_gl_data)n.y());
smooth_normals.push_back((cgal_gl_data)n.z());
}
}
}
void Scene_surface_mesh_item_priv::initializeBuffers(CGAL::Three::Viewer_interface* viewer)const
{
SMesh::Property_map<vertex_descriptor, SMesh::Point> positions =
smesh_->points();
SMesh::Property_map<vertex_descriptor, Kernel::Vector_3 > vnormals =
smesh_->property_map<vertex_descriptor, Kernel::Vector_3 >("v:normal").first;
//vao containing the data for the flat facets
program = item->getShaderProgram(Scene_surface_mesh_item::PROGRAM_WITH_LIGHT, viewer);
program->bind();
item->vaos[Scene_surface_mesh_item_priv::Flat_facets]->bind();
item->buffers[Scene_surface_mesh_item_priv::Flat_vertices].bind();
item->buffers[Scene_surface_mesh_item_priv::Flat_vertices].allocate(flat_vertices.data(),
static_cast<int>(flat_vertices.size()*sizeof(cgal_gl_data)));
program->enableAttributeArray("vertex");
program->setAttributeBuffer("vertex",CGAL_GL_DATA,0,3);
item->buffers[Scene_surface_mesh_item_priv::Flat_vertices].release();
item->buffers[Scene_surface_mesh_item_priv::Flat_normals].bind();
item->buffers[Scene_surface_mesh_item_priv::Flat_normals].allocate(flat_normals.data(),
static_cast<int>(flat_normals.size()*sizeof(cgal_gl_data)));
program->enableAttributeArray("normals");
program->setAttributeBuffer("normals",CGAL_GL_DATA,0,3);
item->buffers[Scene_surface_mesh_item_priv::Flat_normals].release();
if(has_fcolors)
{
item->buffers[Scene_surface_mesh_item_priv::FColors].bind();
item->buffers[Scene_surface_mesh_item_priv::FColors].allocate(f_colors.data(),
static_cast<int>(f_colors.size()*sizeof(cgal_gl_data)));
program->enableAttributeArray("colors");
program->setAttributeBuffer("colors",CGAL_GL_DATA,0,3);
item->buffers[Scene_surface_mesh_item_priv::FColors].release();
}
item->vaos[Scene_surface_mesh_item_priv::Flat_facets]->release();
//vao containing the data for the smooth facets
item->vaos[Scene_surface_mesh_item_priv::Smooth_facets]->bind();
item->buffers[Scene_surface_mesh_item_priv::Smooth_vertices].bind();
if(!floated)
item->buffers[Scene_surface_mesh_item_priv::Smooth_vertices].allocate(positions.data(),
static_cast<int>(num_vertices(*smesh_)*3*sizeof(cgal_gl_data)));
else
item->buffers[Scene_surface_mesh_item_priv::Smooth_vertices].allocate(smooth_vertices.data(),
static_cast<int>(num_vertices(*smesh_)*3*sizeof(cgal_gl_data)));
program->enableAttributeArray("vertex");
program->setAttributeBuffer("vertex",CGAL_GL_DATA,0,3);
item->buffers[Scene_surface_mesh_item_priv::Smooth_vertices].release();
item->buffers[Scene_surface_mesh_item_priv::Smooth_normals].bind();
if(!floated)
item->buffers[Scene_surface_mesh_item_priv::Smooth_normals].allocate(vnormals.data(),
static_cast<int>(num_vertices(*smesh_)*3*sizeof(cgal_gl_data)));
else
item->buffers[Scene_surface_mesh_item_priv::Smooth_normals].allocate(smooth_normals.data(),
static_cast<int>(num_vertices(*smesh_)*3*sizeof(cgal_gl_data)));
program->enableAttributeArray("normals");
program->setAttributeBuffer("normals",CGAL_GL_DATA,0,3);
item->buffers[Scene_surface_mesh_item_priv::Smooth_normals].release();
if(has_vcolors)
{
item->buffers[VColors].bind();
item->buffers[VColors].allocate(v_colors.data(),
static_cast<int>(v_colors.size()*sizeof(cgal_gl_data)));
program->enableAttributeArray("colors");
program->setAttributeBuffer("colors",CGAL_GL_DATA,0,3);
item->buffers[VColors].release();
}
item->vaos[Scene_surface_mesh_item_priv::Smooth_facets]->release();
program->release();
//vao for the edges
program = item->getShaderProgram(Scene_surface_mesh_item::PROGRAM_WITHOUT_LIGHT, viewer);
item->vaos[Scene_surface_mesh_item_priv::Edges]->bind();
item->buffers[Scene_surface_mesh_item_priv::Smooth_vertices].bind();
program->enableAttributeArray("vertex");
program->setAttributeBuffer("vertex",CGAL_GL_DATA,0,3);
item->buffers[Scene_surface_mesh_item_priv::Smooth_vertices].release();
program->release();
are_buffers_filled = true;
}
void Scene_surface_mesh_item::draw(CGAL::Three::Viewer_interface *viewer) const
{
glShadeModel(GL_SMOOTH);
if(!d->are_buffers_filled)
d->initializeBuffers(viewer);
attribBuffers(viewer, PROGRAM_WITH_LIGHT);
d->program = getShaderProgram(PROGRAM_WITH_LIGHT, viewer);
d->program->bind();
if(renderingMode() == Gouraud)
{
vaos[Scene_surface_mesh_item_priv::Smooth_facets]->bind();
if(is_selected)
d->program->setAttributeValue("is_selected", true);
else
d->program->setAttributeValue("is_selected", false);
if(!d->has_vcolors)
d->program->setAttributeValue("colors", this->color());
glDrawElements(GL_TRIANGLES, static_cast<GLuint>(d->idx_data_.size()),
GL_UNSIGNED_INT, d->idx_data_.data());
vaos[Scene_surface_mesh_item_priv::Smooth_facets]->release();
}
else
{
vaos[Scene_surface_mesh_item_priv::Flat_facets]->bind();
d->program->setAttributeValue("colors", this->color());
if(is_selected)
d->program->setAttributeValue("is_selected", true);
else
d->program->setAttributeValue("is_selected", false);
if(!d->has_fcolors)
d->program->setAttributeValue("colors", this->color());
glDrawArrays(GL_TRIANGLES,0,static_cast<GLsizei>(d->flat_vertices.size()/3));
vaos[Scene_surface_mesh_item_priv::Flat_facets]->release();
}
d->program->release();
}
void Scene_surface_mesh_item::drawEdges(CGAL::Three::Viewer_interface *viewer) const
{
if(!d->are_buffers_filled)
d->initializeBuffers(viewer);
attribBuffers(viewer, PROGRAM_WITHOUT_LIGHT);
d->program = getShaderProgram(PROGRAM_WITHOUT_LIGHT, viewer);
d->program->bind();
vaos[Scene_surface_mesh_item_priv::Edges]->bind();
d->program->setAttributeValue("colors", QColor(0,0,0));
if(is_selected)
d->program->setAttributeValue("is_selected", true);
else
d->program->setAttributeValue("is_selected", false);
glDrawElements(GL_LINES, static_cast<GLuint>(d->idx_edge_data_.size()),
GL_UNSIGNED_INT, d->idx_edge_data_.data());
vaos[Scene_surface_mesh_item_priv::Edges]->release();
d->program->release();
}
void Scene_surface_mesh_item::drawPoints(CGAL::Three::Viewer_interface *) const
{
}
void
Scene_surface_mesh_item::selection_changed(bool p_is_selected)
{
if(p_is_selected != is_selected)
{
is_selected = p_is_selected;
}
}
bool
Scene_surface_mesh_item::supportsRenderingMode(RenderingMode m) const
{ return (m == FlatPlusEdges || m == Wireframe || m == Flat || m == Gouraud); }
CGAL::Three::Scene_item::Bbox Scene_surface_mesh_item::bbox() const
{
SMesh::Property_map<vertex_descriptor, Point> pprop = d->smesh_->points();
CGAL::Bbox_3 bbox;
BOOST_FOREACH(vertex_descriptor vd,vertices(*d->smesh_))
{
bbox = bbox + pprop[vd].bbox();
}
return Bbox(bbox.xmin(),bbox.ymin(),bbox.zmin(),
bbox.xmax(),bbox.ymax(),bbox.zmax());
}
bool
Scene_surface_mesh_item::isEmpty() const
{
return num_vertices(*d->smesh_)==0;
}
QString Scene_surface_mesh_item::toolTip() const
{
return QObject::tr("<p>Surface_mesh <b>%1</b> (mode: %5, color: %6)</p>"
"<p>Number of vertices: %2<br />"
"Number of edges: %3<br />"
"Number of faces: %4</p>")
.arg(this->name())
.arg(num_vertices(*d->smesh_))
.arg(num_edges(*d->smesh_))
.arg(num_faces(*d->smesh_))
.arg(this->renderingModeName())
.arg(this->color().name());
}
void Scene_surface_mesh_item_priv::checkFloat()const
{
#if CGAL_IS_FLOAT == 1
floated = true;
#endif
}
void
Scene_surface_mesh_item_priv::triangulate_facet(face_descriptor fd,
SMesh::Property_map<face_descriptor, Kernel::Vector_3> *fnormals,
SMesh::Property_map<face_descriptor, CGAL::Color> *fcolors,
boost::property_map< SMesh, boost::vertex_index_t >::type *im,
bool index) const
{
//Computes the normal of the facet
Kernel::Vector_3 normal = get(*fnormals, fd);
//check if normal contains NaN values
if (normal.x() != normal.x() || normal.y() != normal.y() || normal.z() != normal.z())
{
qDebug()<<"Warning : normal is not valid. Facet not displayed";
return;
}
typedef FacetTriangulator<SMesh, Kernel, boost::graph_traits<SMesh>::vertex_descriptor> FT;
double diagonal;
if(item->diagonalBbox() != std::numeric_limits<double>::infinity())
diagonal = item->diagonalBbox();
else
diagonal = 0.0;
FT triangulation(fd,normal,smesh_,diagonal);
//iterates on the internal faces
for(FT::CDT::Finite_faces_iterator
ffit = triangulation.cdt->finite_faces_begin(),
end = triangulation.cdt->finite_faces_end();
ffit != end; ++ffit)
{
if(ffit->info().is_external)
continue;
//add the vertices to the positions
//adds the vertices, normals and colors to the appropriate vectors
if(!index)
{
CGAL::Color* color;
if(has_fcolors)
color = &(*fcolors)[fd];
else
color = 0;
addFlatData(ffit->vertex(0)->point(),
(*fnormals)[fd],
color);
addFlatData(ffit->vertex(1)->point(),
(*fnormals)[fd],
color);
addFlatData(ffit->vertex(2)->point(),
(*fnormals)[fd],
color);
}
//adds the indices to the appropriate vector
else
{
idx_data_.push_back((*im)[triangulation.v2v[ffit->vertex(0)]]);
idx_data_.push_back((*im)[triangulation.v2v[ffit->vertex(1)]]);
idx_data_.push_back((*im)[triangulation.v2v[ffit->vertex(2)]]);
}
}
}
Scene_surface_mesh_item::~Scene_surface_mesh_item()
{
delete d;
}
Scene_surface_mesh_item::SMesh* Scene_surface_mesh_item::polyhedron() { return d->smesh_; }
const Scene_surface_mesh_item::SMesh* Scene_surface_mesh_item::polyhedron() const { return d->smesh_; }