cgal/Polyhedron/demo/Polyhedron/Scene_polygon_soup_item.cpp

825 lines
23 KiB
C++

#include <vector>
#include <queue>
#include "Scene_polygon_soup_item.h"
#include "Scene_polyhedron_item.h"
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/Polyhedron_incremental_builder_3.h>
#include <QObject>
#include <QtDebug>
#include <set>
#include <stack>
#include <algorithm>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/IO/OFF_reader.h>
#include <CGAL/IO/File_writer_OFF.h>
#include <CGAL/version.h>
#include <CGAL/orient_polygon_soup.h>
#include <CGAL/polygon_soup_to_polyhedron_3.h>
#include <CGAL/orient_polyhedron_3.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
#include <CGAL/Triangulation_face_base_with_info_2.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Constrained_triangulation_plus_2.h>
#include <CGAL/Triangulation_2_filtered_projection_traits_3.h>
#include <CGAL/internal/Operations_on_polyhedra/compute_normal.h>
struct light_info
{
//position
GLfloat position[4];
//ambient
GLfloat ambient[4];
//diffuse
GLfloat diffuse[4];
//specular
GLfloat specular[4];
GLfloat spec_power;
};
struct Polyhedron_to_polygon_soup_writer {
typedef Kernel::Point_3 Point_3;
Polygon_soup* soup;
Polygon_soup::Polygon_3 polygon;
Polyhedron_to_polygon_soup_writer(Polygon_soup* soup) : soup(soup), polygon() {
}
void write_header( std::ostream&,
std::size_t /* vertices */,
std::size_t /* halfedges */,
std::size_t /* facets */,
bool /* normals */ = false ) {
soup->clear();
}
void write_footer() {
}
void write_vertex( const double& x, const double& y, const double& z) {
soup->points.push_back(Point_3(x, y, z));
}
void write_normal( const double& /* x */, const double& /* y */, const double& /* z */) {
}
void write_facet_header() {
}
void write_facet_begin( std::size_t no) {
polygon.clear();
polygon.reserve(no);
}
void write_facet_vertex_index( std::size_t index) {
polygon.push_back(index);
}
void write_facet_end() {
soup->polygons.push_back(polygon);
polygon.clear();
}
}; // end struct Polyhedron_to_soup_writer
void
Scene_polygon_soup_item::initialize_buffers()
{
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, buffer[0]);
glBufferData(GL_ARRAY_BUFFER,
(positions_poly.size())*sizeof(float),
positions_poly.data(),
GL_STATIC_DRAW);
glVertexAttribPointer(0, //number of the buffer
4, //number of floats to be taken
GL_FLOAT, // type of data
GL_FALSE, //not normalized
0, //compact data (not in a struct)
NULL //no offset (seperated in several buffers)
);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, buffer[1]);
glBufferData(GL_ARRAY_BUFFER,
(positions_lines.size())*sizeof(float),
positions_lines.data(),
GL_STATIC_DRAW);
glVertexAttribPointer(1, //number of the buffer
4, //number of floats to be taken
GL_FLOAT, // type of data
GL_FALSE, //not normalized
0, //compact data (not in a struct)
NULL //no offset (seperated in several buffers)
);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, buffer[2]);
glBufferData(GL_ARRAY_BUFFER,
(normals.size())*sizeof(float),
normals.data(), GL_STATIC_DRAW);
glVertexAttribPointer(2,
3,
GL_FLOAT,
GL_FALSE,
0,
NULL
);
glEnableVertexAttribArray(2);
// Clean-up
glBindVertexArray(0);
}
void
Scene_polygon_soup_item::compile_shaders(void)
{
//fill the vertex shader
static const GLchar* vertex_shader_source[] =
{
"#version 300 es \n"
" \n"
"layout (location = 0) in vec4 positions_poly; \n"
"layout (location = 2) in vec3 vNormals; \n"
"uniform mat4 mvp_matrix; \n"
"uniform mat4 mv_matrix; \n"
"uniform int is_two_side; \n"
"uniform vec3 light_pos; \n"
"uniform vec3 light_diff; \n"
"uniform vec3 light_spec; \n"
"uniform vec3 light_amb; \n"
"float spec_power = 128.0; \n"
"out highp vec3 fColors; \n"
" \n"
"void main(void) \n"
"{ \n"
"vec4 P = mv_matrix * positions_poly; \n"
"vec3 N = mat3(mv_matrix)* vNormals; \n"
"vec3 L = light_pos - P.xyz; \n"
"vec3 V = -P.xyz; \n"
"N=normalize(N); \n"
"L = normalize(L); \n"
"V = normalize(V); \n"
"vec3 R = reflect(-L, N); \n"
" vec3 diffuse; \n"
"if(is_two_side == 1) \n"
" diffuse = abs(dot(N,L)) * light_diff; \n"
"else \n"
" diffuse = max(dot(N,L), 0.0) * light_diff; \n"
"vec3 specular = pow(max(dot(R,V), 0.0), spec_power) * light_spec; \n"
"fColors = light_amb + diffuse + specular ; \n"
"gl_Position = mvp_matrix * positions_poly; \n"
"} \n"
};
//fill the fragment shader
static const GLchar* fragment_shader_source[]=
{
"#version 300 es \n"
" \n"
"in highp vec3 fColors; \n"
"out highp vec3 color; \n"
" \n"
"void main(void) \n"
"{ \n"
"/* Lighting gestion */ \n"
" color = fColors; \n"
"} \n"
};
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
glCompileShader(vertex_shader);
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
glCompileShader(fragment_shader);
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glDeleteShader(vertex_shader);
rendering_program_poly = program;
//For the edges
static const GLchar* vertex_shader_source_lines[] =
{
"#version 300 es \n"
" \n"
"layout (location = 1) in vec4 positions_lines; \n"
"uniform mat4 mvp_matrix; \n"
"uniform vec4 color; \n"
"out highp vec3 fColors; \n"
" \n"
"void main(void) \n"
"{ \n"
" fColors = vec3(color); \n"
" gl_Position = mvp_matrix * positions_lines; \n"
"} \n"
};
vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, vertex_shader_source_lines, NULL);
glCompileShader(vertex_shader);
glDeleteShader(fragment_shader);
glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
glCompileShader(fragment_shader);
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
//Clean-up
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
rendering_program_lines = program;
}
void
Scene_polygon_soup_item::uniform_attrib(Viewer_interface* viewer, int mode) const
{
GLfloat colors[4];
light_info light;
GLint is_both_sides = 0;
GLfloat mvp_mat[16];
GLfloat mv_mat[16];
//fills the MVP and MV matrices.
GLdouble d_mat[16];
viewer->camera()->getModelViewProjectionMatrix(d_mat);
//Convert the GLdoubles matrices in GLfloats
for (int i=0; i<16; ++i)
mvp_mat[i] = GLfloat(d_mat[i]);
viewer->camera()->getModelViewMatrix(d_mat);
for (int i=0; i<16; ++i)
mv_mat[i] = GLfloat(d_mat[i]);
glGetIntegerv(GL_LIGHT_MODEL_TWO_SIDE, &is_both_sides);
//fills the arraw of colors with the current color
glGetFloatv(GL_CURRENT_COLOR, colors);
//Gets lighting info :
//position
glGetLightfv(GL_LIGHT0, GL_POSITION, light.position);
//ambient
glGetLightfv(GL_LIGHT0, GL_AMBIENT, light.ambient);
light.ambient[0]*=colors[0];
light.ambient[1]*=colors[1];
light.ambient[2]*=colors[2];
//specular
glGetLightfv(GL_LIGHT0, GL_SPECULAR, light.specular);
//diffuse
glGetLightfv(GL_LIGHT0, GL_DIFFUSE, light.diffuse);
light.diffuse[0]*=colors[0];
light.diffuse[1]*=colors[1];
light.diffuse[2]*=colors[2];
//For the Flat mode
if(mode ==0)
{
glUseProgram(rendering_program_poly);
glUniformMatrix4fv(location[0], 1, GL_FALSE, mvp_mat);
glUniformMatrix4fv(location[1], 1, GL_FALSE, mv_mat);
glUniform3fv(location[2], 1, light.position);
glUniform3fv(location[3], 1, light.diffuse);
glUniform3fv(location[4], 1, light.specular);
glUniform3fv(location[5], 1, light.ambient);
glUniform1i(location[6], is_both_sides);
}
//For the Wire mode
else if(mode ==1)
{
glUseProgram(rendering_program_lines);
glUniformMatrix4fv(location[7], 1, GL_FALSE, mvp_mat);
glUniform4fv(location[8],1,colors);
}
}
typedef typename Polyhedron::Traits Traits;
typedef typename Polygon_soup::Polygon_3 Facet;
typedef CGAL::Triangulation_2_filtered_projection_traits_3<Traits> P_traits;
typedef typename Polyhedron::Halfedge_handle Halfedge_handle;
struct Face_info {
typename Polyhedron::Halfedge_handle e[3];
bool is_external;
};
typedef CGAL::Triangulation_vertex_base_with_info_2<Halfedge_handle,
P_traits> Vb;
typedef CGAL::Triangulation_face_base_with_info_2<Face_info,
P_traits> Fb1;
typedef CGAL::Constrained_triangulation_face_base_2<P_traits, Fb1> Fb;
typedef CGAL::Triangulation_data_structure_2<Vb,Fb> TDS;
typedef CGAL::No_intersection_tag Itag;
typedef CGAL::Constrained_Delaunay_triangulation_2<P_traits,
TDS,
Itag> CDTbase;
typedef CGAL::Constrained_triangulation_plus_2<CDTbase> CDT;
void
Scene_polygon_soup_item::triangulate_polygon(Polygons_iterator pit)
{
//Computes the normal of the facet
const Point_3& pa = soup->points[pit->at(0)];
const Point_3& pb = soup->points[pit->at(1)];
const Point_3& pc = soup->points[pit->at(2)];
typename Traits::Vector_3 normal = CGAL::cross_product(pb-pa, pc -pa);
normal = normal / std::sqrt(normal * normal);
P_traits cdt_traits(normal);
CDT cdt(cdt_traits);
int it = 0;
int it_end =pit->size();
// Iterates the vector of facet handles
typename CDT::Vertex_handle previous, first;
do {
typename CDT::Vertex_handle vh = cdt.insert(soup->points[pit->at(it)]);
if(first == 0) {
first = vh;
}
if(previous != 0 && previous != vh) {
cdt.insert_constraint(previous, vh);
}
previous = vh;
} while( ++it != it_end );
cdt.insert_constraint(previous, first);
// sets mark is_external
for(typename CDT::All_faces_iterator
pit = cdt.all_faces_begin(),
end = cdt.all_faces_end();
pit != end; ++pit)
{
pit->info().is_external = false;
}
//check if the facet is external or internal
std::queue<typename CDT::Face_handle> face_queue;
face_queue.push(cdt.infinite_vertex()->face());
while(! face_queue.empty() ) {
typename CDT::Face_handle fh = face_queue.front();
face_queue.pop();
if(fh->info().is_external) continue;
fh->info().is_external = true;
for(int i = 0; i <3; ++i) {
if(!cdt.is_constrained(std::make_pair(fh, i)))
{
face_queue.push(fh->neighbor(i));
}
}
}
//iterates on the internal faces to add the vertices to the positions
//and the normals to the appropriate vectors
int count =0;
for(typename CDT::Finite_faces_iterator
ffit = cdt.finite_faces_begin(),
end = cdt.finite_faces_end();
ffit != end; ++ffit)
{
count ++;
if(ffit->info().is_external)
continue;
positions_poly.push_back(ffit->vertex(0)->point().x());
positions_poly.push_back(ffit->vertex(0)->point().y());
positions_poly.push_back(ffit->vertex(0)->point().z());
positions_poly.push_back(1.0);
positions_poly.push_back(ffit->vertex(1)->point().x());
positions_poly.push_back(ffit->vertex(1)->point().y());
positions_poly.push_back(ffit->vertex(1)->point().z());
positions_poly.push_back(1.0);
positions_poly.push_back(ffit->vertex(2)->point().x());
positions_poly.push_back(ffit->vertex(2)->point().y());
positions_poly.push_back(ffit->vertex(2)->point().z());
positions_poly.push_back(1.0);
const Point_3& pa = soup->points[pit->at(0)];
const Point_3& pb = soup->points[pit->at(1)];
const Point_3& pc = soup->points[pit->at(2)];
Kernel::Vector_3 n = CGAL::cross_product(pb-pa, pc -pa);
n = n / std::sqrt(n * n);
normals.push_back(n.x());
normals.push_back(n.y());
normals.push_back(n.z());
normals.push_back(n.x());
normals.push_back(n.y());
normals.push_back(n.z());
normals.push_back(n.x());
normals.push_back(n.y());
normals.push_back(n.z());
}
}
void
Scene_polygon_soup_item::compute_normals_and_vertices(){
//get the vertices and normals
typedef Polygon_soup::Polygons::size_type size_type;
positions_poly.clear();
positions_lines.clear();
normals.clear();
for(Polygons_iterator it = soup->polygons.begin();
it != soup->polygons.end(); ++it)
{
if(it->size()!=3)
{
triangulate_polygon(it);
}
else{
const Point_3& pa = soup->points[it->at(0)];
const Point_3& pb = soup->points[it->at(1)];
const Point_3& pc = soup->points[it->at(2)];
Kernel::Vector_3 n = CGAL::cross_product(pb-pa, pc -pa);
n = n / std::sqrt(n * n);
normals.push_back(n.x());
normals.push_back(n.y());
normals.push_back(n.z());
normals.push_back(n.x());
normals.push_back(n.y());
normals.push_back(n.z());
normals.push_back(n.x());
normals.push_back(n.y());
normals.push_back(n.z());
for(size_type i = 0; i < it->size(); ++i)
{
const Point_3& p = soup->points[it->at(i)];
positions_poly.push_back(p.x());
positions_poly.push_back(p.y());
positions_poly.push_back(p.z());
positions_poly.push_back(1.0);
}
}
//Lines
for(size_type i = 0; i < it->size()-1; i++)
{
const Point_3& pa = soup->points[it->at(i)];
const Point_3& pb = soup->points[it->at(i+1)];
positions_lines.push_back(pa.x());
positions_lines.push_back(pa.y());
positions_lines.push_back(pa.z());
positions_lines.push_back(1.0);
positions_lines.push_back(pb.x());
positions_lines.push_back(pb.y());
positions_lines.push_back(pb.z());
positions_lines.push_back(1.0);
}
}
location[0] = glGetUniformLocation(rendering_program_poly, "mvp_matrix");
location[1] = glGetUniformLocation(rendering_program_poly, "mv_matrix");
location[2] = glGetUniformLocation(rendering_program_poly, "light_pos");
location[3] = glGetUniformLocation(rendering_program_poly, "light_diff");
location[4] = glGetUniformLocation(rendering_program_poly, "light_spec");
location[5] = glGetUniformLocation(rendering_program_poly, "light_amb");
location[6] = glGetUniformLocation(rendering_program_poly, "is_two_side");
location[7] = glGetUniformLocation(rendering_program_lines, "mvp_matrix");
location[8] = glGetUniformLocation(rendering_program_lines, "color");
}
Scene_polygon_soup_item::Scene_polygon_soup_item()
: Scene_item(),
soup(0),positions_poly(0),positions_lines(0), normals(0),
oriented(false)
{
glGenVertexArrays(1, &vao);
//Generates an integer which will be used as ID for each buffer
glGenBuffers(3, buffer);
compile_shaders();
}
Scene_polygon_soup_item::~Scene_polygon_soup_item()
{
glDeleteBuffers(3, buffer);
glDeleteVertexArrays(1, &vao);
glDeleteProgram(rendering_program_lines);
glDeleteProgram(rendering_program_poly);
delete soup;
}
Scene_polygon_soup_item*
Scene_polygon_soup_item::clone() const {
Scene_polygon_soup_item* new_soup = new Scene_polygon_soup_item();
new_soup->soup = soup->clone();
new_soup->oriented = oriented;
return new_soup;
}
bool
Scene_polygon_soup_item::load(std::istream& in)
{
if (!soup) soup=new Polygon_soup();
else soup->clear();
bool result = CGAL::read_OFF(in, soup->points, soup->polygons);
emit changed();
return result;
}
void Scene_polygon_soup_item::init_polygon_soup(std::size_t nb_pts, std::size_t nb_polygons){
if(!soup)
soup = new Polygon_soup;
soup->clear();
soup->points.reserve(nb_pts);
soup->polygons.reserve(nb_polygons);
oriented = false;
}
void Scene_polygon_soup_item::finalize_polygon_soup(){ soup->fill_edges(); }
#include <CGAL/IO/generic_print_polyhedron.h>
#include <iostream>
void Scene_polygon_soup_item::load(Scene_polyhedron_item* poly_item) {
if(!poly_item) return;
if(!poly_item->polyhedron()) return;
if(!soup)
soup = new Polygon_soup;
Polyhedron_to_polygon_soup_writer writer(soup);
CGAL::generic_print_polyhedron(std::cerr,
*poly_item->polyhedron(),
writer);
emit changed();
}
void
Scene_polygon_soup_item::setDisplayNonManifoldEdges(const bool b)
{
soup->display_non_manifold_edges = b;
changed();
}
bool
Scene_polygon_soup_item::displayNonManifoldEdges() const {
return soup->display_non_manifold_edges;
}
void Scene_polygon_soup_item::shuffle_orientations()
{
for(Polygon_soup::size_type i = 0, end = soup->polygons.size();
i < end; ++i)
{
if(std::rand() % 2 == 0) soup->inverse_orientation(i);
}
soup->fill_edges();
changed();
}
void Scene_polygon_soup_item::inside_out()
{
for(Polygon_soup::size_type i = 0, end = soup->polygons.size();
i < end; ++i)
{
soup->inverse_orientation(i);
}
soup->fill_edges();
changed();
}
bool
Scene_polygon_soup_item::orient()
{
if(isEmpty() || this->oriented)
return true; // nothing to do
oriented = CGAL::orient_polygon_soup(soup->points, soup->polygons);
return oriented;
}
bool
Scene_polygon_soup_item::save(std::ostream& out) const
{
typedef Polygon_soup::size_type size_type;
CGAL::File_writer_OFF writer;
writer.write_header(out,
soup->points.size(),
0,
soup->polygons.size());
for(size_type i = 0, end = soup->points.size();
i < end; ++i)
{
const Point_3& p = soup->points[i];
writer.write_vertex( p.x(), p.y(), p.z() );
}
writer.write_facet_header();
for(size_type i = 0, end = soup->polygons.size();
i < end; ++i)
{
const Polygon_soup::Polygon_3& polygon = soup->polygons[i];
const size_type size = polygon.size();
writer.write_facet_begin(size);
for(size_type j = 0; j < size; ++j) {
writer.write_facet_vertex_index(polygon[j]);
}
writer.write_facet_end();
}
writer.write_footer();
return (bool) out;
}
bool
Scene_polygon_soup_item::exportAsPolyhedron(Polyhedron* out_polyhedron)
{
orient();
CGAL::polygon_soup_to_polyhedron_3(*out_polyhedron, soup->points, soup->polygons);
if(out_polyhedron->size_of_vertices() > 0) {
// Also check whether the consistent orientation is fine
if(!CGAL::is_oriented(*out_polyhedron)) {
out_polyhedron->inside_out();
}
return true;
}
return false;
}
QString
Scene_polygon_soup_item::toolTip() const
{
if(!soup)
return QString();
return QObject::tr("<p><b>%1</b> (mode: %5, color: %6)<br />"
"<i>Polygons soup</i></p>"
"<p>Number of vertices: %2<br />"
"Number of polygons: %3</p>")
.arg(this->name())
.arg(soup->points.size())
.arg(soup->polygons.size())
.arg(this->renderingModeName())
.arg(this->color().name());
}
void
Scene_polygon_soup_item::draw(Viewer_interface* viewer) const {
if(soup == 0) return;
//Calls the buffer info again so that it's the right one used even if
//there are several objects drawn
glBindVertexArray(vao);
uniform_attrib(viewer,0);
// tells the GPU to use the program just created
glUseProgram(rendering_program_poly);
//draw the polygons
// the third argument is the number of vec4 that will be entered
glDrawArrays(GL_TRIANGLES, 0, positions_poly.size()/4);
// Clean-up
glUseProgram(0);
glBindVertexArray(0);
}
void
Scene_polygon_soup_item::draw_points(Viewer_interface* viewer) const {
if(soup == 0) return;
glBindVertexArray(vao);
uniform_attrib(viewer,1);
glUseProgram(rendering_program_lines);
//draw the points
glDrawArrays(GL_POINTS, 0, positions_lines.size()/4);
// Clean-up
glUseProgram(0);
glBindVertexArray(0);
}
void
Scene_polygon_soup_item::draw_edges(Viewer_interface* viewer) const {
if(soup == 0) return;
glBindVertexArray(vao);
uniform_attrib(viewer,1);
glUseProgram(rendering_program_lines);
//draw the edges
glDrawArrays(GL_LINES, 0, positions_lines.size()/4);
// Clean-up
glUseProgram(0);
glBindVertexArray(0);
}
bool
Scene_polygon_soup_item::isEmpty() const {
return (soup == 0 || soup->points.empty());
}
void
Scene_polygon_soup_item::changed()
{
compute_normals_and_vertices();
initialize_buffers();
}
Scene_polygon_soup_item::Bbox
Scene_polygon_soup_item::bbox() const {
const Point_3& p = *(soup->points.begin());
CGAL::Bbox_3 bbox(p.x(), p.y(), p.z(), p.x(), p.y(), p.z());
for(Polygon_soup::Points::const_iterator it = soup->points.begin();
it != soup->points.end();
++it) {
bbox = bbox + it->bbox();
}
return Bbox(bbox.xmin(),bbox.ymin(),bbox.zmin(),
bbox.xmax(),bbox.ymax(),bbox.zmax());
}
void
Scene_polygon_soup_item::new_vertex(const double& x,
const double& y,
const double& z)
{
soup->points.push_back(Point_3(x, y, z));
}
void
Scene_polygon_soup_item::new_triangle(const std::size_t i,
const std::size_t j,
const std::size_t k)
{
Polygon_soup::Polygon_3 new_polygon(3);
new_polygon[0] = i;
new_polygon[1] = j;
new_polygon[2] = k;
soup->polygons.push_back(new_polygon);
}
#include "Scene_polygon_soup_item.moc"
// Local Variables:
// c-basic-offset: 4
// End: