diff --git a/AABB_tree/demo/AABB_tree/Scene.cpp b/AABB_tree/demo/AABB_tree/Scene.cpp index 5edece4661a..a87cd91e890 100644 --- a/AABB_tree/demo/AABB_tree/Scene.cpp +++ b/AABB_tree/demo/AABB_tree/Scene.cpp @@ -1111,7 +1111,6 @@ void Scene::compute_distance_function(const Tree& tree) { // Get transformation Aff_transformation t = frame_transformation(); - m_max_distance_function = FT(0); FT diag = bbox_diag(); @@ -1126,7 +1125,6 @@ void Scene::compute_distance_function(const Tree& tree) for(int j=0 ; j +#ifdef scene_color_ramp_EXPORTS +# define SCENE_COLOR_RAMP_EXPORT Q_DECL_EXPORT +#else +# define SCENE_COLOR_RAMP_EXPORT Q_DECL_IMPORT +#endif + #include -class Color_component +class SCENE_COLOR_RAMP_EXPORT Color_component { typedef std::list > Values; @@ -26,7 +33,7 @@ private: }; -class Color_ramp +class SCENE_COLOR_RAMP_EXPORT Color_ramp { public : Color_ramp(); @@ -39,6 +46,7 @@ public : void build_red(); void build_blue(); + void build_thermal(); void print() const; private : diff --git a/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/CMakeLists.txt index d35c622c752..a1f0c9c862e 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/CMakeLists.txt @@ -1,4 +1,4 @@ include( polyhedron_demo_macros ) -polyhedron_demo_plugin(cut_plugin Cut_plugin) -target_link_libraries(cut_plugin scene_polyhedron_item scene_basic_objects) +polyhedron_demo_plugin(cut_plugin Cut_plugin ) +target_link_libraries(cut_plugin scene_polyhedron_item scene_basic_objects scene_color_ramp) diff --git a/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp index b387cd8834e..b051061e2b5 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/AABB_tree/Cut_plugin.cpp @@ -3,18 +3,24 @@ #include #include +#include "Scene.h" +#include "Color_ramp.h" #include "Messages_interface.h" #include "Scene_plane_item.h" #include "Scene_polyhedron_item.h" #include #include +#include +#include #include #include #include #include +#include #include -#include +//#include +#include #include @@ -25,19 +31,172 @@ #include #include #include -#include -//typedef CGAL::Simple_cartesian Epic_kernel; -typedef CGAL::Exact_predicates_inexact_constructions_kernel Epic_kernel; +#include +#include + +#ifdef CGAL_LINKED_WITH_TBB +#include +#include +#include +#endif // CGAL_LINKED_WITH_TBB + +typedef CGAL::Simple_cartesian Simple_kernel; +typedef Simple_kernel::FT FT; +typedef Simple_kernel::Point_3 Point; +typedef std::pair Point_distance; + + +FT random_in(const double a, + const double b) +{ + double r = rand() / (double)RAND_MAX; + return (FT)(a + (b - a) * r); +} + +Simple_kernel::Vector_3 random_vector() +{ + FT x = random_in(0.0,1.0); + FT y = random_in(0.0,1.0); + FT z = random_in(0.0,1.0); + return Simple_kernel::Vector_3(x,y,z); +} + +#ifdef CGAL_LINKED_WITH_TBB +//functor for tbb parallelization +template +class FillGridSize { + std::size_t grid_size; + Point_distance (&distance_function)[100][100]; + FT diag; + FT& max_distance_function; + QMap *trees; + bool is_signed; + qglviewer::ManipulatedFrame* frame; +public: + FillGridSize(std::size_t grid_size, FT diag, Point_distance (&distance_function)[100][100], + FT& max_distance_function,QMap* trees, + bool is_signed, qglviewer::ManipulatedFrame* frame) + : grid_size(grid_size), distance_function (distance_function), diag(diag), + max_distance_function(max_distance_function), + trees(trees), is_signed(is_signed), frame(frame) + { + } + void operator()(const tbb::blocked_range& r) const + { + const GLdouble* m = frame->matrix(); + Simple_kernel::Aff_transformation_3 transfo = Simple_kernel::Aff_transformation_3 (m[0], m[4], m[8], m[12], + m[1], m[5], m[9], m[13], + m[2], m[6], m[10], m[14]); + const FT dx = 2*diag; + const FT dy = 2*diag; + const FT z (0); + const FT fd = FT(1); + Tree *min_tree = NULL ; + for( std::size_t t = r.begin(); t != r.end(); ++t) + { + int i(t%grid_size), j(t/grid_size); + FT x = -diag/fd + FT(i)/FT(grid_size) * dx; + { + FT y = -diag/fd + FT(j)/FT(grid_size) * dy; + + Point query = transfo( Point(x,y,z) ); + FT min = DBL_MAX; + + Q_FOREACH(Tree *tree, trees->values()) + { + FT dist = CGAL::sqrt( tree->squared_distance(query) ); + if(dist < min) + { + min = dist; + if(is_signed) + min_tree = tree; + } + } + distance_function[i][j] = Point_distance(query,min); + max_distance_function = (std::max)(min, max_distance_function); + + if(is_signed) + { + typedef typename Tree::size_type size_type; + Simple_kernel::Vector_3 random_vec = random_vector(); + + const Simple_kernel::Point_3& p = distance_function[i][j].first; + const FT unsigned_distance = distance_function[i][j].second; + + // get sign through ray casting (random vector) + Simple_kernel::Ray_3 ray(p, random_vec); + size_type nbi = min_tree->number_of_intersected_primitives(ray); + + FT sign ( (nbi&1) == 0 ? 1 : -1); + distance_function[i][j].second = sign * unsigned_distance; + } + } + } + } +}; +#endif + +const int slow_distance_grid_size = 100; +const int fast_distance_grid_size = 20; +class Texture{ +private: + int Width; + int Height; + int size; + GLubyte *data; +public: + Texture(int w, int h) + { + Width = w; + Height = h; + size = 3*Height*Width; + data = new GLubyte[Height*Width*3]; + } + int getWidth() const {return Width;} + int getHeight() const {return Height;} + int getSize() const {return size;} + void setData(int i, int j, int r, int g, int b){ + data[3*(Width*j+i) + 0] = r; + data[3*(Width*j+i) + 1] = g; + data[3*(Width*j+i) + 2] = b; + } + + GLubyte* getData(){return data; } + +}; +typedef CGAL::Simple_cartesian Simple_kernel; + +//typedef CGAL::Exact_predicates_inexact_constructions_kernel Simple_kernel; +struct PPMAP +{ + typedef boost::readable_property_map_tag category; + typedef Simple_kernel::Point_3 value_type; + typedef const Simple_kernel::Point_3& reference; + typedef boost::graph_traits::vertex_descriptor key_type; + friend reference get(const PPMAP&, key_type v) + { + return reinterpret_cast(v->point()); + } +}; + +typedef CGAL::AABB_face_graph_triangle_primitive Facet_primitive; +typedef CGAL::AABB_traits Facet_traits; +typedef CGAL::AABB_tree Facet_tree; + +typedef CGAL::AABB_halfedge_graph_segment_primitive Edge_primitive; +typedef CGAL::AABB_traits Edge_traits; +typedef CGAL::AABB_tree Edge_tree; + + +typedef QMap Facet_trees; +typedef QMap Edge_trees; -typedef CGAL::AABB_face_graph_triangle_primitive AABB_primitive; -typedef CGAL::AABB_traits AABB_traits; -typedef CGAL::AABB_tree AABB_tree; class Q_DECL_EXPORT Scene_aabb_item : public CGAL::Three::Scene_item { Q_OBJECT public: - Scene_aabb_item(const AABB_tree& tree_) : CGAL::Three::Scene_item(1,1), tree(tree_) + Scene_aabb_item(const Facet_tree& tree_) : CGAL::Three::Scene_item(1,1), tree(tree_) { positions_lines.resize(0); invalidateOpenGLBuffers(); @@ -87,10 +246,9 @@ public: { computeElements(); are_buffers_filled = false; - compute_bbox(); } public: - const AABB_tree& tree; + const Facet_tree& tree; private: mutable std::vector positions_lines; @@ -119,7 +277,7 @@ private: { positions_lines.clear(); - CGAL::AABB_drawing_traits > traits; + CGAL::AABB_drawing_traits > traits; traits.v_edges = &positions_lines; tree.traversal(0, traits); @@ -208,7 +366,7 @@ public: } public: - std::vector edges; + std::vector edges; private: mutable std::vector positions_lines; @@ -239,8 +397,8 @@ private: for(size_t i = 0, end = edges.size(); i < end; ++i) { - const Epic_kernel::Point_3& a = edges[i].source(); - const Epic_kernel::Point_3& b = edges[i].target(); + const Simple_kernel::Point_3& a = edges[i].source(); + const Simple_kernel::Point_3& b = edges[i].target(); positions_lines.push_back(a.x()); positions_lines.push_back(a.y()); positions_lines.push_back(a.z()); positions_lines.push_back(b.x()); positions_lines.push_back(b.y()); positions_lines.push_back(b.z()); } @@ -262,6 +420,484 @@ private: }; // end class Scene_edges_item +class Q_DECL_EXPORT Scene_aabb_plane_item : public Scene_plane_item +{ + Q_OBJECT + +public: + + typedef Simple_kernel::FT FT; + enum Cut_planes_types { + UNSIGNED_FACETS = 0, SIGNED_FACETS, UNSIGNED_EDGES, CUT_SEGMENTS + }; + Scene_aabb_plane_item(const CGAL::Three::Scene_interface* scene_interface) + :Scene_plane_item(scene_interface) + { + for(int i=0; icreate(); + } + for(int i=0; icompileSourceCode(tex_vertex_source)) + { + std::cerr<<"Compiling vertex source FAILED"<compileSourceCode(tex_fragment_source)) + { + std::cerr<<"Compiling fragmentsource FAILED"<addShader(tex_vertex_shader)) + { + std::cerr<<"adding vertex shader FAILED"<addShader(tex_fragment_shader)) + { + std::cerr<<"adding fragment shader FAILED"<link()) + { + std::cerr<<"linking Program FAILED"<facet_trees = facet_trees; + } + + void set_edge_trees(Edge_trees *edge_trees) + { + this->edge_trees = edge_trees; + } + void draw(CGAL::Three::Viewer_interface* viewer) const + { + if(!are_buffers_filled) + initializeBuffers(viewer); + QMatrix4x4 fMatrix; + fMatrix.setToIdentity(); + for(int i=0; i< 16 ; i++) + fMatrix.data()[i] = frame->matrix()[i]; + + switch( m_cut_plane ) + { + case UNSIGNED_EDGES: + case UNSIGNED_FACETS: + case SIGNED_FACETS: + + viewer->glActiveTexture(GL_TEXTURE0); + viewer->glBindTexture(GL_TEXTURE_2D, textureId); + + vaos[TexturedCutplane]->bind(); + + attribTexBuffers(viewer); + + tex_rendering_program->bind(); + tex_rendering_program->setUniformValue("f_matrix", fMatrix); + viewer->glDrawArrays(GL_TRIANGLES, 0,static_cast(positions_quad.size()/3)); + tex_rendering_program->release(); + vaos[TexturedCutplane]->release(); + break; + + case CUT_SEGMENTS: + vaos[Facets]->bind(); + program = getShaderProgram(PROGRAM_NO_SELECTION, viewer); + attribBuffers(viewer, PROGRAM_NO_SELECTION); + program->bind(); + program->setUniformValue("f_matrix", fMatrix); + program->setAttributeValue("colors", this->color()); + viewer->glDrawArrays(GL_TRIANGLES, 0,static_cast(positions_quad.size()/3)); + + program->release(); + vaos[Facets]->release(); + break; + } + } + void drawEdges(CGAL::Three::Viewer_interface *viewer) const + { + if(m_cut_plane != CUT_SEGMENTS) + return; + QMatrix4x4 fMatrix; + fMatrix.setToIdentity(); + for(int i=0; i< 16 ; i++) + fMatrix.data()[i] = frame->matrix()[i]; + vaos[Edges]->bind(); + program = getShaderProgram(PROGRAM_NO_SELECTION, viewer); + attribBuffers(viewer, PROGRAM_NO_SELECTION); + program->bind(); + program->setUniformValue("f_matrix", fMatrix); + program->setAttributeValue("colors", QColor(Qt::black)); + viewer->glDrawArrays(GL_LINES, 0,static_cast(positions_lines.size()/3)); + program->release(); + vaos[Edges]->release(); + } + + void invalidateOpenGLBuffers() + { + computeElements(); + are_buffers_filled = false; + } + + void set_fast_distance(bool b)const { m_fast_distance = b; update_grid_size(); } + void setCutPlaneType(Cut_planes_types type){ m_cut_plane = type;} + Cut_planes_types cutPlaneType()const {return m_cut_plane;} +private: + Edge_trees* edge_trees; + Facet_trees* facet_trees; + enum VAOs{ + Facets = 0, + Edges, + TexturedCutplane, + NbVaos + }; + enum VBOs{ + Facets_vertices = 0, + Edges_vertices, + UVCoords, + NbVbos + }; + typedef std::pair Point_distance; + std::vector vaos; + mutable int m_grid_size; + mutable bool m_fast_distance; + mutable QOpenGLShaderProgram* tex_rendering_program; + mutable Point_distance m_distance_function[100][100]; + mutable GLuint textureId; + mutable Texture *texture; + // An aabb_tree indexing polyhedron facets/segments + mutable Color_ramp m_red_ramp; + mutable Color_ramp m_blue_ramp; + mutable Color_ramp m_thermal_ramp; + mutable Simple_kernel::FT m_max_distance_function; + mutable std::vector tex_map; + mutable Cut_planes_types m_cut_plane; + mutable std::vector buffers; + + template + void compute_distance_function(QMap *trees, bool is_signed = false)const + { + + m_max_distance_function = FT(0); + FT diag = scene_diag(); +#ifndef CGAL_LINKED_WITH_TBB + const GLdouble* m = frame->matrix(); + Simple_kernel::Aff_transformation_3 t = Simple_kernel::Aff_transformation_3 (m[0], m[4], m[8], m[12], + m[1], m[5], m[9], m[13], + m[2], m[6], m[10], m[14]); + const FT dx = 2*diag; + const FT dy = 2*diag; + const FT z (0); + const FT fd = FT(1); + Tree *min_tree = NULL; + for(int i=0 ; ivalues()) + { + FT dist = CGAL::sqrt( tree->squared_distance(query) ); + if(dist < min) + { + min = dist; + if(is_signed) + min_tree = tree; + } + } + m_distance_function[i][j] = Point_distance(query,min); + m_max_distance_function = (std::max)(min, m_max_distance_function); + } + } + if(is_signed) + { + for(int i=0 ; inumber_of_intersected_primitives(ray); + + FT sign ( (nbi&1) == 0 ? 1 : -1); + m_distance_function[i][j].second = sign * unsigned_distance; + } + } +#else + FillGridSize f(m_grid_size, diag, m_distance_function, m_max_distance_function, trees, is_signed, frame); + tbb::parallel_for(tbb::blocked_range(0, m_grid_size*m_grid_size), f); +#endif + } + + void compute_texture(int i, int j,Color_ramp pos_ramp ,Color_ramp neg_ramp)const + { + const FT& d00 = m_distance_function[i][j].second; + // determines grey level + FT i00 = (double)std::fabs(d00) / m_max_distance_function; + + if(d00 > 0.0) + texture->setData(i,j,255*pos_ramp.r(i00),255*pos_ramp.g(i00),255*pos_ramp.b(i00)); + else + texture->setData(i,j,255*neg_ramp.r(i00),255*neg_ramp.g(i00),255*neg_ramp.b(i00)); + + + } + +#ifdef CGAL_LINKED_WITH_TBB + class FillTexture + { + std::size_t grid_size; + Color_ramp pos_ramp; + Color_ramp neg_ramp; + Scene_aabb_plane_item* item; + public : + FillTexture(std::size_t grid_size, + Color_ramp pos_ramp, + Color_ramp neg_ramp, + Scene_aabb_plane_item* item + ) + :grid_size(grid_size), pos_ramp(pos_ramp), neg_ramp(neg_ramp), item(item) {} + + void operator()(const tbb::blocked_range& r) const + { + for(std::size_t t = r.begin(); t!= r.end(); ++t) + { + int i(t%grid_size), j(t/grid_size); + item->compute_texture(i,j, pos_ramp, neg_ramp); + } + } + }; +#endif + + void computeElements() + { + switch(m_cut_plane) + { + case UNSIGNED_FACETS: + if ( facet_trees->empty() ) { return; } + compute_distance_function(facet_trees); + break; + case SIGNED_FACETS: + if ( facet_trees->empty() ) { return; } + compute_distance_function(facet_trees, true); + + break; + case UNSIGNED_EDGES: + if ( edge_trees->empty() ) { return; } + compute_distance_function(edge_trees); + break; + default: + break; + } + //The texture + switch(m_cut_plane) + { + case SIGNED_FACETS: + { +#ifndef CGAL_LINKED_WITH_TBB + for( int i=0 ; i < texture->getWidth(); i++ ) + { + for( int j=0 ; j < texture->getHeight() ; j++) + { + compute_texture(i,j,m_red_ramp,m_blue_ramp); + } + } +#else + FillTexture f(m_grid_size, m_red_ramp, m_blue_ramp, this); + tbb::parallel_for(tbb::blocked_range(0, m_grid_size * m_grid_size), f); +#endif + break; + } + case UNSIGNED_FACETS: + case UNSIGNED_EDGES: + { + #ifndef CGAL_LINKED_WITH_TBB + for( int i=0 ; i < texture->getWidth(); i++ ) + { + for( int j=0 ; j < texture->getHeight() ; j++) + { + compute_texture(i,j,m_thermal_ramp,m_thermal_ramp); + } + } +#else + FillTexture f(m_grid_size, m_thermal_ramp, m_thermal_ramp, this); + tbb::parallel_for(tbb::blocked_range(0, m_grid_size * m_grid_size), f); +#endif + break; + } + default: + break; + } + } + + void initializeBuffers(CGAL::Three::Viewer_interface *viewer) const + { + if(GLuint(-1) == textureId) { + viewer->glGenTextures(1, &textureId); + } + + //vaos for the basic cutting plane + { + program = getShaderProgram(PROGRAM_NO_SELECTION, viewer); + program->bind(); + vaos[Facets]->bind(); + + buffers[Facets_vertices].bind(); + buffers[Facets_vertices].allocate(positions_quad.data(), + static_cast(positions_quad.size()*sizeof(float))); + program->enableAttributeArray("vertex"); + program->setAttributeBuffer("vertex",GL_FLOAT,0,3); + buffers[Facets_vertices].release(); + vaos[Facets]->release(); + + + vaos[Edges]->bind(); + buffers[Edges_vertices].bind(); + buffers[Edges_vertices].allocate(positions_lines.data(), + static_cast(positions_lines.size()*sizeof(float))); + program->enableAttributeArray("vertex"); + program->setAttributeBuffer("vertex",GL_FLOAT,0,3); + buffers[Edges_vertices].release(); + vaos[Edges]->release(); + + + program->release(); + } + //vao for the textured cutting planes + { + tex_rendering_program->bind(); + vaos[TexturedCutplane]->bind(); + buffers[Facets_vertices].bind(); + tex_rendering_program->enableAttributeArray("vertex"); + tex_rendering_program->setAttributeBuffer("vertex",GL_FLOAT,0,3); + buffers[Facets_vertices].release(); + + buffers[UVCoords].bind(); + buffers[UVCoords].allocate(tex_map.data(), static_cast(tex_map.size()*sizeof(float))); + tex_rendering_program->attributeLocation("tex_coord"); + tex_rendering_program->setAttributeBuffer("tex_coord",GL_FLOAT,0,2); + tex_rendering_program->enableAttributeArray("tex_coord"); + buffers[UVCoords].release(); + + viewer->glBindTexture(GL_TEXTURE_2D, textureId); + viewer->glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGB, + texture->getWidth(), + texture->getHeight(), + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + texture->getData()); + viewer->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + viewer->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + viewer->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE ); + viewer->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE ); + tex_rendering_program->release(); + } + are_buffers_filled = true; + } + + void attribTexBuffers(CGAL::Three::Viewer_interface* viewer)const + { + QMatrix4x4 mvpMatrix; + double mat[16]; + viewer->camera()->getModelViewProjectionMatrix(mat); + for(int i=0; i < 16; i++) + { + mvpMatrix.data()[i] = (float)mat[i]; + } + tex_rendering_program->bind(); + tex_rendering_program->setUniformValue("mvp_matrix", mvpMatrix); + tex_rendering_program->release(); + } +}; using namespace CGAL::Three; class Polyhedron_demo_cut_plugin : public QObject, @@ -337,40 +973,121 @@ public: Messages_interface* m); QList actions() const; + bool eventFilter(QObject *, QEvent *event) + { + if(!plane_item) + return false; + if(event->type() == QEvent::MouseButtonPress) + { + QMouseEvent * mevent = static_cast(event); + if ( mevent->modifiers() == Qt::ControlModifier ) + { + plane_item->set_fast_distance(true); + plane_item->invalidateOpenGLBuffers(); + plane_item->itemChanged(); + } + } + else if(event->type() == QEvent::MouseButtonRelease) + { + QMouseEvent * mevent = static_cast(event); + if ( mevent->modifiers() == Qt::ControlModifier ) + { + plane_item->set_fast_distance(false); + plane_item->invalidateOpenGLBuffers(); + plane_item->itemChanged(); + } + } + return false; + } + public Q_SLOTS: void updateCutPlane() { + if(plane_item->manipulatedFrame()->isSpinning()) + plane_item->set_fast_distance(true); ready_to_cut = true; QTimer::singleShot(0,this,SLOT(cut())); } - void createCutPlane(); - void enableAction(); void cut(); + void computeIntersection(); void reset_edges() { edges_item = 0; } - + void Intersection(); + void SignedFacets(); + void UnsignedFacets(); + void UnsignedEdges(); + void resetPlane() + { + plane_item = NULL; + } + void uncheckActions() + { + Q_FOREACH(QAction* action, _actions) + if(action->isChecked()) + { + action->setChecked(false); + return; + } + } + void deleteTrees(CGAL::Three::Scene_item* sender) + { + Scene_polyhedron_item* item = qobject_cast(sender); + if(!item) + return; + if(facet_trees.keys().contains(item)) + { + delete facet_trees[item]; + facet_trees.remove(item); + } + if(edge_trees.keys().contains(item)) + { + delete edge_trees[item]; + edge_trees.remove(item); + } + if(facet_trees.empty()) + { + if(plane_item) + scene->erase(scene->item_id(plane_item)); + if(edges_item) + scene->erase(scene->item_id(edges_item)); + } + else + { + ready_to_cut = true; + cut(); + } + } + void updateTrees(int id); private: + QList_actions; + void createCutPlane(); CGAL::Three::Scene_interface* scene; Messages_interface* messages; - Scene_plane_item* plane_item; + Scene_aabb_plane_item* plane_item; Scene_edges_item* edges_item; - QAction* actionCreateCutPlane; - bool ready_to_cut; + QAction* actionIntersection; + QAction* actionSignedFacets; + QAction* actionUnsignedFacets; + QAction* actionUnsignedEdges; - typedef std::map Trees; - Trees trees; + bool ready_to_cut; + Facet_trees facet_trees; + Edge_trees edge_trees; }; // end Polyhedron_demo_cut_plugin Polyhedron_demo_cut_plugin::~Polyhedron_demo_cut_plugin() { - for ( Trees::iterator it = trees.begin(), end = trees.end() ; - it != end ; ++it) + Q_FOREACH(Facet_tree *tree, facet_trees.values()) { - delete it->second; + delete tree; } + Q_FOREACH(Edge_tree *tree, edge_trees.values()) + { + delete tree; + } } @@ -380,35 +1097,96 @@ void Polyhedron_demo_cut_plugin::init(QMainWindow* mainWindow, { scene = scene_interface; messages = m; - actionCreateCutPlane = new QAction(tr("Create Cutting Plane"), mainWindow); - actionCreateCutPlane->setProperty("subMenuName","3D Fast Intersection and Distance Computation"); + actionIntersection = new QAction(tr("Cut Segments"), mainWindow); + actionSignedFacets = new QAction(tr("Signed Distance Function to Facets"), mainWindow); + actionUnsignedFacets= new QAction(tr("Unsigned Distance Function to Facets"), mainWindow); + actionUnsignedEdges = new QAction(tr("Unsigned Distance Function to Edges"), mainWindow); + + actionIntersection->setProperty("subMenuName","3D Fast Intersection and Distance Computation"); + actionSignedFacets->setProperty("subMenuName","3D Fast Intersection and Distance Computation"); + actionUnsignedFacets->setProperty("subMenuName","3D Fast Intersection and Distance Computation"); + actionUnsignedEdges->setProperty("subMenuName","3D Fast Intersection and Distance Computation"); + ready_to_cut = true; - connect(actionCreateCutPlane, SIGNAL(triggered()), - this, SLOT(createCutPlane())); + connect(actionIntersection, SIGNAL(triggered()), + this, SLOT(Intersection())); + connect(actionSignedFacets, SIGNAL(triggered()), + this, SLOT(SignedFacets())); + connect(actionUnsignedFacets, SIGNAL(triggered()), + this, SLOT(UnsignedFacets())); + connect(actionUnsignedEdges, SIGNAL(triggered()), + this, SLOT(UnsignedEdges())); + plane_item = NULL; + Scene* real_scene = static_cast(scene); + connect(real_scene, SIGNAL(itemAboutToBeDestroyed(CGAL::Three::Scene_item*)), + this, SLOT(deleteTrees(CGAL::Three::Scene_item*))); + connect(real_scene, SIGNAL(newItem(int)), + this, SLOT(updateTrees(int))); + + QGLViewer* viewer = *QGLViewer::QGLViewerPool().begin(); + viewer->installEventFilter(this); + + _actions << actionIntersection + << actionSignedFacets + << actionUnsignedFacets + << actionUnsignedEdges; + QActionGroup *group = new QActionGroup(mainWindow); + group->setExclusive(true); + + Q_FOREACH(QAction *action, _actions) + { + action->setActionGroup(group); + action->setCheckable(true); + } + } QList Polyhedron_demo_cut_plugin::actions() const { - return QList() << actionCreateCutPlane; + return _actions; +} + +void Polyhedron_demo_cut_plugin::updateTrees(int id) +{ +if(plane_item && + qobject_cast(scene->item(id))) + createCutPlane(); } void Polyhedron_demo_cut_plugin::createCutPlane() { - plane_item = new Scene_plane_item(scene); + bool updating = false; + Scene_aabb_plane_item::Cut_planes_types type; + int plane_id = -1; + if(plane_item) + updating = true; + if(updating) + { + type = plane_item->cutPlaneType(); + plane_id = scene->item_id(plane_item); + } + + plane_item = new Scene_aabb_plane_item(scene); const CGAL::Three::Scene_interface::Bbox& bbox = scene->bbox(); plane_item->setPosition((bbox.xmin()+bbox.xmax())/2.f, (bbox.ymin()+bbox.ymax())/2.f, (bbox.zmin()+bbox.zmax())/2.f); plane_item->setNormal(0., 0., 1.); - connect(plane_item, SIGNAL(destroyed()), - this, SLOT(enableAction())); plane_item->setManipulatable(true); plane_item->setClonable(false); plane_item->setColor(Qt::green); plane_item->setName(tr("Cutting plane")); connect(plane_item->manipulatedFrame(), SIGNAL(modified()), this, SLOT(updateCutPlane())); - scene->addItem(plane_item); - actionCreateCutPlane->setEnabled(false); - + connect(plane_item, SIGNAL(aboutToBeDestroyed()), + this, SLOT(resetPlane())); + connect(plane_item, SIGNAL(aboutToBeDestroyed()), + this, SLOT(uncheckActions())); + if(updating) + { + scene->replaceItem(plane_id, plane_item)->deleteLater(); + plane_item->setCutPlaneType(type); + } + else + scene->addItem(plane_item); // Hide polyhedrons and call cut() (avoid that nothing shows up until user // decides to move the plane item) for(int i = 0, end = scene->numberOfEntries(); i < end; ++i) { @@ -417,11 +1195,87 @@ void Polyhedron_demo_cut_plugin::createCutPlane() { if ( NULL != poly_item ) poly_item->setVisible(false); } + //fills the tree maps + for(int i = 0, end = scene->numberOfEntries(); i < end; ++i) { + CGAL::Three::Scene_item* item = scene->item(i); + Scene_polyhedron_item* poly_item = qobject_cast(item); + if(!poly_item) continue; + + if(facet_trees.find(poly_item) == facet_trees.end()) { + facet_trees[poly_item] = new Facet_tree(); + PPMAP pmap; + facet_trees[poly_item]->insert(faces(*(poly_item->polyhedron())).first, + faces(*(poly_item->polyhedron())).second, + *poly_item->polyhedron(), + pmap ); + Scene_aabb_item* aabb_item = new Scene_aabb_item(*facet_trees[poly_item]); + aabb_item->setName(tr("AABB tree of %1").arg(poly_item->name())); + aabb_item->setRenderingMode(Wireframe); + aabb_item->setColor(Qt::black); + aabb_item->setVisible(false); + scene->addItem(aabb_item); + } + if(edge_trees.find(poly_item) == edge_trees.end()) { + edge_trees[poly_item] = new Edge_tree(); + PPMAP pmap; + edge_trees[poly_item]->insert(edges(*poly_item->polyhedron()).first, + edges(*poly_item->polyhedron()).second, + *poly_item->polyhedron(), + pmap); + } + } + plane_item->set_facet_trees(&facet_trees); + plane_item->set_edge_trees(&edge_trees); + ready_to_cut = true; cut(); } +void Polyhedron_demo_cut_plugin::Intersection() +{ + if(!plane_item) + createCutPlane(); + plane_item->setCutPlaneType(Scene_aabb_plane_item::CUT_SEGMENTS); + computeIntersection(); + plane_item->invalidateOpenGLBuffers(); +} -void Polyhedron_demo_cut_plugin::cut() { +void Polyhedron_demo_cut_plugin::SignedFacets() { + if(!plane_item) + createCutPlane(); + plane_item->setCutPlaneType(Scene_aabb_plane_item::SIGNED_FACETS); + plane_item->invalidateOpenGLBuffers(); + if(edges_item) + { + scene->erase(scene->item_id(edges_item)); + edges_item = NULL; + } + +} +void Polyhedron_demo_cut_plugin::UnsignedFacets() { + if(!plane_item) + createCutPlane(); + plane_item->setCutPlaneType(Scene_aabb_plane_item::UNSIGNED_FACETS); + plane_item->invalidateOpenGLBuffers(); + if(edges_item) + { + scene->erase(scene->item_id(edges_item)); + edges_item = NULL; + } +} +void Polyhedron_demo_cut_plugin::UnsignedEdges() { + if(!plane_item) + createCutPlane(); + plane_item->setCutPlaneType(Scene_aabb_plane_item::UNSIGNED_EDGES); + plane_item->invalidateOpenGLBuffers(); + if(edges_item) + { + scene->erase(scene->item_id(edges_item)); + edges_item = NULL; + } +} + +void Polyhedron_demo_cut_plugin::computeIntersection() +{ QApplication::setOverrideCursor(Qt::WaitCursor); if(!edges_item) { edges_item = new Scene_edges_item; @@ -431,63 +1285,62 @@ void Polyhedron_demo_cut_plugin::cut() { this, SLOT(reset_edges())); scene->addItem(edges_item); } - if(ready_to_cut) - { + const qglviewer::Vec& pos = plane_item->manipulatedFrame()->position(); const qglviewer::Vec& n = - plane_item->manipulatedFrame()->inverseTransformOf(qglviewer::Vec(0.f, 0.f, 1.f)); - Epic_kernel::Plane_3 plane(n[0], n[1], n[2], - n * pos); + plane_item->manipulatedFrame()->inverseTransformOf(qglviewer::Vec(0.f, 0.f, 1.f)); + Simple_kernel::Plane_3 plane(n[0], n[1], n[2], - n * pos); //std::cerr << plane << std::endl; edges_item->edges.clear(); QTime time; time.start(); - for(int i = 0, end = scene->numberOfEntries(); i < end; ++i) { - CGAL::Three::Scene_item* item = scene->item(i); - Scene_polyhedron_item* poly_item = qobject_cast(item); - if(!poly_item) continue; - Trees::iterator it = trees.find(poly_item); - if(it == trees.end()) { - it = trees.insert(trees.begin(), - std::make_pair(poly_item, - new AABB_tree(faces(*(poly_item->polyhedron())).first, - faces(*(poly_item->polyhedron())).second, - *poly_item->polyhedron() ))); - Scene_aabb_item* aabb_item = new Scene_aabb_item(*it->second); - aabb_item->setName(tr("AABB tree of %1").arg(poly_item->name())); - aabb_item->setRenderingMode(Wireframe); - aabb_item->setColor(Qt::black); - aabb_item->setVisible(false); - scene->addItem(aabb_item); - //std::cerr << "size: " << it->second->size() << std::endl; - } - - if(!CGAL::do_intersect(plane, it->second->bbox())) + bool does_intersect = false; + for(Facet_trees::iterator it = facet_trees.begin(); it != facet_trees.end(); ++it) + { + if(!CGAL::do_intersect(plane, it.value()->bbox())) continue; - - std::vector intersections; - it->second->all_intersections(plane, std::back_inserter(intersections)); - - for ( std::vector::iterator it = intersections.begin(), - end = intersections.end() ; it != end ; ++it ) + does_intersect = true; + std::vector intersections; + it.value()->all_intersections(plane, std::back_inserter(intersections)); + + for ( std::vector::iterator it = intersections.begin(), + end = intersections.end() ; it != end ; ++it ) { - const Epic_kernel::Segment_3* inter_seg = - CGAL::object_cast(&(it->first)); - + const Simple_kernel::Segment_3* inter_seg = + CGAL::object_cast(&(it->first)); + if ( NULL != inter_seg ) edges_item->edges.push_back(*inter_seg); } - ready_to_cut = false; } - - messages->information(QString("cut (%1 ms). %2 edges.").arg(time.elapsed()).arg(edges_item->edges.size())); + if(does_intersect) + messages->information(QString("cut (%1 ms). %2 edges.").arg(time.elapsed()).arg(edges_item->edges.size())); edges_item->invalidateOpenGLBuffers(); - scene->itemChanged(edges_item); - } + edges_item->itemChanged(); + ready_to_cut = false; QApplication::restoreOverrideCursor(); } -void Polyhedron_demo_cut_plugin::enableAction() { - actionCreateCutPlane->setEnabled(true); +void Polyhedron_demo_cut_plugin::cut() +{ + if(!plane_item) + return; + switch(plane_item->cutPlaneType()) + { + case Scene_aabb_plane_item::CUT_SEGMENTS: + if(ready_to_cut) + { + computeIntersection(); + } + break; + default: + if(ready_to_cut) + { + ready_to_cut = false; + plane_item->invalidateOpenGLBuffers(); + } + } } + #include "Cut_plugin.moc" diff --git a/Polyhedron/demo/Polyhedron/Scene_plane_item.cpp b/Polyhedron/demo/Polyhedron/Scene_plane_item.cpp index 9448b5f4ffc..82e61b06f54 100644 --- a/Polyhedron/demo/Polyhedron/Scene_plane_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_plane_item.cpp @@ -2,32 +2,6 @@ using namespace CGAL::Three; -struct Scene_plane_item_priv -{ - Scene_plane_item_priv(Scene_plane_item* parent) - { - item = parent; - } - - ~Scene_plane_item_priv() { - } - - double scene_diag() const { - const Scene_item::Bbox& bbox = item->scene->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_plane_item* item; - -}; - Scene_plane_item::Scene_plane_item(const CGAL::Three::Scene_interface* scene_interface) :CGAL::Three::Scene_item(NbOfVbos,NbOfVaos), @@ -37,13 +11,11 @@ Scene_plane_item::Scene_plane_item(const CGAL::Three::Scene_interface* scene_int frame(new ManipulatedFrame()) { setNormal(0., 0., 1.); - d = new Scene_plane_item_priv(this); //Generates an integer which will be used as ID for each buffer invalidateOpenGLBuffers(); } Scene_plane_item::~Scene_plane_item() { delete frame; - delete d; } void Scene_plane_item::initializeBuffers(Viewer_interface *viewer) const @@ -75,12 +47,12 @@ void Scene_plane_item::initializeBuffers(Viewer_interface *viewer) const } -void Scene_plane_item::compute_normals_and_vertices(void) +void Scene_plane_item::compute_normals_and_vertices(void) const { positions_quad.resize(0); positions_lines.resize(0); - const double diag = d->scene_diag(); + const double diag = scene_diag(); //The quad { @@ -94,11 +66,11 @@ void Scene_plane_item::compute_normals_and_vertices(void) positions_quad.push_back(-diag); positions_quad.push_back(0.0); - positions_quad.push_back(-diag); positions_quad.push_back(diag); + positions_quad.push_back(-diag); positions_quad.push_back(0.0); - positions_quad.push_back(diag); positions_quad.push_back(-diag); + positions_quad.push_back(diag); positions_quad.push_back(0.0); positions_quad.push_back(diag); positions_quad.push_back(diag); diff --git a/Polyhedron/demo/Polyhedron/Scene_plane_item.h b/Polyhedron/demo/Polyhedron/Scene_plane_item.h index 22c287906fa..321ab2eb4b2 100644 --- a/Polyhedron/demo/Polyhedron/Scene_plane_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_plane_item.h @@ -17,7 +17,6 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel_epic; typedef Kernel_epic::Plane_3 Plane_3; -struct Scene_plane_item_priv; class SCENE_BASIC_OBJECTS_EXPORT Scene_plane_item : public CGAL::Three::Scene_item { @@ -28,6 +27,16 @@ public: Scene_plane_item(const CGAL::Three::Scene_interface* scene_interface); ~Scene_plane_item(); + double scene_diag() const { + const Scene_item::Bbox& bbox = scene->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; + } bool isFinite() const { return false; } bool isEmpty() const { return false; } void compute_bbox() const { _bbox = Bbox(); } @@ -61,9 +70,6 @@ public Q_SLOTS: void setManipulatable(bool b = true); protected: - friend struct Scene_plane_item_priv; - Scene_plane_item_priv* d; - const CGAL::Three::Scene_interface* scene; bool manipulable; @@ -88,7 +94,7 @@ protected: mutable QOpenGLShaderProgram *program; void initializeBuffers(CGAL::Three::Viewer_interface*)const; - void compute_normals_and_vertices(void); + void compute_normals_and_vertices(void) const; mutable bool are_buffers_filled; }; diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp index 799e24ca464..be8e7662c87 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp @@ -1272,7 +1272,7 @@ Scene_polyhedron_item::select(double orig_x, typedef Input_facets_AABB_tree Tree; typedef Tree::Object_and_primitive_id Object_and_primitive_id; - Tree* aabb_tree = static_cast(d->get_aabb_tree()); + Tree* aabb_tree = static_cast(d->get_aabb_tree()); if(aabb_tree) { const Kernel::Point_3 ray_origin(orig_x, orig_y, orig_z); @@ -1756,3 +1756,4 @@ bool Scene_polyhedron_item::triangulated(){return d->poly->is_pure_triangle();} bool Scene_polyhedron_item::self_intersected(){return !(d->self_intersect);} void Scene_polyhedron_item::setItemIsMulticolor(bool b){ d->is_multicolor = b;} bool Scene_polyhedron_item::isItemMulticolor(){ return d->is_multicolor;} +