cgal/Polyhedron/demo/Polyhedron/Scene_c3t3_item.cpp

1362 lines
44 KiB
C++

#include "config.h"
#include "create_sphere.h"
#include "Scene_c3t3_item.h"
#include <QVector>
#include <QColor>
#include <QPixmap>
#include <QPainter>
#include <QtCore/qglobal.h>
#include <QGuiApplication>
#include <map>
#include <vector>
#include <CGAL/gl.h>
#include <CGAL/Mesh_3/dihedral_angle_3.h>
#include <CGAL/Three/Scene_interface.h>
#include <CGAL/Real_timer.h>
#include <QGLViewer/manipulatedFrame.h>
#include <QGLViewer/qglviewer.h>
#include <boost/function_output_iterator.hpp>
#include <boost/foreach.hpp>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/AABB_C3T3_triangle_primitive.h>
typedef CGAL::AABB_C3T3_triangle_primitive<Kernel,C3t3> Primitive;
typedef CGAL::AABB_traits<Kernel, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
typedef Tree::Point_and_primitive_id Point_and_primitive_id;
struct Scene_c3t3_item_priv {
Scene_c3t3_item_priv(Scene_c3t3_item* item)
: item(item), c3t3()
{
init_default_values();
}
Scene_c3t3_item_priv(const C3t3& c3t3_, Scene_c3t3_item* item)
: item(item), c3t3(c3t3_)
{
init_default_values();
}
void init_default_values() {
show_tetrahedra = false;
is_aabb_tree_built = false;
}
void compute_intersection(const Primitive& facet);
void fill_aabb_tree() {
if(item->isEmpty()) return;
QGuiApplication::setOverrideCursor(Qt::WaitCursor);
CGAL::Real_timer timer;
timer.start();
tree.clear();
for (Tr::Finite_facets_iterator
fit = c3t3.triangulation().finite_facets_begin(),
end = c3t3.triangulation().finite_facets_end();
fit != end; ++fit)
{
Tr::Cell_handle ch = fit->first, nh =ch->neighbor(fit->second);
if( (!c3t3.is_in_complex(ch)) && (!c3t3.is_in_complex(nh)) )
continue;
if(c3t3.is_in_complex(ch)){
tree.insert(Primitive(fit));
} else{
int ni = nh->index(ch);
tree.insert(Primitive(Tr::Facet(nh,ni)));
}
}
tree.build();
std::cerr << "C3t3 facets AABB tree built in " << timer.time()
<< " wall-clock seconds\n";
is_aabb_tree_built = true;
QGuiApplication::restoreOverrideCursor();
}
Scene_c3t3_item* item;
C3t3 c3t3;
Tree tree;
QVector<QColor> colors;
bool show_tetrahedra;
bool is_aabb_tree_built;
};
struct Set_show_tetrahedra {
Scene_c3t3_item_priv* priv;
Set_show_tetrahedra(Scene_c3t3_item_priv* priv) : priv(priv) {}
void operator()(bool b) {
priv->show_tetrahedra = b;
priv->item->changed();
priv->item->itemChanged();
}
};
void Scene_c3t3_item::compile_shaders()
{
program_sphere = new QOpenGLShaderProgram();
//Source code
const char vertex_source[] =
{
"#version 120 \n"
"attribute highp vec4 vertex; \n"
"attribute highp vec3 normals; \n"
"attribute highp vec3 colors; \n"
"attribute highp vec3 center; \n"
"attribute highp float radius; \n"
"uniform highp vec4 cutplane; \n"
"uniform highp mat4 mvp_matrix; \n"
"uniform highp mat4 mv_matrix; \n"
"varying highp vec4 fP; \n"
"varying highp vec3 fN; \n"
"varying highp vec4 color; \n"
" \n"
" \n"
"void main(void) \n"
"{ \n"
" if(center.x * cutplane.x + center.y * cutplane.y + center.z * cutplane.z + cutplane.w > 0){ \n"
" color = vec4(colors,0.0); \n"
" }else{ \n"
" color = vec4(colors,1.0);} \n"
" fP = mv_matrix * vertex; \n"
" fN = mat3(mv_matrix)* normals; \n"
" gl_Position = mvp_matrix * \n"
" vec4(radius*vertex.x + center.x, radius* vertex.y + center.y, radius*vertex.z + center.z, 1.0) ; \n"
"} \n"
};
QOpenGLShader *vertex_shader = new QOpenGLShader(QOpenGLShader::Vertex);
if(!vertex_shader->compileSourceCode(vertex_source))
{
std::cerr<<"Compiling vertex source FAILED"<<std::endl;
}
if(!program_sphere->addShader(vertex_shader))
{
std::cerr<<"adding vertex shader FAILED"<<std::endl;
}
if(!program_sphere->addShaderFromSourceFile(QOpenGLShader::Fragment,":/cgal/Polyhedron_3/resources/shader_c3t3.f" ))
{
std::cerr<<"adding fragment shader FAILED"<<std::endl;
}
if(!program_sphere->link())
{
//std::cerr<<"linking Program FAILED"<<std::endl;
qDebug() << program_sphere->log();
}
}
double complex_diag(const Scene_item* item) {
const Scene_item::Bbox& bbox = item->bbox();
const double& xdelta = bbox.xmax-bbox.xmin;
const double& ydelta = bbox.ymax-bbox.ymin;
const double& zdelta = bbox.zmax-bbox.zmin;
const double diag = std::sqrt(xdelta*xdelta +
ydelta*ydelta +
zdelta*zdelta);
return diag * 0.7;
}
Scene_c3t3_item::Scene_c3t3_item()
: Scene_item(NumberOfBuffers, NumberOfVaos)
, d(new Scene_c3t3_item_priv(this))
, frame(new ManipulatedFrame())
, last_known_scene(NULL)
, data_item_(NULL)
, histogram_()
, indices_()
{
are_intersection_buffers_filled = false;
positions_lines.resize(0);
positions_poly.resize(0);
normals.resize(0);
s_vertex.resize(0);
s_normals.resize(0);
ws_vertex.resize(0);
need_changed = false;
startTimer(0);
connect(frame, SIGNAL(modified()), this, SLOT(changed()));
c3t3_changed();
setRenderingMode(FlatPlusEdges);
compile_shaders();
spheres_are_shown = false;
create_flat_and_wire_sphere(1.0f,s_vertex,s_normals, ws_vertex);
}
Scene_c3t3_item::Scene_c3t3_item(const C3t3& c3t3)
: Scene_item(NumberOfBuffers, NumberOfVaos)
, d(new Scene_c3t3_item_priv(c3t3, this))
, frame(new ManipulatedFrame())
, last_known_scene(NULL)
, data_item_(NULL)
, histogram_()
, indices_()
{
positions_lines.resize(0);
positions_poly.resize(0);
normals.resize(0);
s_vertex.resize(0);
s_normals.resize(0);
ws_vertex.resize(0);
need_changed = false;
startTimer(0);
connect(frame, SIGNAL(modified()), this, SLOT(changed()));
reset_cut_plane();
c3t3_changed();
setRenderingMode(FlatPlusEdges);
compile_shaders();
spheres_are_shown = false;
create_flat_and_wire_sphere(1.0f,s_vertex,s_normals, ws_vertex);
}
Scene_c3t3_item::~Scene_c3t3_item()
{
frame = 0;
delete frame;
delete d;
}
const Scene_item*
Scene_c3t3_item::data_item() const
{
return data_item_;
}
void
Scene_c3t3_item::set_data_item(const Scene_item* data_item)
{
data_item_ = data_item;
if (NULL != data_item)
{
connect(data_item, SIGNAL(aboutToBeDestroyed()),
this, SLOT(data_item_destroyed()));
}
}
void
Scene_c3t3_item::data_item_destroyed()
{
set_data_item(NULL);
}
const C3t3&
Scene_c3t3_item::c3t3() const {
return d->c3t3;
}
C3t3&
Scene_c3t3_item::c3t3()
{
return d->c3t3;
}
void
Scene_c3t3_item::changed()
{
need_changed = true;
}
void Scene_c3t3_item::timerEvent(QTimerEvent* /*event*/)
{ // just handle deformation - paint like selection is handled in eventFilter()
if(need_changed) {
are_intersection_buffers_filled = false;
need_changed = false;
}
}
void
Scene_c3t3_item::c3t3_changed()
{
// Update colors
// Fill indices map and get max subdomain value
indices_.clear();
int max = 0;
for (C3t3::Cells_in_complex_iterator cit = this->c3t3().cells_in_complex_begin(),
end = this->c3t3().cells_in_complex_end(); cit != end; ++cit)
{
max = (std::max)(max, cit->subdomain_index());
indices_.insert(cit->subdomain_index());
}
for (C3t3::Facets_in_complex_iterator fit = this->c3t3().facets_in_complex_begin(),
end = this->c3t3().facets_in_complex_end(); fit != end; ++fit)
{
max = (std::max)(max, fit->first->surface_patch_index(fit->second));
indices_.insert(fit->first->surface_patch_index(fit->second));
}
d->colors.resize(max + 1);
compute_color_map(color_);
// Rebuild histogram
build_histogram();
d->tree.clear();
d->is_aabb_tree_built = false;
}
QPixmap
Scene_c3t3_item::graphicalToolTip() const
{
if (!histogram_.isNull())
{
return histogram_;
}
else
{
const_cast<Scene_c3t3_item&>(*this).build_histogram();
return histogram_;
}
}
template<typename C3t3>
std::vector<int>
create_histogram(const C3t3& c3t3, double& min_value, double& max_value)
{
typedef typename C3t3::Triangulation::Point Point_3;
std::vector<int> histo(181, 0);
min_value = 180.;
max_value = 0.;
for (typename C3t3::Cells_in_complex_iterator cit = c3t3.cells_in_complex_begin();
cit != c3t3.cells_in_complex_end();
++cit)
{
if (!c3t3.is_in_complex(cit))
continue;
#ifdef CGAL_MESH_3_DEMO_DONT_COUNT_TETS_ADJACENT_TO_SHARP_FEATURES_FOR_HISTOGRAM
if (c3t3.in_dimension(cit->vertex(0)) <= 1
|| c3t3.in_dimension(cit->vertex(1)) <= 1
|| c3t3.in_dimension(cit->vertex(2)) <= 1
|| c3t3.in_dimension(cit->vertex(3)) <= 1)
continue;
#endif //CGAL_MESH_3_DEMO_DONT_COUNT_TETS_ADJACENT_TO_SHARP_FEATURES_FOR_HISTOGRAM
const Point_3& p0 = cit->vertex(0)->point();
const Point_3& p1 = cit->vertex(1)->point();
const Point_3& p2 = cit->vertex(2)->point();
const Point_3& p3 = cit->vertex(3)->point();
double a = CGAL::to_double(CGAL::abs(CGAL::Mesh_3::dihedral_angle(p0, p1, p2, p3)));
histo[static_cast<int>(std::floor(a))] += 1;
min_value = (std::min)(min_value, a);
max_value = (std::max)(max_value, a);
a = CGAL::to_double(CGAL::abs(CGAL::Mesh_3::dihedral_angle(p0, p2, p1, p3)));
histo[static_cast<int>(std::floor(a))] += 1;
min_value = (std::min)(min_value, a);
max_value = (std::max)(max_value, a);
a = CGAL::to_double(CGAL::abs(CGAL::Mesh_3::dihedral_angle(p0, p3, p1, p2)));
histo[static_cast<int>(std::floor(a))] += 1;
min_value = (std::min)(min_value, a);
max_value = (std::max)(max_value, a);
a = CGAL::to_double(CGAL::abs(CGAL::Mesh_3::dihedral_angle(p1, p2, p0, p3)));
histo[static_cast<int>(std::floor(a))] += 1;
min_value = (std::min)(min_value, a);
max_value = (std::max)(max_value, a);
a = CGAL::to_double(CGAL::abs(CGAL::Mesh_3::dihedral_angle(p1, p3, p0, p2)));
histo[static_cast<int>(std::floor(a))] += 1;
min_value = (std::min)(min_value, a);
max_value = (std::max)(max_value, a);
a = CGAL::to_double(CGAL::abs(CGAL::Mesh_3::dihedral_angle(p2, p3, p0, p1)));
histo[static_cast<int>(std::floor(a))] += 1;
min_value = (std::min)(min_value, a);
max_value = (std::max)(max_value, a);
}
return histo;
}
void
Scene_c3t3_item::build_histogram()
{
#ifdef CGAL_MESH_3_DEMO_BIGGER_HISTOGRAM_WITH_WHITE_BACKGROUNG
// Create an histogram_ and display it
const int height = 280;
const int top_margin = 5;
const int left_margin = 20;
const int drawing_height = height - top_margin * 2;
const int width = 804;
const int cell_width = 4;
const int text_margin = 3;
const int text_height = 34;
histogram_ = QPixmap(width, height + text_height);
histogram_.fill(QColor(255, 255, 255));
#else
// Create an histogram_ and display it
const int height = 140;
const int top_margin = 5;
const int left_margin = 20;
const int drawing_height = height - top_margin * 2;
const int width = 402;
const int cell_width = 2;
const int text_margin = 3;
const int text_height = 20;
histogram_ = QPixmap(width, height + text_height);
histogram_.fill(QColor(192, 192, 192));
#endif
QPainter painter(&histogram_);
painter.setPen(Qt::black);
painter.setBrush(QColor(128, 128, 128));
//painter.setFont(QFont("Arial", 30));
// Build histogram_ data
double min_value, max_value;
std::vector<int> histo_data = create_histogram(c3t3(), min_value, max_value);
// Get maximum value (to normalize)
int max_size = 0;
for (std::vector<int>::iterator it = histo_data.begin(), end = histo_data.end();
it != end; ++it)
{
max_size = (std::max)(max_size, *it);
}
// colored histogram
int j = 0;
// draw
int i = left_margin;
for (std::vector<int>::iterator it = histo_data.begin(), end = histo_data.end();
it != end; ++it, i += cell_width)
{
int line_height = static_cast<int>(std::ceil(static_cast<double>(drawing_height)*
static_cast<double>(*it) / static_cast<double>(max_size)) + .5);
painter.fillRect(i,
drawing_height + top_margin - line_height,
cell_width,
line_height,
get_histogram_color(j++));
}
// draw bottom horizontal line
painter.setPen(Qt::blue);
painter.drawLine(QPoint(left_margin, drawing_height + top_margin),
QPoint(left_margin + static_cast<int>(histo_data.size())*cell_width,
drawing_height + top_margin));
// draw min value and max value
const int min_tr_width = static_cast<int>(2 * (std::floor(min_value)*cell_width + left_margin));
const int max_tr_width = static_cast<int>(
2 * ((histo_data.size() - std::floor(max_value))*cell_width + left_margin));
const int tr_y = drawing_height + top_margin + text_margin;
painter.setPen(get_histogram_color(min_value));
QRect min_text_rect(0, tr_y, min_tr_width, text_height);
painter.drawText(min_text_rect, Qt::AlignCenter, tr("%1").arg(min_value, 0, 'f', 1));
painter.setPen(get_histogram_color(max_value));
QRect max_text_rect(width - max_tr_width, tr_y, max_tr_width, text_height);
painter.drawText(max_text_rect, Qt::AlignCenter, tr("%1").arg(max_value, 0, 'f', 1));
}
QColor
Scene_c3t3_item::get_histogram_color(const double v) const
{
if (v < 5) { return Qt::red; }
else if (v < 10) { return QColor(215, 108, 0); }
else if (v < 15) { return QColor(138, 139, 0); }
else if (v < 165) { return QColor(60, 136, 64); }
else if (v < 170) { return QColor(138, 139, 1); }
else if (v < 175) { return QColor(215, 108, 0); }
else /* 175<v<=180 */ { return Qt::red; }
}
void
Scene_c3t3_item::update_histogram()
{
build_histogram();
}
void
Scene_c3t3_item::compute_color_map(const QColor& c)
{
typedef Indices::size_type size_type;
size_type nb_domains = indices_.size();
size_type i = 0;
for (Indices::iterator it = indices_.begin(), end = indices_.end();
it != end; ++it, ++i)
{
double hue = c.hueF() + 1. / nb_domains * i;
if (hue > 1) { hue -= 1.; }
d->colors[*it] = QColor::fromHsvF(hue, c.saturationF(), c.valueF());
}
}
Kernel::Plane_3 Scene_c3t3_item::plane() const {
const qglviewer::Vec& pos = frame->position();
const qglviewer::Vec& n =
frame->inverseTransformOf(qglviewer::Vec(0.f, 0.f, 1.f));
return Kernel::Plane_3(n[0], n[1], n[2], -n * pos);
}
void Scene_c3t3_item::compute_bbox() const {
if (isEmpty())
_bbox = Bbox();
else {
CGAL::Bbox_3 result;
for (Tr::Finite_vertices_iterator
vit = ++c3t3().triangulation().finite_vertices_begin(),
end = c3t3().triangulation().finite_vertices_end();
vit != end; ++vit)
{
if(vit->in_dimension() == -1) continue;
result = result + vit->point().bbox();
}
_bbox = Bbox(result.xmin(), result.ymin(), result.zmin(),
result.xmax(), result.ymax(), result.zmax());
}
}
QString Scene_c3t3_item::toolTip() const {
return tr("<p><b>3D complex in a 3D triangulation</b></p>"
"<p>Number of vertices: %1<br />"
"Number of surface facets: %2<br />"
"Number of volume tetrahedra: %3</p>")
.arg(c3t3().triangulation().number_of_vertices())
.arg(c3t3().number_of_facets_in_complex())
.arg(c3t3().number_of_cells_in_complex());
}
void Scene_c3t3_item::draw(CGAL::Three::Viewer_interface* viewer) const {
Scene_c3t3_item* ncthis = const_cast<Scene_c3t3_item*>(this);
if (!are_buffers_filled)
{
ncthis->compute_elements();
ncthis->initialize_buffers(viewer);
}
vaos[Grid]->bind();
program = getShaderProgram(PROGRAM_WITHOUT_LIGHT);
attrib_buffers(viewer, PROGRAM_WITHOUT_LIGHT);
program->bind();
program->setAttributeValue("colors", QColor(Qt::black));
QMatrix4x4 f_mat;
for (int i = 0; i<16; i++)
f_mat.data()[i] = frame->matrix()[i];
program->setUniformValue("f_matrix", f_mat);
viewer->glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(positions_grid.size() / 3));
program->release();
vaos[Grid]->release();
vaos[Facets]->bind();
program = getShaderProgram(PROGRAM_C3T3);
attrib_buffers(viewer, PROGRAM_C3T3);
program->bind();
QVector4D cp(this->plane().a(),this->plane().b(),this->plane().c(),this->plane().d());
program->setUniformValue("cutplane", cp);
// positions_poly_size is the number of total facets in the C3T3
// it is only computed once and positions_poly is emptied at the end
viewer->glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(positions_poly_size / 3));
program->release();
vaos[Facets]->release();
if(d->show_tetrahedra && !frame->isManipulated()) {
if (!are_intersection_buffers_filled)
{
ncthis->compute_intersections();
ncthis->initialize_intersection_buffers(viewer);
}
vaos[iFacets]->bind();
program = getShaderProgram(PROGRAM_WITH_LIGHT);
attrib_buffers(viewer, PROGRAM_WITH_LIGHT);
program->bind();
// positions_poly is also used for the faces in the cut plane
// and changes when the cut plane is moved
viewer->glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(positions_poly.size() / 3));
program->release();
vaos[iFacets]->release();
}
if(spheres_are_shown)
{
vaos[Spheres]->bind();
program_sphere->bind();
//ModelViewMatrix used for the transformation of the camera.
QMatrix4x4 mvp_mat;
// ModelView Matrix used for the lighting system
QMatrix4x4 mv_mat;
GLdouble d_mat[16];
GLint is_both_sides = 0;
viewer->camera()->getModelViewProjectionMatrix(d_mat);
//Convert the GLdoubles matrices in GLfloats
for (int i=0; i<16; ++i){
mvp_mat.data()[i] = GLfloat(d_mat[i]);
}
viewer->camera()->getModelViewMatrix(d_mat);
for (int i=0; i<16; ++i)
mv_mat.data()[i] = GLfloat(d_mat[i]);
QVector4D position(0.0f,0.0f,1.0f, 1.0f );
QVector4D ambient(0.4f, 0.4f, 0.4f, 0.4f);
// Diffuse
QVector4D diffuse(1.0f, 1.0f, 1.0f, 1.0f);
// Specular
QVector4D specular(0.0f, 0.0f, 0.0f, 1.0f);
viewer->glGetIntegerv(GL_LIGHT_MODEL_TWO_SIDE, &is_both_sides);
QVector4D cp(this->plane().a(),this->plane().b(),this->plane().c(),this->plane().d());
program_sphere->setUniformValue("cutplane", cp);
program_sphere->setUniformValue("mvp_matrix", mvp_mat);
program_sphere->setUniformValue("mv_matrix", mv_mat);
program_sphere->setUniformValue("light_pos", position);
program_sphere->setUniformValue("light_diff",diffuse);
program_sphere->setUniformValue("light_spec", specular);
program_sphere->setUniformValue("light_amb", ambient);
program_sphere->setUniformValue("spec_power", 51.8f);
program_sphere->setUniformValue("is_two_side", is_both_sides);
viewer->glDrawArraysInstanced(GL_TRIANGLES, 0,
static_cast<GLsizei>(s_vertex.size()/3),
static_cast<GLsizei>(s_radius.size()));
program_sphere->release();
vaos[Spheres]->release();
}
}
void Scene_c3t3_item::draw_edges(CGAL::Three::Viewer_interface* viewer) const {
Scene_c3t3_item* ncthis = const_cast<Scene_c3t3_item*>(this);
if (!are_buffers_filled)
{
ncthis->compute_elements();
ncthis->initialize_buffers(viewer);
}
if(renderingMode() == Wireframe)
{
vaos[Grid]->bind();
program = getShaderProgram(PROGRAM_WITHOUT_LIGHT);
attrib_buffers(viewer, PROGRAM_WITHOUT_LIGHT);
program->bind();
program->setAttributeValue("colors", QColor(Qt::black));
QMatrix4x4 f_mat;
for (int i = 0; i<16; i++)
f_mat.data()[i] = frame->matrix()[i];
program->setUniformValue("f_matrix", f_mat);
viewer->glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(positions_grid.size() / 3));
program->release();
vaos[Grid]->release();
}
vaos[Edges]->bind();
program = getShaderProgram(PROGRAM_C3T3_EDGES);
attrib_buffers(viewer, PROGRAM_C3T3_EDGES);
program->bind();
QVector4D cp(this->plane().a(),this->plane().b(),this->plane().c(),this->plane().d());
program->setUniformValue("cutplane", cp);
program->setAttributeValue("colors", QColor(Qt::black));
viewer->glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(positions_lines_size / 3));
program->release();
vaos[Edges]->release();
if(d->show_tetrahedra && !frame->isManipulated()) {
if (!are_intersection_buffers_filled)
{
ncthis->compute_intersections();
ncthis->initialize_intersection_buffers(viewer);
}
vaos[iEdges]->bind();
program = getShaderProgram(PROGRAM_NO_SELECTION);
attrib_buffers(viewer, PROGRAM_NO_SELECTION);
program->bind();
program->setAttributeValue("colors", QColor(Qt::black));
viewer->glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(positions_lines.size() / 3));
program->release();
vaos[iEdges]->release();
}
if(spheres_are_shown)
{
vaos[Wired_spheres]->bind();
program_sphere->bind();
//ModelViewMatrix used for the transformation of the camera.
QMatrix4x4 mvp_mat;
// ModelView Matrix used for the lighting system
QMatrix4x4 mv_mat;
GLdouble d_mat[16];
GLint is_both_sides = 0;
viewer->camera()->getModelViewProjectionMatrix(d_mat);
//Convert the GLdoubles matrices in GLfloats
for (int i=0; i<16; ++i){
mvp_mat.data()[i] = GLfloat(d_mat[i]);
}
viewer->camera()->getModelViewMatrix(d_mat);
for (int i=0; i<16; ++i)
mv_mat.data()[i] = GLfloat(d_mat[i]);
QVector4D position(0.0f,0.0f,1.0f, 1.0f );
QVector4D ambient(0.4f, 0.4f, 0.4f, 0.4f);
// Diffuse
QVector4D diffuse(1.0f, 1.0f, 1.0f, 1.0f);
// Specular
QVector4D specular(0.0f, 0.0f, 0.0f, 1.0f);
viewer->glGetIntegerv(GL_LIGHT_MODEL_TWO_SIDE, &is_both_sides);
program_sphere->setUniformValue("mvp_matrix", mvp_mat);
program_sphere->setUniformValue("mv_matrix", mv_mat);
program_sphere->setUniformValue("light_pos", position);
program_sphere->setUniformValue("light_diff",diffuse);
program_sphere->setUniformValue("light_spec", specular);
program_sphere->setUniformValue("light_amb", ambient);
program_sphere->setUniformValue("spec_power", 51.8f);
program_sphere->setUniformValue("is_two_side", is_both_sides);
viewer->glDrawArraysInstanced(GL_TRIANGLES, 0,
static_cast<GLsizei>(ws_vertex.size()/3),
static_cast<GLsizei>(s_radius.size()));
program_sphere->release();
vaos[Wired_spheres]->release();
}
}
void Scene_c3t3_item::draw_points(CGAL::Three::Viewer_interface * viewer) const
{
Scene_c3t3_item* ncthis = const_cast<Scene_c3t3_item*>(this);
if (!are_buffers_filled)
{
ncthis->compute_elements();
ncthis-> initialize_buffers(viewer);
}
vaos[Edges]->bind();
program = getShaderProgram(PROGRAM_C3T3_EDGES);
attrib_buffers(viewer, PROGRAM_C3T3_EDGES);
program->bind();
QVector4D cp(this->plane().a(),this->plane().b(),this->plane().c(),this->plane().d());
program->setUniformValue("cutplane", cp);
program->setAttributeValue("colors", this->color());
viewer->glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(positions_lines.size() / 3));
vaos[Edges]->release();
program->release();
vaos[Grid]->bind();
program = getShaderProgram(PROGRAM_WITHOUT_LIGHT);
attrib_buffers(viewer, PROGRAM_WITHOUT_LIGHT);
program->bind();
program->setAttributeValue("colors", this->color());
QMatrix4x4 f_mat;
for (int i = 0; i<16; i++)
f_mat.data()[i] = frame->matrix()[i];
program->setUniformValue("f_matrix", f_mat);
viewer->glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(positions_grid.size() / 3));
program->release();
vaos[Grid]->release();
}
void Scene_c3t3_item::draw_triangle(const Kernel::Point_3& pa,
const Kernel::Point_3& pb,
const Kernel::Point_3& pc, bool /* is_cut */) const {
#undef darker
Kernel::Vector_3 n = cross_product(pb - pa, pc - pa);
n = n / CGAL::sqrt(n*n);
for (int i = 0; i<3; i++)
{
normals.push_back(n.x());
normals.push_back(n.y());
normals.push_back(n.z());
}
positions_poly.push_back(pa.x());
positions_poly.push_back(pa.y());
positions_poly.push_back(pa.z());
positions_poly.push_back(pb.x());
positions_poly.push_back(pb.y());
positions_poly.push_back(pb.z());
positions_poly.push_back(pc.x());
positions_poly.push_back(pc.y());
positions_poly.push_back(pc.z());
}
void Scene_c3t3_item::draw_triangle_edges(const Kernel::Point_3& pa,
const Kernel::Point_3& pb,
const Kernel::Point_3& pc)const {
#undef darker
positions_lines.push_back(pa.x());
positions_lines.push_back(pa.y());
positions_lines.push_back(pa.z());
positions_lines.push_back(pb.x());
positions_lines.push_back(pb.y());
positions_lines.push_back(pb.z());
positions_lines.push_back(pb.x());
positions_lines.push_back(pb.y());
positions_lines.push_back(pb.z());
positions_lines.push_back(pc.x());
positions_lines.push_back(pc.y());
positions_lines.push_back(pc.z());
positions_lines.push_back(pc.x());
positions_lines.push_back(pc.y());
positions_lines.push_back(pc.z());
positions_lines.push_back(pa.x());
positions_lines.push_back(pa.y());
positions_lines.push_back(pa.z());
}
double Scene_c3t3_item::complex_diag() const {
const Bbox& bbox = this->bbox();
const double& xdelta = bbox.xmax - bbox.xmin;
const double& ydelta = bbox.ymax - bbox.ymin;
const double& zdelta = bbox.zmax - bbox.zmin;
const double diag = std::sqrt(xdelta*xdelta +
ydelta*ydelta +
zdelta*zdelta);
return diag * 0.7;
}
void Scene_c3t3_item::export_facets_in_complex()
{
std::stringstream off_sstream;
c3t3().output_facets_in_complex_to_off(off_sstream);
std::string backup = off_sstream.str();
// Try to read .off in a polyhedron
Scene_polyhedron_item* item = new Scene_polyhedron_item;
if (!item->load(off_sstream))
{
delete item;
off_sstream.str(backup);
// Try to read .off in a polygon soup
Scene_polygon_soup_item* soup_item = new Scene_polygon_soup_item;
if (!soup_item->load(off_sstream)) {
delete soup_item;
return;
}
soup_item->setName(QString("%1_%2").arg(this->name()).arg("facets"));
last_known_scene->addItem(soup_item);
}
else{
item->setName(QString("%1_%2").arg(this->name()).arg("facets"));
last_known_scene->addItem(item);
}
}
QMenu* Scene_c3t3_item::contextMenu()
{
const char* prop_name = "Menu modified by Scene_c3t3_item.";
QMenu* menu = Scene_item::contextMenu();
// Use dynamic properties:
// http://doc.qt.io/qt-5/qobject.html#property
bool menuChanged = menu->property(prop_name).toBool();
if (!menuChanged) {
QAction* actionExportFacetsInComplex =
menu->addAction(tr("Export facets in complex"));
actionExportFacetsInComplex->setObjectName("actionExportFacetsInComplex");
connect(actionExportFacetsInComplex,
SIGNAL(triggered()), this,
SLOT(export_facets_in_complex()));
QAction* actionShowSpheres =
menu->addAction(tr("Show protecting &spheres"));
actionShowSpheres->setCheckable(true);
actionShowSpheres->setObjectName("actionShowSpheres");
connect(actionShowSpheres, SIGNAL(toggled(bool)),
this, SLOT(show_spheres(bool)));
QAction* actionShowTets =
menu->addAction(tr("Show &tetrahedra"));
actionShowTets->setCheckable(true);
actionShowTets->setObjectName("actionShowTets");
connect(actionShowTets, &QAction::toggled, Set_show_tetrahedra(this->d));
menu->setProperty(prop_name, true);
}
return menu;
}
void Scene_c3t3_item::initialize_intersection_buffers(CGAL::Three::Viewer_interface *viewer)
{
//vao containing the data for the facets
{
program = getShaderProgram(PROGRAM_WITH_LIGHT, viewer);
program->bind();
vaos[iFacets]->bind();
buffers[iFacet_vertices].bind();
buffers[iFacet_vertices].allocate(positions_poly.data(),
static_cast<int>(positions_poly.size()*sizeof(float)));
program->enableAttributeArray("vertex");
program->setAttributeBuffer("vertex", GL_FLOAT, 0, 3);
buffers[iFacet_vertices].release();
buffers[iFacet_normals].bind();
buffers[iFacet_normals].allocate(normals.data(),
static_cast<int>(normals.size()*sizeof(float)));
program->enableAttributeArray("normals");
program->setAttributeBuffer("normals", GL_FLOAT, 0, 3);
buffers[iFacet_normals].release();
buffers[iFacet_colors].bind();
buffers[iFacet_colors].allocate(f_colors.data(),
static_cast<int>(f_colors.size()*sizeof(float)));
program->enableAttributeArray("colors");
program->setAttributeBuffer("colors", GL_FLOAT, 0, 3);
buffers[iFacet_colors].release();
vaos[iFacets]->release();
program->release();
}
//vao containing the data for the lines
{
program = getShaderProgram(PROGRAM_NO_SELECTION, viewer);
program->bind();
vaos[iEdges]->bind();
buffers[iEdges_vertices].bind();
buffers[iEdges_vertices].allocate(positions_lines.data(),
static_cast<int>(positions_lines.size()*sizeof(float)));
program->enableAttributeArray("vertex");
program->setAttributeBuffer("vertex", GL_FLOAT, 0, 3);
buffers[iEdges_vertices].release();
vaos[iEdges]->release();
program->release();
}
are_intersection_buffers_filled = true;
}
void Scene_c3t3_item::initialize_buffers(CGAL::Three::Viewer_interface *viewer)
{
//vao containing the data for the facets
{
program = getShaderProgram(PROGRAM_C3T3, viewer);
program->bind();
vaos[Facets]->bind();
buffers[Facet_vertices].bind();
buffers[Facet_vertices].allocate(positions_poly.data(),
static_cast<int>(positions_poly.size()*sizeof(float)));
program->enableAttributeArray("vertex");
program->setAttributeBuffer("vertex", GL_FLOAT, 0, 3);
buffers[Facet_vertices].release();
buffers[Facet_normals].bind();
buffers[Facet_normals].allocate(normals.data(),
static_cast<int>(normals.size()*sizeof(float)));
program->enableAttributeArray("normals");
program->setAttributeBuffer("normals", GL_FLOAT, 0, 3);
buffers[Facet_normals].release();
buffers[Facet_colors].bind();
buffers[Facet_colors].allocate(f_colors.data(),
static_cast<int>(f_colors.size()*sizeof(float)));
program->enableAttributeArray("colors");
program->setAttributeBuffer("colors", GL_FLOAT, 0, 3);
buffers[Facet_colors].release();
vaos[Facets]->release();
program->release();
positions_poly_size = positions_poly.size();
positions_poly.clear();
positions_poly.swap(positions_poly);
normals.clear();
normals.swap(normals);
f_colors.clear();
f_colors.swap(f_colors);
}
//vao containing the data for the lines
{
program = getShaderProgram(PROGRAM_C3T3_EDGES, viewer);
program->bind();
vaos[Edges]->bind();
buffers[Edges_vertices].bind();
buffers[Edges_vertices].allocate(positions_lines.data(),
static_cast<int>(positions_lines.size()*sizeof(float)));
program->enableAttributeArray("vertex");
program->setAttributeBuffer("vertex", GL_FLOAT, 0, 3);
buffers[Edges_vertices].release();
vaos[Edges]->release();
program->release();
positions_lines_size = positions_lines.size();
positions_lines.clear();
positions_lines.swap(positions_lines);
}
//vao containing the data for the grid
{
program = getShaderProgram(PROGRAM_WITHOUT_LIGHT, viewer);
program->bind();
vaos[Grid]->bind();
buffers[Grid_vertices].bind();
buffers[Grid_vertices].allocate(positions_grid.data(),
static_cast<int>(positions_grid.size()*sizeof(float)));
program->enableAttributeArray("vertex");
program->setAttributeBuffer("vertex", GL_FLOAT, 0, 3);
buffers[Grid_vertices].release();
vaos[Grid]->release();
program->release();
}
//vao containing the data for the spheres
{
program_sphere->bind();
vaos[Spheres]->bind();
buffers[Sphere_vertices].bind();
buffers[Sphere_vertices].allocate(s_vertex.data(),
static_cast<int>(s_vertex.size()*sizeof(float)));
program_sphere->enableAttributeArray("vertex");
program_sphere->setAttributeBuffer("vertex", GL_FLOAT, 0, 3);
buffers[Sphere_vertices].release();
buffers[Sphere_normals].bind();
buffers[Sphere_normals].allocate(s_normals.data(),
static_cast<int>(s_normals.size()*sizeof(float)));
program_sphere->enableAttributeArray("normals");
program_sphere->setAttributeBuffer("normals", GL_FLOAT, 0, 3);
buffers[Sphere_normals].release();
buffers[Sphere_colors].bind();
buffers[Sphere_colors].allocate(s_colors.data(),
static_cast<int>(s_colors.size()*sizeof(float)));
program_sphere->enableAttributeArray("colors");
program_sphere->setAttributeBuffer("colors", GL_FLOAT, 0, 3);
buffers[Sphere_colors].release();
buffers[Sphere_radius].bind();
buffers[Sphere_radius].allocate(s_radius.data(),
static_cast<int>(s_radius.size()*sizeof(float)));
program_sphere->enableAttributeArray("radius");
program_sphere->setAttributeBuffer("radius", GL_FLOAT, 0, 1);
buffers[Sphere_radius].release();
buffers[Sphere_center].bind();
buffers[Sphere_center].allocate(s_center.data(),
static_cast<int>(s_center.size()*sizeof(float)));
program_sphere->enableAttributeArray("center");
program_sphere->setAttributeBuffer("center", GL_FLOAT, 0, 3);
buffers[Sphere_center].release();
viewer->glVertexAttribDivisor(program_sphere->attributeLocation("center"), 1);
viewer->glVertexAttribDivisor(program_sphere->attributeLocation("radius"), 1);
viewer->glVertexAttribDivisor(program_sphere->attributeLocation("colors"), 1);
vaos[Spheres]->release();
}
//vao containing the data for the wired spheres
{
program_sphere->bind();
vaos[Wired_spheres]->bind();
buffers[Wired_spheres_vertices].bind();
buffers[Wired_spheres_vertices].allocate(s_vertex.data(),
static_cast<int>(s_vertex.size()*sizeof(float)));
program_sphere->enableAttributeArray("vertex");
program_sphere->setAttributeBuffer("vertex", GL_FLOAT, 0, 3);
buffers[Wired_spheres_vertices].release();
buffers[Sphere_normals].bind();
program_sphere->enableAttributeArray("normals");
program_sphere->setAttributeBuffer("normals", GL_FLOAT, 0, 3);
buffers[Sphere_normals].release();
buffers[Sphere_colors].bind();
program_sphere->enableAttributeArray("colors");
program_sphere->setAttributeBuffer("colors", GL_FLOAT, 0, 3);
buffers[Sphere_colors].release();
buffers[Sphere_radius].bind();
program_sphere->enableAttributeArray("radius");
program_sphere->setAttributeBuffer("radius", GL_FLOAT, 0, 1);
buffers[Sphere_radius].release();
buffers[Sphere_center].bind();
program_sphere->enableAttributeArray("center");
program_sphere->setAttributeBuffer("center", GL_FLOAT, 0, 3);
buffers[Sphere_center].release();
viewer->glVertexAttribDivisor(program_sphere->attributeLocation("center"), 1);
viewer->glVertexAttribDivisor(program_sphere->attributeLocation("radius"), 1);
viewer->glVertexAttribDivisor(program_sphere->attributeLocation("colors"), 1);
vaos[Wired_spheres]->release();
program_sphere->release();
}
program_sphere->release();
are_buffers_filled = true;
}
void Scene_c3t3_item_priv::compute_intersection(const Primitive& facet)
{
const Kernel::Point_3& pa = facet.id().first->vertex(0)->point();
const Kernel::Point_3& pb = facet.id().first->vertex(1)->point();
const Kernel::Point_3& pc = facet.id().first->vertex(2)->point();
const Kernel::Point_3& pd = facet.id().first->vertex(3)->point();
QColor color = this->colors[facet.id().first->subdomain_index()].darker(150);
for(int i=0; i < 12;i++){
item->f_colors.push_back(color.redF());
item->f_colors.push_back(color.greenF());
item->f_colors.push_back(color.blueF());
}
item->draw_triangle(pb, pa, pc, true);
item->draw_triangle(pa, pb, pd, true);
item->draw_triangle(pa, pd, pc, true);
item->draw_triangle(pb, pc, pd, true);
item->draw_triangle_edges(pb, pa, pc);
item->draw_triangle_edges(pa, pb, pd);
item->draw_triangle_edges(pa, pd, pc);
item->draw_triangle_edges(pb, pc, pd);
{
Tr::Cell_handle nh = facet.id().first->neighbor(facet.id().second);
if(c3t3.is_in_complex(nh)){
const Kernel::Point_3& pa = nh->vertex(0)->point();
const Kernel::Point_3& pb = nh->vertex(1)->point();
const Kernel::Point_3& pc = nh->vertex(2)->point();
const Kernel::Point_3& pd = nh->vertex(3)->point();
for(int i=0; i < 12;i++){
item->f_colors.push_back(color.redF());
item->f_colors.push_back(color.greenF());
item->f_colors.push_back(color.blueF());
}
item->draw_triangle(pb, pa, pc, true);
item->draw_triangle(pa, pb, pd, true);
item->draw_triangle(pa, pd, pc, true);
item->draw_triangle(pb, pc, pd, true);
item->draw_triangle_edges(pb, pa, pc);
item->draw_triangle_edges(pa, pb, pd);
item->draw_triangle_edges(pa, pd, pc);
item->draw_triangle_edges(pb, pc, pd);
}
}
}
struct Compute_intersection {
Scene_c3t3_item_priv& item_priv;
Compute_intersection(Scene_c3t3_item_priv& item_priv)
: item_priv(item_priv)
{}
void operator()(const Primitive& facet) const
{
item_priv.compute_intersection(facet);
}
};
void Scene_c3t3_item::compute_intersections()
{
if(!d->is_aabb_tree_built) d->fill_aabb_tree();
positions_poly.clear();
normals.clear();
f_colors.clear();
positions_lines.clear();
const Kernel::Plane_3& plane = this->plane();
d->tree.all_intersected_primitives(plane,
boost::make_function_output_iterator(Compute_intersection(*this->d)));
}
void Scene_c3t3_item::compute_elements()
{
positions_poly.clear();
normals.clear();
f_colors.clear();
positions_lines.clear();
s_colors.resize(0);
s_center.resize(0);
s_radius.resize(0);
//The grid
{
float x = (2 * (float)complex_diag()) / 10.0;
float y = (2 * (float)complex_diag()) / 10.0;
for (int u = 0; u < 11; u++)
{
positions_grid.push_back(-(float)complex_diag() + x* u);
positions_grid.push_back(-(float)complex_diag());
positions_grid.push_back(0.0);
positions_grid.push_back(-(float)complex_diag() + x* u);
positions_grid.push_back((float)complex_diag());
positions_grid.push_back(0.0);
}
for (int v = 0; v<11; v++)
{
positions_grid.push_back(-(float)complex_diag());
positions_grid.push_back(-(float)complex_diag() + v * y);
positions_grid.push_back(0.0);
positions_grid.push_back((float)complex_diag());
positions_grid.push_back(-(float)complex_diag() + v * y);
positions_grid.push_back(0.0);
}
}
if (isEmpty()){
return;
}
//The facets
{
for (C3t3::Facet_iterator
fit = c3t3().facets_begin(),
end = c3t3().facets_end();
fit != end; ++fit)
{
const Tr::Cell_handle& cell = fit->first;
const int& index = fit->second;
const Kernel::Point_3& pa = cell->vertex((index + 1) & 3)->point();
const Kernel::Point_3& pb = cell->vertex((index + 2) & 3)->point();
const Kernel::Point_3& pc = cell->vertex((index + 3) & 3)->point();
QColor color = d->colors[cell->surface_patch_index(index)];
f_colors.push_back(color.redF());f_colors.push_back(color.greenF());f_colors.push_back(color.blueF());
f_colors.push_back(color.redF());f_colors.push_back(color.greenF());f_colors.push_back(color.blueF());
f_colors.push_back(color.redF());f_colors.push_back(color.greenF());f_colors.push_back(color.blueF());
if ((index % 2 == 1) == c3t3().is_in_complex(cell)) draw_triangle(pb, pa, pc, false);
else draw_triangle(pa, pb, pc, false);
draw_triangle_edges(pa, pb, pc);
}
}
//The Spheres
{
for(Tr::Finite_vertices_iterator
vit = d->c3t3.triangulation().finite_vertices_begin(),
end = d->c3t3.triangulation().finite_vertices_end();
vit != end; ++vit)
{
if(vit->point().weight()==0) continue;
typedef Tr::Vertex_handle Vertex_handle;
std::vector<Vertex_handle> incident_vertices;
d->c3t3.triangulation().incident_vertices(vit, std::back_inserter(incident_vertices));
bool red = vit->is_special();
for(std::vector<Vertex_handle>::const_iterator
vvit = incident_vertices.begin(), end = incident_vertices.end();
vvit != end; ++vvit)
{
if(Kernel::Sphere_3(vit->point().point(),
vit->point().weight()).bounded_side((*vvit)->point().point())
== CGAL::ON_BOUNDED_SIDE)
red = true;
}
if(red){
s_colors.push_back(1.0);
s_colors.push_back(0.0);
s_colors.push_back(0.0);
}
else{
QColor c = this->color().darker(250);
s_colors.push_back(c.redF());
s_colors.push_back(c.greenF());
s_colors.push_back(c.blueF());
}
s_center.push_back(vit->point().point().x());
s_center.push_back(vit->point().point().y());
s_center.push_back(vit->point().point().z());
s_radius.push_back(CGAL::sqrt(vit->point().weight()));
}
}
}
bool Scene_c3t3_item::load_binary(std::istream& is)
{
if(!CGAL::Mesh_3::load_binary_file(is, c3t3())) return false;
if(is && frame == 0) {
frame = new qglviewer::ManipulatedFrame();
}
reset_cut_plane();
if(is.good()) {
c3t3_changed();
changed();
return true;
}
else
return false;
}
void
Scene_c3t3_item::reset_cut_plane() {
const Bbox& bbox = this->bbox();
const float xcenter = static_cast<float>((bbox.xmax+bbox.xmin)/2.);
const float ycenter = static_cast<float>((bbox.ymax+bbox.ymin)/2.);
const float zcenter = static_cast<float>((bbox.zmax+bbox.zmin)/2.);
frame->setPosition(qglviewer::Vec(xcenter, ycenter, zcenter));
}
void
Scene_c3t3_item::setColor(QColor c)
{
color_ = c;
compute_color_map(c);
invalidateOpenGLBuffers();
// changed() doesn't work because the timerEvent delays it out of the draw
// function and the intersection is not drawn before the next draw call
are_intersection_buffers_filled = false;
}