1 
2 #include <fstream>
3 #include <QtCore/qglobal.h>
4 #include <CGAL/intersections.h>
5 
6 #include "Scene.h"
7 #include "Color_ramp.h"
8 #include "Messages_interface.h"
9 #include "Scene_plane_item.h"
10 #include "Scene_surface_mesh_item.h"
11 #include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
12 #include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
13 #include <CGAL/Three/Scene_interface.h>
14 #include <CGAL/Three/Scene_item_rendering_helper.h>
15 #include <CGAL/Three/Viewer_interface.h>
16 #include <CGAL/Three/Three.h>
17 #include <CGAL/Three/Triangle_container.h>
18 #include <CGAL/Three/Edge_container.h>
19 
20 #include <CGAL/AABB_tree.h>
21 #include <CGAL/AABB_traits.h>
22 #include <CGAL/AABB_face_graph_triangle_primitive.h>
23 #include <CGAL/AABB_halfedge_graph_segment_primitive.h>
24 #include <CGAL/internal/AABB_tree/AABB_drawing_traits.h>
25 //#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
26 #include <CGAL/Simple_cartesian.h>
27 
28 #include <CGAL/bounding_box.h>
29 
30 #include <QElapsedTimer>
31 
32 #include <QAction>
33 #include <QMainWindow>
34 #include <QApplication>
35 #include <CGAL/Three/Scene_item.h>
36 #include <QMouseEvent>
37 #include <QWidgetAction>
38 #include <QMenu>
39 
40 #ifdef CGAL_LINKED_WITH_TBB
41 #include <tbb/parallel_for.h>
42 #include <tbb/blocked_range.h>
43 #include <tbb/scalable_allocator.h>
44 #else
45   struct HackRange{
HackRangeHackRange46     HackRange(const std::size_t& first, const std::size_t& last)
47       :first(first), last(last)
48     {}
beginHackRange49     std::size_t begin() const{ return first; }
endHackRange50     std::size_t end() const{ return last; }
51   private:
52     std::size_t first;
53     std::size_t last;
54   };
55 #endif // CGAL_LINKED_WITH_TBB
56 #include <CGAL/Three/Three.h>
57 
58 using namespace CGAL::Three;
59 typedef Edge_container Ec;
60 typedef Triangle_container Tc;
61 typedef Viewer_interface Vi;
62 
63 typedef CGAL::Simple_cartesian<double> Simple_kernel;
64 typedef Simple_kernel::FT FT;
65 typedef Simple_kernel::Point_3 Point;
66 typedef std::pair<Point,FT> Point_distance;
67 
68 
random_in(const double a,const double b)69 FT random_in(const double a,
70                     const double b)
71 {
72     double r = rand() / (double)RAND_MAX;
73     return (FT)(a + (b - a) * r);
74 }
75 
random_vector()76 Simple_kernel::Vector_3 random_vector()
77 {
78     FT x = random_in(0.0,1.0);
79     FT y = random_in(0.0,1.0);
80     FT z = random_in(0.0,1.0);
81     return Simple_kernel::Vector_3(x,y,z);
82 }
83 
84 
85 //functor for tbb parallelization
86 template <typename SM_Tree>
87 class FillGridSize {
88   std::size_t grid_size;
89   Point_distance (&distance_function)[100][100];
90   FT diag;
91   FT& max_distance_function;
92   std::vector<SM_Tree*>&sm_trees;
93   bool is_signed;
94   CGAL::qglviewer::ManipulatedFrame* frame;
95 public:
FillGridSize(std::size_t grid_size,FT diag,Point_distance (& distance_function)[100][100],FT & max_distance_function,std::vector<SM_Tree * > & sm_trees,bool is_signed,CGAL::qglviewer::ManipulatedFrame * frame)96   FillGridSize(std::size_t grid_size, FT diag, Point_distance (&distance_function)[100][100],
97   FT& max_distance_function, std::vector<SM_Tree*>& sm_trees,
98   bool is_signed, CGAL::qglviewer::ManipulatedFrame* frame)
99   : grid_size(grid_size), distance_function (distance_function), diag(diag),
100     max_distance_function(max_distance_function),
101     sm_trees(sm_trees), is_signed(is_signed), frame(frame)
102   {
103   }
104   template<typename Range>
operator ()(Range & r) const105   void operator()(Range& r) const
106   {
107     const GLdouble* m = frame->matrix();
108     Simple_kernel::Aff_transformation_3 transfo = Simple_kernel::Aff_transformation_3 (m[0], m[4], m[8], m[12],
109         m[1], m[5], m[9], m[13],
110         m[2], m[6], m[10], m[14]);
111     const FT dx = 2*diag;
112     const FT dy = 2*diag;
113     const FT z (0);
114     const FT fd =  FT(1);
115     SM_Tree *min_sm_tree = nullptr;
116     for( std::size_t t = r.begin(); t != r.end(); ++t)
117     {
118       int i = static_cast<int>(t%grid_size), j = static_cast<int>(t/grid_size);
119       FT x = -diag/fd + FT(i)/FT(grid_size) * dx;
120       {
121         FT y = -diag/fd + FT(j)/FT(grid_size) * dy;
122         const CGAL::qglviewer::Vec v_offset = Three::mainViewer()->offset();
123         Simple_kernel::Vector_3 offset(v_offset.x, v_offset.y, v_offset.z);
124         Point query = transfo( Point(x,y,z))-offset;
125         FT min = DBL_MAX;
126         Q_FOREACH(SM_Tree *tree, sm_trees)
127         {
128           FT dist = CGAL::sqrt( tree->squared_distance(query) );
129           if(dist < min)
130           {
131             min = dist;
132             if(is_signed)
133               min_sm_tree = tree;
134           }
135         }
136         distance_function[i][j] = Point_distance(query,min);
137         max_distance_function = (std::max)(min, max_distance_function);
138 
139 
140         if(is_signed)
141         {
142           if(!min_sm_tree)
143           {
144             distance_function[i][j] = Point_distance(query,DBL_MAX);
145             max_distance_function = DBL_MAX;//(std::max)(min, max_distance_function);
146             continue;
147           }
148           typedef typename SM_Tree::size_type size_type;
149           Simple_kernel::Vector_3 random_vec = random_vector();
150 
151           const Simple_kernel::Point_3& p = distance_function[i][j].first;
152           const FT unsigned_distance = distance_function[i][j].second;
153 
154           // get sign through ray casting (random vector)
155           Simple_kernel::Ray_3  ray(p, random_vec);
156           size_type nbi =  min_sm_tree->number_of_intersected_primitives(ray);
157 
158           FT sign ( (nbi&1) == 0 ? 1 : -1);
159           distance_function[i][j].second = sign * unsigned_distance;
160         }
161       }
162     }
163   }
164 };
165 
166 const int slow_distance_grid_size = 100;
167 const int fast_distance_grid_size = 20;
168 class Texture{
169 private:
170      int Width;
171      int Height;
172      int size;
173     GLubyte *data;
174 public:
Texture(int w,int h)175     Texture(int w, int h)
176     {
177         Width = w;
178         Height = h;
179         size = 3*Height*Width;
180         data = new GLubyte[Height*Width*3];
181     }
getWidth() const182     int getWidth() const {return Width;}
getHeight() const183     int getHeight() const {return Height;}
getSize() const184     int getSize() const {return size;}
setData(int i,int j,int r,int g,int b)185     void setData(int i, int j, int r, int g, int b){
186         data[3*(Width*j+i) + 0] = r;
187         data[3*(Width*j+i) + 1] = g;
188         data[3*(Width*j+i) + 2] = b;
189     }
190 
getData()191     GLubyte* getData(){return data; }
192 
193 };
194 typedef CGAL::Simple_cartesian<double> Simple_kernel;
195 
196 //typedef CGAL::Exact_predicates_inexact_constructions_kernel         Simple_kernel;
197 template< typename Mesh>
198 struct PPMAP
199 {
200   typedef boost::readable_property_map_tag category;
201   typedef Simple_kernel::Point_3 value_type;
202   typedef const Simple_kernel::Point_3& reference;
203   typedef typename boost::graph_traits<Mesh>::vertex_descriptor key_type;
204   typedef typename boost::property_map<Mesh, boost::vertex_point_t>::type VertexPointMap;
205 
206   Mesh* _mesh;
207   PPMAP<Mesh>()
208     :_mesh(nullptr){}
209   PPMAP<Mesh>(Mesh* mesh)
210     :_mesh(mesh)
211   {
212   }
213 
214 
215 
get(const PPMAP<Mesh> & ppmap,key_type v)216   friend reference get(const PPMAP<Mesh>&ppmap, key_type v)
217   {
218    VertexPointMap pmap = get(boost::vertex_point, *ppmap._mesh);
219     return reinterpret_cast<const Simple_kernel::Point_3&>(get(pmap, v));
220   }
221 };
222 
223 typedef CGAL::AABB_face_graph_triangle_primitive<SMesh, PPMAP<SMesh> > Facet_sm_primitive;
224 typedef CGAL::AABB_traits<Simple_kernel, Facet_sm_primitive>           Facet_sm_traits;
225 typedef CGAL::AABB_tree<Facet_sm_traits>                               Facet_sm_tree;
226 
227 typedef CGAL::AABB_halfedge_graph_segment_primitive<SMesh, PPMAP<SMesh> > Edge_sm_primitive;
228 typedef CGAL::AABB_traits<Simple_kernel, Edge_sm_primitive>              Edge_sm_traits;
229 typedef CGAL::AABB_tree<Edge_sm_traits>                                Edge_sm_tree;
230 
231 typedef QMap<QObject*, Facet_sm_tree*>                   Facet_sm_trees;
232 typedef QMap<QObject*, Edge_sm_tree*>                    Edge_sm_trees;
233 
234 
235 class Q_DECL_EXPORT Scene_aabb_plane_item : public Scene_plane_item
236 {
237   Q_OBJECT
238 
239 public:
240 
241   typedef Simple_kernel::FT                                                  FT;
242   enum Cut_planes_types {
243     UNSIGNED_FACETS = 0, SIGNED_FACETS, UNSIGNED_EDGES, CUT_SEGMENTS
244   };
Scene_aabb_plane_item(const CGAL::Three::Scene_interface * scene_interface)245   Scene_aabb_plane_item(const CGAL::Three::Scene_interface* scene_interface)
246     :Scene_plane_item(scene_interface)
247   {
248     m_grid_size = slow_distance_grid_size;
249     m_red_ramp.build_red();
250     m_blue_ramp.build_blue();
251     m_thermal_ramp.build_thermal();
252     setTriangleContainer(1, new Tc(Vi::PROGRAM_NO_SELECTION, false));
253     setTriangleContainer(0, new Tc(Vi::PROGRAM_WITH_TEXTURE, false));
254     setEdgeContainer(0, new Ec(Vi::PROGRAM_NO_SELECTION, false));
255     texture = new ::Texture(m_grid_size,m_grid_size);
256     getTriangleContainer(0)->setTextureSize(QSize(m_grid_size, m_grid_size));
257     for(auto v : CGAL::QGLViewer::QGLViewerPool())
258     {
259       CGAL::Three::Viewer_interface* viewer = static_cast<CGAL::Three::Viewer_interface*>(v);
260       initGL(viewer);
261     }
262     //UV Mapping
263     tex_map.push_back(0.0f);
264     tex_map.push_back(0.0f);
265 
266     tex_map.push_back(0.0f);
267     tex_map.push_back(1.0f);
268 
269     tex_map.push_back(1.0f);
270     tex_map.push_back(0.0f);
271 
272     tex_map.push_back(1.0f);
273     tex_map.push_back(0.0f);
274 
275     tex_map.push_back(0.0f);
276     tex_map.push_back(1.0f);
277 
278     tex_map.push_back(1.0f);
279     tex_map.push_back(1.0f);
280 
281     Scene_plane_item::computeElements();
282   }
283 
~Scene_aabb_plane_item()284   ~Scene_aabb_plane_item()
285   {
286     delete texture;
287   }
288 
update_grid_size() const289   void update_grid_size()const
290   {
291       m_grid_size = m_fast_distance ? fast_distance_grid_size
292                                     : slow_distance_grid_size;
293       delete texture;
294       texture = new ::Texture(m_grid_size,m_grid_size);
295       getTriangleContainer(0)->setTextureSize(QSize(m_grid_size,m_grid_size));
296   }
297 
set_facet_sm_trees(Facet_sm_trees * facet_trees)298   void set_facet_sm_trees(Facet_sm_trees *facet_trees)
299   {
300     this->facet_sm_trees = facet_trees;
301   }
302 
set_edge_sm_trees(Edge_sm_trees * edge_trees)303   void set_edge_sm_trees(Edge_sm_trees *edge_trees)
304   {
305     this->edge_sm_trees = edge_trees;
306   }
draw(CGAL::Three::Viewer_interface * viewer) const307   void draw(CGAL::Three::Viewer_interface* viewer) const Q_DECL_OVERRIDE
308   {
309     if(!isInit(viewer))
310       initGL(viewer);
311     if ( getBuffersFilled() &&
312          ! getBuffersInit(viewer))
313     {
314       initializeBuffers(viewer);
315       setBuffersInit(viewer, true);
316     }
317     if(!getBuffersFilled())
318     {
319       computeElements();
320       initializeBuffers(viewer);
321     }
322     QMatrix4x4 fMatrix;
323     fMatrix.setToIdentity();
324     for(int i=0; i< 16 ; i++)
325       fMatrix.data()[i] =  frame->matrix()[i];
326     Tc *tc ;
327     switch( m_cut_plane )
328     {
329     case UNSIGNED_EDGES:
330     case UNSIGNED_FACETS:
331     case SIGNED_FACETS:
332       tc = getTriangleContainer(0);
333       tc->setFrameMatrix(fMatrix);
334       tc->draw(viewer, true);
335       break;
336     case CUT_SEGMENTS:
337       tc = getTriangleContainer(1);
338       tc->setFrameMatrix(fMatrix);
339       tc->setColor(this->color());
340       tc->draw(viewer, true);
341       break;
342     }
343   }
drawEdges(CGAL::Three::Viewer_interface * viewer) const344   void drawEdges(CGAL::Three::Viewer_interface *viewer) const Q_DECL_OVERRIDE
345   {
346     if(!isInit(viewer))
347       initGL(viewer);
348     if ( getBuffersFilled() &&
349          ! getBuffersInit(viewer))
350     {
351       initializeBuffers(viewer);
352       setBuffersInit(viewer, true);
353     }
354     if(!getBuffersFilled())
355     {
356       computeElements();
357       initializeBuffers(viewer);
358     }
359     if(m_cut_plane != CUT_SEGMENTS)
360       return;
361     QMatrix4x4 fMatrix;
362     for(int i=0; i< 16 ; i++)
363       fMatrix.data()[i] =  frame->matrix()[i];
364     Ec* ec = getEdgeContainer(0);
365     ec->setFrameMatrix(fMatrix);
366     ec->setColor(QColor(Qt::black));
367     ec->draw(viewer, true);
368   }
369 
invalidateOpenGLBuffers()370   void invalidateOpenGLBuffers()Q_DECL_OVERRIDE
371   {
372     setBuffersFilled(false);
373     getTriangleContainer(0)->reset_vbos(ALL);
374     getTriangleContainer(1)->reset_vbos(ALL);
375     getEdgeContainer(0)->reset_vbos(ALL);
376   }
377 
set_fast_distance(bool b) const378   void set_fast_distance(bool b)const  { m_fast_distance = b; update_grid_size(); }
setCutPlaneType(Cut_planes_types type)379   void setCutPlaneType(Cut_planes_types type){ m_cut_plane = type;}
cutPlaneType() const380   Cut_planes_types cutPlaneType()const {return m_cut_plane;}
381 private:
382   Edge_sm_trees* edge_sm_trees;
383   Facet_sm_trees* facet_sm_trees;
384   typedef std::pair<Simple_kernel::Point_3,Simple_kernel::FT> Point_distance;
385   mutable int m_grid_size;
386   mutable bool m_fast_distance;
387   mutable Point_distance m_distance_function[100][100];
388   mutable ::Texture *texture;
389   // An aabb_tree indexing surface_mesh facets/segments
390   mutable Color_ramp m_red_ramp;
391   mutable Color_ramp m_blue_ramp;
392   mutable Color_ramp m_thermal_ramp;
393   mutable Simple_kernel::FT m_max_distance_function;
394   mutable std::vector<float> tex_map;
395   mutable Cut_planes_types m_cut_plane;
396   template <typename SM_Tree>
compute_distance_function(QMap<QObject *,SM_Tree * > * sm_trees,bool is_signed=false) const397   void compute_distance_function(QMap<QObject*, SM_Tree*> *sm_trees, bool is_signed = false)const
398   {
399 
400     m_max_distance_function = FT(0);
401 
402     FT diag = scene_diag();
403     std::vector<SM_Tree*> closed_sm_trees;
404     Q_FOREACH(SM_Tree *sm_tree, sm_trees->values())
405       if(!(is_signed && !CGAL::is_closed(*qobject_cast<Scene_surface_mesh_item*>(sm_trees->key(sm_tree))->polyhedron())))
406         closed_sm_trees.push_back(sm_tree);
407 #ifndef CGAL_LINKED_WITH_TBB
408     FillGridSize<SM_Tree> f(m_grid_size, diag, m_distance_function, m_max_distance_function, closed_sm_trees, is_signed, frame);
409     HackRange range(0, static_cast<std::size_t>(m_grid_size*m_grid_size));
410     f(range);
411 #else
412     FillGridSize<SM_Tree> f(m_grid_size, diag, m_distance_function, m_max_distance_function, closed_sm_trees, is_signed, frame);
413     tbb::parallel_for(tbb::blocked_range<size_t>(0, m_grid_size*m_grid_size), f);
414 #endif
415   }
416 
compute_texture(int i,int j,Color_ramp pos_ramp,Color_ramp neg_ramp) const417   void compute_texture(int i, int j,Color_ramp pos_ramp ,Color_ramp neg_ramp)const
418   {
419     const FT& d00 = m_distance_function[i][j].second;
420     // determines grey level
421     FT i00 = (double)std::fabs(d00) / m_max_distance_function;
422 
423     if(d00 > 0.0)
424       texture->setData(i,j,255*pos_ramp.r(i00),255*pos_ramp.g(i00),255*pos_ramp.b(i00));
425     else
426       texture->setData(i,j,255*neg_ramp.r(i00),255*neg_ramp.g(i00),255*neg_ramp.b(i00));
427   }
428 
429 #ifdef CGAL_LINKED_WITH_TBB
430   class FillTexture
431   {
432     std::size_t grid_size;
433     Color_ramp pos_ramp;
434     Color_ramp neg_ramp;
435     Scene_aabb_plane_item* item;
436   public :
FillTexture(std::size_t grid_size,Color_ramp pos_ramp,Color_ramp neg_ramp,Scene_aabb_plane_item * item)437     FillTexture(std::size_t grid_size,
438                  Color_ramp pos_ramp,
439                  Color_ramp neg_ramp,
440                  Scene_aabb_plane_item* item
441                  )
442       :grid_size(grid_size), pos_ramp(pos_ramp), neg_ramp(neg_ramp), item(item) {}
443 
operator ()(const tbb::blocked_range<std::size_t> & r) const444     void operator()(const tbb::blocked_range<std::size_t>& r) const
445     {
446       for(std::size_t t = r.begin(); t!= r.end(); ++t)
447       {
448         int i = static_cast<int>(t%grid_size), j = static_cast<int>(t/grid_size);
449         item->compute_texture(i,j, pos_ramp, neg_ramp);
450       }
451     }
452   };
453 #endif
454 
computeElements() const455   void computeElements() const Q_DECL_OVERRIDE
456   {
457     switch(m_cut_plane)
458     {
459     case UNSIGNED_FACETS:
460       if ( !facet_sm_trees || facet_sm_trees->empty() ) { return; }
461       compute_distance_function(facet_sm_trees);
462       break;
463     case SIGNED_FACETS:
464       if (!facet_sm_trees || facet_sm_trees->empty() ) { return; }
465       compute_distance_function( facet_sm_trees, true);
466 
467       break;
468     case UNSIGNED_EDGES:
469       if ( !edge_sm_trees || edge_sm_trees->empty()) { return; }
470       compute_distance_function( edge_sm_trees);
471       break;
472     default:
473       break;
474     }
475     //The texture
476     switch(m_cut_plane)
477     {
478     case SIGNED_FACETS:
479     {
480 #ifndef CGAL_LINKED_WITH_TBB
481         for( int i=0 ; i < texture->getWidth(); i++ )
482         {
483             for( int j=0 ; j < texture->getHeight() ; j++)
484             {
485                 compute_texture(i,j,m_red_ramp,m_blue_ramp);
486             }
487         }
488 #else
489       FillTexture f(m_grid_size, m_red_ramp, m_blue_ramp, const_cast<Scene_aabb_plane_item*>(this));
490       tbb::parallel_for(tbb::blocked_range<size_t>(0, m_grid_size * m_grid_size), f);
491 #endif
492         break;
493     }
494     case UNSIGNED_FACETS:
495     case UNSIGNED_EDGES:
496     {
497       #ifndef CGAL_LINKED_WITH_TBB
498         for( int i=0 ; i < texture->getWidth(); i++ )
499         {
500             for( int j=0 ; j < texture->getHeight() ; j++)
501             {
502                 compute_texture(i,j,m_thermal_ramp,m_thermal_ramp);
503             }
504         }
505 #else
506       FillTexture f(m_grid_size, m_thermal_ramp, m_thermal_ramp, const_cast<Scene_aabb_plane_item*>(this));
507       tbb::parallel_for(tbb::blocked_range<size_t>(0, m_grid_size * m_grid_size), f);
508 #endif
509         break;
510     }
511     default:
512       break;
513     }
514 
515     Tc* tc = getTriangleContainer(0);
516     tc->allocate(Tc::Flat_vertices,
517                  positions_quad.data(),
518                  static_cast<int>(positions_quad.size()*sizeof(float)));
519     tc->allocate(
520           Tc::Texture_map,
521           tex_map.data(),
522           static_cast<int>(tex_map.size()*sizeof(float)));
523     tc->getTexture()->setData(texture->getData());
524 
525 
526     tc = getTriangleContainer(1);
527     tc->allocate(Tc::Flat_vertices,
528                  positions_quad.data(),
529                  static_cast<int>(positions_quad.size()*sizeof(float)));
530     Ec* ec = getEdgeContainer(0);
531     ec->allocate(
532           Ec::Vertices,
533           positions_lines.data(),
534           static_cast<int>(positions_lines.size()*sizeof(float)));
535     setBuffersFilled(true);
536 
537   }
538 
initializeBuffers(CGAL::Three::Viewer_interface * viewer) const539   void initializeBuffers(CGAL::Three::Viewer_interface *viewer) const Q_DECL_OVERRIDE
540   {
541     getTriangleContainer(0)->initializeBuffers(viewer);
542     getTriangleContainer(1)->initializeBuffers(viewer);
543     getEdgeContainer(0)->initializeBuffers(viewer);
544     getTriangleContainer(0)->setFlatDataSize(positions_quad.size());
545     getTriangleContainer(1)->setFlatDataSize(positions_quad.size());
546     getEdgeContainer(0)->setFlatDataSize(positions_lines.size());
547   }
548 };
549 
550 
551 class Q_DECL_EXPORT Scene_aabb_item : public CGAL::Three::Scene_item_rendering_helper
552 {
553   Q_OBJECT
554 public:
Scene_aabb_item(const Facet_sm_tree & tree)555   Scene_aabb_item(const Facet_sm_tree& tree)
556   {
557     filter_plane = false;
558     tree_size = tree.size();
559     is_tree_empty = tree.empty();
560     traversal(tree.size(), *tree.root_node(), 0);
561     lvlSlider = new QSlider(Qt::Horizontal);
562     lvlSlider->setMinimum(-1);
563     lvlSlider->setMaximum(static_cast<int>(boxes.size())-1);
564     lvlSlider->setValue(-1);
565     lvlSlider->setPageStep(1);
566     const CGAL::Bbox_3 bbox = tree.bbox();
567     setBbox(Bbox(bbox.xmin(),
568                  bbox.ymin(),
569                  bbox.zmin(),
570                  bbox.xmax(),
571                  bbox.ymax(),
572                  bbox.zmax()));
573     qDebug()<<this->name()<<" at creation: "<<bbox.xmin()<<", "<<bbox.xmax()<<", "<<bbox.ymin()<<", "<<bbox.ymax()<<", "
574            <<bbox.zmin()<<", "<<bbox.zmax();
575     setEdgeContainer(0, new Ec(Vi::PROGRAM_NO_SELECTION, false));
576     for(auto v : CGAL::QGLViewer::QGLViewerPool())
577     {
578       CGAL::Three::Viewer_interface* viewer = static_cast<CGAL::Three::Viewer_interface*>(v);
579       initGL(viewer);
580     }
581     invalidateOpenGLBuffers();
582   }
583 
~Scene_aabb_item()584     ~Scene_aabb_item()
585     {
586     }
587 
contextMenu()588   QMenu* contextMenu()
589   {
590     const char* prop_name = "Menu modified by Scene_aabb_item.";
591 
592     QMenu* menu = Scene_item::contextMenu();
593     bool menuChanged = menu->property(prop_name).toBool();
594     if (!menuChanged) {
595 
596       QAction* filterAction = new QAction(tr("Only Intersected Boxes"));
597       filterAction->setCheckable(true);
598       filterAction->setChecked(false);
599       connect(filterAction, &QAction::toggled, this, [this](bool b){
600         if(b)
601         {
602           filter_plane = true;
603           invalidateOpenGLBuffers();
604           redraw();
605         }
606         else
607         {
608           filter_plane = false;
609           invalidateOpenGLBuffers();
610           redraw();
611         }
612       });
613       menu->addAction(filterAction);
614 
615       QMenu *container = new QMenu(tr("Tree level"));
616       QWidgetAction *sliderAction = new QWidgetAction(nullptr);
617       connect(lvlSlider, &QSlider::valueChanged, this,
618               [this](){
619         invalidateOpenGLBuffers();
620         redraw();
621       });
622       sliderAction->setDefaultWidget(lvlSlider);
623 
624       container->addAction(sliderAction);
625       menu->addMenu(container);
626 
627 
628       menu->setProperty(prop_name, true);
629     }
630     return menu;
631   }
632 
633 
isFinite() const634   bool isFinite() const { return false; }
isEmpty() const635   bool isEmpty() const { return is_tree_empty; }
636   //computed in constructor
compute_bbox() const637   void compute_bbox() const {}
638 
clone() const639   Scene_aabb_item* clone() const {
640     return nullptr;
641   }
642 
toolTip() const643   QString toolTip() const {
644     return
645       tr("<p><b>%1</b> (mode: %2, color: %3)<br />"
646          "<i>AABB_tree</i></p>"
647          "<p>Number of nodes: %4</p>"
648          "<p><b>Instructions:</b><br>Check <i>Only Intersected Boxes</i> in the item's menu to filter out the boxes of the tree that are not intersected by the plane.<br>"
649          "Use the cursor <i>Tree level</i> to only print the boxes of the Nth level. The most left-hand level is the full Tree.</p>")
650       .arg(this->name())
651       .arg(this->renderingModeName())
652       .arg(this->color().name())
653       .arg(tree_size);
654   }
655 
656 
657   // Indicate if rendering mode is supported
supportsRenderingMode(RenderingMode m) const658   bool supportsRenderingMode(RenderingMode m) const {
659     return (m == Wireframe);
660   }
661 
invalidateOpenGLBuffers()662   void invalidateOpenGLBuffers()
663   {
664       setBuffersFilled(false);
665       for(CGAL::QGLViewer* v: CGAL::QGLViewer::QGLViewerPool())
666       {
667         CGAL::Three::Viewer_interface* viewer = static_cast<CGAL::Three::Viewer_interface*>(v);
668         if(viewer == nullptr)
669           continue;
670         setBuffersInit(viewer, false);
671       }
672       getEdgeContainer(0)->reset_vbos(ALL);
673   }
674 
update_tree(Scene_aabb_plane_item * plane_item) const675   void update_tree(Scene_aabb_plane_item* plane_item)const
676   {
677     positions_lines.clear();
678     const CGAL::qglviewer::Vec offset = Three::mainViewer()->offset();
679     CGAL::AABB_drawing_traits<Facet_sm_primitive,  CGAL::AABB_node<Facet_sm_traits> > traits;
680     for(int i=0; i<3; ++i)
681       traits.offset[i] = offset[i];
682     traits.v_edges = &positions_lines;
683     if(lvlSlider->value() != -1)
684     {
685       for(const auto& bb : boxes[lvlSlider->value()])
686       {
687         if(!plane_item || (!filter_plane) || CGAL::do_intersect(plane_item->plane(offset), bb))
688           traits.gl_draw(bb);
689       }
690     }
691     else
692     {
693       for(std::size_t i=0; i<boxes.size(); ++i)
694       {
695         for(const auto& bb : boxes[i])
696         {
697           if(!plane_item || (!filter_plane) || CGAL::do_intersect(plane_item->plane(offset), bb))
698             traits.gl_draw(bb);
699         }
700       }
701     }
702     nb_lines = positions_lines.size();
703     Ec* ec = getEdgeContainer(0);
704     ec->allocate(Ec::Vertices,
705                  positions_lines.data(),
706                  static_cast<int>(positions_lines.size()*sizeof(float)));
707     setBuffersFilled(true);
708   }
709 
710 private:
711    std::size_t tree_size;
712    bool is_tree_empty;
713    bool filter_plane;
714    mutable  std::vector<float> positions_lines;
715    mutable std::size_t nb_lines;
716    std::vector<std::vector<Bbox> > boxes;
717    QSlider* lvlSlider;
718 
719    void
traversal(const std::size_t nb_primitives,const CGAL::AABB_node<Facet_sm_traits> & node,int lvl)720    traversal(const std::size_t nb_primitives,
721              const CGAL::AABB_node<Facet_sm_traits>& node,
722              int lvl)
723    {
724      //traversed lvl by lvl, so one push_back should be enough.
725      if(static_cast<int>(boxes.size()) <= lvl )
726        boxes.push_back(std::vector<Bbox>());
727      CGAL_assertion(static_cast<int>(boxes.size()) > lvl);
728      boxes[lvl].push_back(node.bbox());
729 
730      // Recursive traversal
731      switch(nb_primitives)
732      {
733      case 2:
734        break;
735      case 3:
736        traversal(2, node.right_child(), lvl +1);
737        break;
738      default:
739        traversal(nb_primitives/2, node.left_child(),lvl +1);
740        traversal(nb_primitives-nb_primitives/2, node.right_child(), lvl +1);
741      }
742    }
743 
get_plane_item() const744    Scene_aabb_plane_item* get_plane_item()const
745    {
746      Scene_aabb_plane_item* plane_item = nullptr;
747      if(filter_plane)
748        for(int i=0; i< CGAL::Three::Three::scene()->numberOfEntries(); ++i)
749        {
750          plane_item = qobject_cast<Scene_aabb_plane_item*>(CGAL::Three::Three::scene()->item(i));
751          if(plane_item)
752          {
753            return plane_item;
754          }
755        }
756      return nullptr;
757    }
758 
759 
760 public:
initializeBuffers(CGAL::Three::Viewer_interface * viewer) const761    void initializeBuffers(CGAL::Three::Viewer_interface *viewer)const
762    {
763      Ec* ec = getEdgeContainer(0);
764      ec->initializeBuffers(viewer);
765      ec->setFlatDataSize(nb_lines);
766      positions_lines.clear();
767      positions_lines.shrink_to_fit();
768    }
769 
drawEdges(CGAL::Three::Viewer_interface * viewer) const770     void drawEdges(CGAL::Three::Viewer_interface* viewer) const
771     {
772       if(!isInit(viewer)){
773         setBuffersFilled(false);
774         setBuffersInit(viewer, false);
775         initGL(viewer);
776       }
777       if ( getBuffersFilled() &&
778            ! getBuffersInit(viewer))
779       {
780         initializeBuffers(viewer);
781         setBuffersInit(viewer, true);
782       }
783       if(!getBuffersFilled())
784       {
785         update_tree(get_plane_item());
786         initializeBuffers(viewer);
787       }
788       Ec* ec = getEdgeContainer(0);
789       ec->setColor(this->color());
790         ec->draw(viewer, true);
791     }
792 
computeElements() const793     void computeElements() const
794     {
795       update_tree(get_plane_item());
796     }
797 
798 }; // end class Scene_aabb_item
799 
800 class Q_DECL_EXPORT Scene_edges_item : public CGAL::Three::Scene_item_rendering_helper
801 {
802   Q_OBJECT
803 public:
Scene_edges_item()804     Scene_edges_item()
805     {
806         positions_lines.resize(0);
807         setEdgeContainer(0, new Ec(Vi::PROGRAM_NO_SELECTION, false));
808     }
~Scene_edges_item()809   ~Scene_edges_item()
810   {
811   }
isFinite() const812     bool isFinite() const { return true; }
isEmpty() const813   bool isEmpty() const { return edges.empty(); }
compute_bbox() const814   void compute_bbox() const {
815     if(isEmpty())
816     {
817       setBbox(Bbox());
818       return;
819     }
820     CGAL::Bbox_3 bbox = edges.begin()->bbox();
821     for(size_t i = 1, end = edges.size(); i < end; ++i) {
822       bbox = bbox + edges[i].bbox();
823     }
824     setBbox(Bbox(bbox.xmin(),
825                 bbox.ymin(),
826                 bbox.zmin(),
827                 bbox.xmax(),
828                 bbox.ymax(),
829                 bbox.zmax()));
830   }
invalidateOpenGLBuffers()831   void invalidateOpenGLBuffers()
832   {
833    setBuffersFilled(false);
834    getEdgeContainer(0)->reset_vbos(ALL);
835    compute_bbox();
836   }
837 
clone() const838   Scene_edges_item* clone() const {
839     Scene_edges_item* item = new Scene_edges_item();
840     item->edges = edges;
841     return item;
842   }
843 
toolTip() const844   QString toolTip() const {
845     return
846       tr("<p><b>%1</b> (mode: %2, color: %3)<br />"
847          "<i>Edges</i></p>"
848          "<p>Number of edges: %4</p>")
849       .arg(this->name())
850       .arg(this->renderingModeName())
851       .arg(this->color().name())
852       .arg(edges.size());
853   }
854 
855   // Indicate if rendering mode is supported
supportsRenderingMode(RenderingMode m) const856   bool supportsRenderingMode(RenderingMode m) const {
857     return (m == Wireframe);
858   }
859 
860 
861 
save(std::ostream & os) const862   bool save(std::ostream& os) const
863   {
864     os.precision(17);
865     for(size_t i = 0, end = edges.size(); i < end; ++i){
866       os << "2 " << edges[i].source() << " " <<  edges[i].target() << "\n";
867     }
868     return true;
869   }
870 
871 public:
872   std::vector<Simple_kernel::Segment_3> edges;
873 private:
874     mutable std::vector<float> positions_lines;
875   mutable std::size_t nb_lines;
initializeBuffers(CGAL::Three::Viewer_interface * viewer) const876     void initializeBuffers(CGAL::Three::Viewer_interface *viewer)const
877     {
878       Ec* ec = getEdgeContainer(0);
879       ec->initializeBuffers(viewer);
880       ec->setFlatDataSize(nb_lines);
881       positions_lines.clear();
882       positions_lines.shrink_to_fit();
883     }
computeElements() const884     void computeElements() const
885     {
886        const CGAL::qglviewer::Vec v_offset = Three::mainViewer()->offset();
887        Simple_kernel::Vector_3 offset(v_offset.x, v_offset.y, v_offset.z);
888        QApplication::setOverrideCursor(Qt::WaitCursor);
889        positions_lines.clear();
890 
891        for(size_t i = 0, end = edges.size();
892            i < end; ++i)
893        {
894          const Simple_kernel::Point_3& a = edges[i].source()+offset;
895          const Simple_kernel::Point_3& b = edges[i].target()+offset;
896          positions_lines.push_back(a.x()); positions_lines.push_back(a.y()); positions_lines.push_back(a.z());
897          positions_lines.push_back(b.x()); positions_lines.push_back(b.y()); positions_lines.push_back(b.z());
898        }
899        getEdgeContainer(0)->allocate(
900              Ec::Vertices,
901              positions_lines.data(),
902              static_cast<int>(positions_lines.size()*sizeof(float)));
903        nb_lines = positions_lines.size();
904        setBuffersFilled(true);
905        QApplication::restoreOverrideCursor();
906     }
drawEdges(CGAL::Three::Viewer_interface * viewer) const907     void drawEdges(CGAL::Three::Viewer_interface* viewer) const
908     {
909       if(!isInit(viewer))
910         initGL(viewer);
911       if ( getBuffersFilled() &&
912            ! getBuffersInit(viewer))
913       {
914         initializeBuffers(viewer);
915         setBuffersInit(viewer, true);
916       }
917       if(!getBuffersFilled())
918       {
919         computeElements();
920         initializeBuffers(viewer);
921       }
922       Ec* ec = getEdgeContainer(0);
923       ec->setColor(this->color());
924       ec->draw(viewer, true);
925     }
926 }; // end class Scene_edges_item
927 
928 using namespace CGAL::Three;
929 class Polyhedron_demo_cut_plugin :
930   public QObject,
931   public Polyhedron_demo_plugin_interface,
932   public Polyhedron_demo_io_plugin_interface
933 {
934   Q_OBJECT
935   Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
936   Q_INTERFACES(CGAL::Three::Polyhedron_demo_io_plugin_interface)
937   Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
938   Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.90")
939 
940 public:
Polyhedron_demo_cut_plugin()941   Polyhedron_demo_cut_plugin() : QObject(), edges_item(nullptr) {
942   }
943 
944    ~Polyhedron_demo_cut_plugin();
945 
applicable(QAction *) const946   bool applicable(QAction*) const Q_DECL_OVERRIDE{
947     // returns true if one surface_mesh is in the entries
948     for (int i=0; i< scene->numberOfEntries(); ++i)
949     {
950       if ( qobject_cast<Scene_surface_mesh_item*>(scene->item(i)) )
951         return true;
952     }
953     return false;
954   }
955 
name() const956   QString name() const Q_DECL_OVERRIDE
957   {
958     return "cut-plugin";
959   }
960 
961 
nameFilters() const962    QString nameFilters() const Q_DECL_OVERRIDE
963   {
964     return "Segment soup file (*.polylines.txt *.cgal)";
965   }
966 
967 
canLoad(QFileInfo) const968   bool canLoad(QFileInfo) const Q_DECL_OVERRIDE
969   {
970     return false;
971   }
972 
load(QFileInfo,bool & ok,bool add_to_scene=true)973   QList<Scene_item*> load(QFileInfo , bool& ok, bool add_to_scene=true) Q_DECL_OVERRIDE
974 
975   {
976     Q_UNUSED(add_to_scene);
977     ok = false;
978     return QList<Scene_item*>();
979   }
980 
canSave(const CGAL::Three::Scene_item * item)981   bool canSave(const CGAL::Three::Scene_item* item) Q_DECL_OVERRIDE
982   {
983     // This plugin supports edges items
984     bool b = qobject_cast<const Scene_edges_item*>(item) != 0;
985     return b;
986   }
987 
988 
save(QFileInfo fileinfo,QList<CGAL::Three::Scene_item * > & items)989   bool save(QFileInfo fileinfo,QList<CGAL::Three::Scene_item*>& items) Q_DECL_OVERRIDE
990   {
991     Scene_item* item = items.front();
992     // This plugin supports edges items
993     const Scene_edges_item* edges_item =
994       qobject_cast<const Scene_edges_item*>(item);
995 
996     if(!edges_item){
997       return false;
998     }
999 
1000     std::ofstream out(fileinfo.filePath().toUtf8());
1001     bool ok = (out && edges_item->save(out));
1002     if(ok)
1003       items.pop_front();
1004     return ok;
1005   }
1006 
isDefaultLoader(const Scene_item * item) const1007   bool isDefaultLoader(const Scene_item* item) const Q_DECL_OVERRIDE{
1008     if(qobject_cast<const Scene_edges_item*>(item))
1009       return true;
1010     return false;
1011   }
1012 
1013   using Polyhedron_demo_io_plugin_interface::init;
1014   void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface,
1015             Messages_interface* m) override;
1016   QList<QAction*> actions() const Q_DECL_OVERRIDE;
1017 
eventFilter(QObject *,QEvent * event)1018   bool eventFilter(QObject *, QEvent *event) Q_DECL_OVERRIDE
1019   {
1020     if(!plane_item)
1021       return false;
1022     if(event->type() == QEvent::MouseButtonPress)
1023     {
1024       QMouseEvent * mevent = static_cast<QMouseEvent*>(event);
1025       if ( mevent->modifiers() == Qt::ControlModifier )
1026       {
1027         plane_item->set_fast_distance(true);
1028         plane_item->invalidateOpenGLBuffers();
1029         plane_item->itemChanged();
1030       }
1031     }
1032     else if(event->type() == QEvent::MouseButtonRelease)
1033     {
1034       QMouseEvent * mevent = static_cast<QMouseEvent*>(event);
1035       if ( mevent->modifiers() == Qt::ControlModifier )
1036       {
1037         plane_item->set_fast_distance(false);
1038         plane_item->invalidateOpenGLBuffers();
1039         plane_item->itemChanged();
1040       }
1041     }
1042     return false;
1043   }
1044 
1045 public Q_SLOTS:
1046 
updateCutPlane()1047   void updateCutPlane()
1048   {
1049     if(plane_item->manipulatedFrame()->isSpinning())
1050       plane_item->set_fast_distance(true);
1051      ready_to_cut = true;
1052      QTimer::singleShot(0,this,SLOT(cut()));
1053   }
1054   void cut();
1055   void computeIntersection();
reset_edges()1056   void reset_edges() {
1057     edges_item = nullptr;
1058   }
1059   void Intersection();
1060   void SignedFacets();
1061   void UnsignedFacets();
1062   void UnsignedEdges();
resetPlane()1063   void resetPlane()
1064   {
1065     plane_item = nullptr;
1066   }
uncheckActions()1067   void uncheckActions()
1068   {
1069    Q_FOREACH(QAction* action, _actions)
1070     if(action->isChecked())
1071     {
1072       action->setChecked(false);
1073       return;
1074     }
1075   }
1076 
deleteTree()1077   void deleteTree()
1078   {
1079     Scene_item* item = qobject_cast<Scene_item*>(sender());
1080     if(item)
1081       deleteTrees(item);
1082   }
deleteTrees(CGAL::Three::Scene_item * sender)1083   void deleteTrees(CGAL::Three::Scene_item* sender)
1084   {
1085     Scene_surface_mesh_item* sm_item = qobject_cast<Scene_surface_mesh_item*>(sender);
1086     if(!sm_item)
1087       return;
1088     if(facet_sm_trees.keys().contains(sm_item))
1089     {
1090       delete facet_sm_trees[sm_item];
1091       facet_sm_trees.remove(sm_item);
1092     }
1093     if(edge_sm_trees.keys().contains(sm_item))
1094     {
1095       delete edge_sm_trees[sm_item];
1096       edge_sm_trees.remove(sm_item);
1097     }
1098     if(facet_sm_trees.empty())
1099     {
1100       if(plane_item)
1101         scene->erase(scene->item_id(plane_item));
1102       if(edges_item)
1103         scene->erase(scene->item_id(edges_item));
1104     }
1105     else
1106     {
1107       ready_to_cut = true;
1108       cut();
1109     }
1110   }
1111   void updateTrees(int id);
1112 private:
1113   QList<QAction*>_actions;
1114   void createCutPlane();
1115   CGAL::Three::Scene_interface* scene;
1116   Messages_interface* messages;
1117   Scene_aabb_plane_item* plane_item;
1118   Scene_edges_item* edges_item;
1119   QAction* actionIntersection;
1120   QAction* actionSignedFacets;
1121   QAction* actionUnsignedFacets;
1122   QAction* actionUnsignedEdges;
1123 
1124   bool ready_to_cut;
1125 
1126   Facet_sm_trees facet_sm_trees;
1127   Edge_sm_trees edge_sm_trees;
1128   template<typename Item, typename Mesh, typename Facets_traits, typename Facets_tree, typename Edges_tree>
1129   void apply(Item* item, QMap< QObject*, Facets_tree*>& f_trees, QMap<QObject*, Edges_tree*>& e_trees);
1130 }; // end Polyhedron_demo_cut_plugin
1131 
1132 
~Polyhedron_demo_cut_plugin()1133 Polyhedron_demo_cut_plugin::~Polyhedron_demo_cut_plugin()
1134 {
1135   Q_FOREACH(Facet_sm_tree *tree, facet_sm_trees.values())
1136   {
1137     delete tree;
1138   }
1139     Q_FOREACH(Edge_sm_tree *tree, edge_sm_trees.values())
1140     {
1141       delete tree;
1142     }
1143 }
1144 
1145 
init(QMainWindow * mainWindow,CGAL::Three::Scene_interface * scene_interface,Messages_interface * m)1146 void Polyhedron_demo_cut_plugin::init(QMainWindow* mainWindow,
1147                                       CGAL::Three::Scene_interface* scene_interface,
1148                                       Messages_interface* m)
1149 {
1150   scene = scene_interface;
1151   messages = m;
1152   actionIntersection = new QAction(tr("Cut Segments"), mainWindow);
1153   actionSignedFacets = new QAction(tr("Signed Distance Function to Facets"), mainWindow);
1154   actionUnsignedFacets= new QAction(tr("Unsigned Distance Function to Facets"), mainWindow);
1155   actionUnsignedEdges = new QAction(tr("Unsigned Distance Function to Edges"), mainWindow);
1156 
1157   actionIntersection->setProperty("subMenuName","3D Fast Intersection and Distance Computation");
1158   actionSignedFacets->setProperty("subMenuName","3D Fast Intersection and Distance Computation");
1159   actionUnsignedFacets->setProperty("subMenuName","3D Fast Intersection and Distance Computation");
1160   actionUnsignedEdges->setProperty("subMenuName","3D Fast Intersection and Distance Computation");
1161 
1162   ready_to_cut = true;
1163   connect(actionIntersection, SIGNAL(triggered()),
1164           this, SLOT(Intersection()));
1165   connect(actionSignedFacets, SIGNAL(triggered()),
1166           this, SLOT(SignedFacets()));
1167   connect(actionUnsignedFacets, SIGNAL(triggered()),
1168           this, SLOT(UnsignedFacets()));
1169   connect(actionUnsignedEdges, SIGNAL(triggered()),
1170           this, SLOT(UnsignedEdges()));
1171   plane_item = nullptr;
1172   Scene* real_scene = static_cast<Scene*>(scene);
1173     connect(real_scene, SIGNAL(itemAboutToBeDestroyed(CGAL::Three::Scene_item*)),
1174             this, SLOT(deleteTrees(CGAL::Three::Scene_item*)));
1175     connect(real_scene, SIGNAL(newItem(int)),
1176             this, SLOT(updateTrees(int)));
1177 
1178   CGAL::QGLViewer* viewer = Three::mainViewer();
1179   viewer->installEventFilter(this);
1180 
1181   _actions << actionIntersection
1182            << actionSignedFacets
1183            << actionUnsignedFacets
1184            << actionUnsignedEdges;
1185   QActionGroup *group = new QActionGroup(mainWindow);
1186   group->setExclusive(true);
1187 
1188   Q_FOREACH(QAction *action, _actions)
1189   {
1190     action->setActionGroup(group);
1191     action->setCheckable(true);
1192   }
1193 
1194 }
1195 
actions() const1196 QList<QAction*> Polyhedron_demo_cut_plugin::actions() const {
1197   return _actions;
1198 }
1199 
updateTrees(int id)1200 void Polyhedron_demo_cut_plugin::updateTrees(int id)
1201 {
1202 if(plane_item &&
1203    qobject_cast<Scene_surface_mesh_item*>(scene->item(id)))
1204   createCutPlane();
1205 }
1206 
1207 template<typename Item, typename Mesh, typename Facets_traits, typename Facets_tree, typename Edges_tree>
apply(Item * item,QMap<QObject *,Facets_tree * > & f_trees,QMap<QObject *,Edges_tree * > & e_trees)1208 void Polyhedron_demo_cut_plugin::apply(Item* item, QMap< QObject*, Facets_tree*>& f_trees, QMap<QObject*, Edges_tree*>& e_trees)
1209 {
1210   const Mesh& mesh = *item->polyhedron();
1211   if(!CGAL::is_triangle_mesh(mesh))
1212   {
1213     CGAL::Three::Three::warning(QString("%1 ignored (not a triangulated mesh)").arg(item->name()));
1214     return;
1215   }
1216   if(!CGAL::is_closed(mesh))
1217   {
1218     CGAL::Three::Three::warning(QString("%1 is not closed. Signed function will not be displayed.").arg(item->name()));
1219   }
1220   if(f_trees.find(item) == f_trees.end()) {
1221     PPMAP<Mesh> pmap(item->polyhedron());
1222     Facets_traits traits;
1223     traits.set_shared_data(mesh, pmap); //Mandatory for SMesh. If not provided, mesh and PPmap are taken default, saying NULL in tree.traversal().
1224     connect(item, SIGNAL(item_is_about_to_be_changed()),
1225             this, SLOT(deleteTree()));
1226     Facets_tree* new_tree = new Facets_tree(traits);
1227     //filter facets to ignore degenerated ones
1228 
1229     for(typename boost::graph_traits<Mesh>::face_iterator fit = faces(mesh).first,
1230         end = faces(mesh).second;
1231         fit!=end; ++fit)
1232     {
1233       typename PPMAP<Mesh>::value_type a(get(pmap, target(halfedge(*fit, mesh), mesh))),
1234           b(get(pmap, target(next(halfedge(*fit, mesh), mesh), mesh))),
1235           c(get(pmap, target(prev(halfedge(*fit, mesh), mesh), mesh)));
1236 
1237       if(!CGAL::collinear(a,b,c))
1238         new_tree->insert(typename Facets_tree::Primitive(fit, mesh, pmap));
1239     }
1240     Scene_aabb_item* aabb_item = new Scene_aabb_item(*new_tree);
1241     f_trees[item] = new_tree;
1242     aabb_item->setName(tr("AABB tree of %1").arg(item->name()));
1243     aabb_item->setRenderingMode(Wireframe);
1244     aabb_item->setColor(Qt::black);
1245     aabb_item->setVisible(false);
1246     scene->addItem(aabb_item);
1247   }
1248   if(e_trees.find(item) == e_trees.end()) {
1249     e_trees[item] = new Edges_tree();
1250     PPMAP<Mesh> pmap(item->polyhedron());
1251     e_trees[item]->insert(edges(mesh).first,
1252                                   edges(mesh).second,
1253                                   mesh,
1254                                   pmap);
1255   }
1256 }
1257 
createCutPlane()1258 void Polyhedron_demo_cut_plugin::createCutPlane() {
1259   bool updating = false;
1260   Scene_aabb_plane_item::Cut_planes_types type;
1261   int plane_id = -1;
1262   if(plane_item)
1263       updating = true;
1264   if(updating)
1265   {
1266     type = plane_item->cutPlaneType();
1267     plane_id = scene->item_id(plane_item);
1268   }
1269 
1270   plane_item = new Scene_aabb_plane_item(scene);
1271   const CGAL::Three::Scene_interface::Bbox& bbox = scene->bbox();
1272   plane_item->setPosition((bbox.xmin()+bbox.xmax())/2.f,
1273                           (bbox.ymin()+bbox.ymax())/2.f,
1274                           (bbox.zmin()+bbox.zmax())/2.f);
1275   plane_item->setNormal(0., 0., 1.);
1276   plane_item->setManipulatable(true);
1277   plane_item->setClonable(false);
1278   plane_item->setColor(Qt::green);
1279   plane_item->setName(tr("Cutting plane"));
1280   connect(plane_item->manipulatedFrame(), SIGNAL(modified()),
1281           this, SLOT(updateCutPlane()));
1282   connect(plane_item, SIGNAL(aboutToBeDestroyed()),
1283           this, SLOT(resetPlane()));
1284   connect(plane_item, SIGNAL(aboutToBeDestroyed()),
1285           this, SLOT(uncheckActions()));
1286   if(updating)
1287   {
1288     scene->replaceItem(plane_id, plane_item)->deleteLater();
1289     plane_item->setCutPlaneType(type);
1290   }
1291   else
1292     scene->addItem(plane_item);
1293   // Hide surface_meshes and call cut() (avoid that nothing shows up until user
1294   // decides to move the plane item)
1295   for(int i = 0, end = scene->numberOfEntries(); i < end; ++i) {
1296     CGAL::Three::Scene_item* item = scene->item(i);
1297 
1298     Scene_surface_mesh_item* sm_item = qobject_cast<Scene_surface_mesh_item*>(item);
1299     if ( nullptr != sm_item )
1300       sm_item->setVisible(false);
1301   }
1302   //fills the tree maps
1303   for(int i = 0, end = scene->numberOfEntries(); i < end; ++i) {
1304     CGAL::Three::Scene_item* item = scene->item(i);
1305     Scene_surface_mesh_item* sm_item = qobject_cast<Scene_surface_mesh_item*>(item);
1306     if(sm_item)
1307     {
1308       apply<Scene_surface_mesh_item, SMesh, Facet_sm_traits, Facet_sm_tree, Edge_sm_tree>(sm_item,facet_sm_trees, edge_sm_trees);
1309     }
1310   }
1311 
1312   plane_item->set_facet_sm_trees(&facet_sm_trees);
1313   plane_item->set_edge_sm_trees(&edge_sm_trees);
1314 
1315   ready_to_cut = true;
1316   cut();
1317 }
1318 
Intersection()1319 void Polyhedron_demo_cut_plugin::Intersection()
1320 {
1321   QApplication::setOverrideCursor(Qt::WaitCursor);
1322   if(!plane_item)
1323     createCutPlane();
1324   plane_item->setCutPlaneType(Scene_aabb_plane_item::CUT_SEGMENTS);
1325   computeIntersection();
1326   plane_item->invalidateOpenGLBuffers();
1327   plane_item->redraw();
1328   QApplication::restoreOverrideCursor();
1329 }
1330 
SignedFacets()1331 void Polyhedron_demo_cut_plugin::SignedFacets() {
1332   QApplication::setOverrideCursor(Qt::WaitCursor);
1333   if(!plane_item)
1334     createCutPlane();
1335   plane_item->setCutPlaneType(Scene_aabb_plane_item::SIGNED_FACETS);
1336   plane_item->invalidateOpenGLBuffers();
1337   plane_item->redraw();
1338   if(edges_item)
1339   {
1340     scene->erase(scene->item_id(edges_item));
1341     edges_item = nullptr;
1342   }
1343   QApplication::restoreOverrideCursor();
1344 
1345 }
UnsignedFacets()1346 void Polyhedron_demo_cut_plugin::UnsignedFacets() {
1347   QApplication::setOverrideCursor(Qt::WaitCursor);
1348   if(!plane_item)
1349     createCutPlane();
1350   plane_item->setCutPlaneType(Scene_aabb_plane_item::UNSIGNED_FACETS);
1351   plane_item->invalidateOpenGLBuffers();
1352   plane_item->redraw();
1353   if(edges_item)
1354   {
1355     scene->erase(scene->item_id(edges_item));
1356     edges_item = nullptr;
1357   }
1358   QApplication::restoreOverrideCursor();
1359 }
UnsignedEdges()1360 void Polyhedron_demo_cut_plugin::UnsignedEdges() {
1361   QApplication::setOverrideCursor(Qt::WaitCursor);
1362   if(!plane_item)
1363     createCutPlane();
1364   plane_item->setCutPlaneType(Scene_aabb_plane_item::UNSIGNED_EDGES);
1365   plane_item->invalidateOpenGLBuffers();
1366   plane_item->redraw();
1367   if(edges_item)
1368   {
1369     scene->erase(scene->item_id(edges_item));
1370     edges_item = nullptr;
1371   }
1372   QApplication::restoreOverrideCursor();
1373 }
1374 
computeIntersection()1375 void Polyhedron_demo_cut_plugin::computeIntersection()
1376 {
1377   QApplication::setOverrideCursor(Qt::WaitCursor);
1378   if(!edges_item) {
1379     edges_item = new Scene_edges_item;
1380     edges_item->setName("Edges of the Cut");
1381     edges_item->setColor(Qt::red);
1382     connect(edges_item, SIGNAL(destroyed()),
1383             this, SLOT(reset_edges()));
1384     scene->addItem(edges_item);
1385   }
1386 
1387   const CGAL::qglviewer::Vec offset = Three::mainViewer()->offset();
1388   const CGAL::qglviewer::Vec& pos = plane_item->manipulatedFrame()->position() - offset;
1389   const CGAL::qglviewer::Vec& n =
1390       plane_item->manipulatedFrame()->inverseTransformOf(CGAL::qglviewer::Vec(0.f, 0.f, 1.f));
1391   Simple_kernel::Plane_3 plane(n[0], n[1],  n[2], - n * pos);
1392   //std::cerr << plane << std::endl;
1393   edges_item->edges.clear();
1394   QElapsedTimer time;
1395   time.start();
1396   bool does_intersect = false;
1397   for(Facet_sm_trees::iterator it = facet_sm_trees.begin(); it != facet_sm_trees.end(); ++it)
1398   {
1399     if(!CGAL::do_intersect(plane, it.value()->bbox()))
1400       continue;
1401     does_intersect = true;
1402     std::vector<Facet_sm_tree::Object_and_primitive_id> intersections;
1403     it.value()->all_intersections(plane, std::back_inserter(intersections));
1404 
1405     for ( std::vector<Facet_sm_tree::Object_and_primitive_id>::iterator it = intersections.begin(),
1406           end = intersections.end() ; it != end ; ++it )
1407     {
1408       const Simple_kernel::Segment_3* inter_seg =
1409           CGAL::object_cast<Simple_kernel::Segment_3>(&(it->first));
1410 
1411       if ( nullptr != inter_seg )
1412         edges_item->edges.push_back(*inter_seg);
1413     }
1414   }
1415   if(does_intersect)
1416     CGAL::Three::Three::information(QString("cut (%1 ms). %2 edges.").arg(time.elapsed()).arg(edges_item->edges.size()));
1417   edges_item->invalidateOpenGLBuffers();
1418   edges_item->itemChanged();
1419   ready_to_cut = false;
1420   QApplication::restoreOverrideCursor();
1421 }
1422 
cut()1423 void Polyhedron_demo_cut_plugin::cut()
1424 {
1425   if(!plane_item)
1426     return;
1427 
1428   for(int id =0; id < CGAL::Three::Three::scene()->numberOfEntries(); ++id)
1429   {
1430     Scene_item* item = CGAL::Three::Three::scene()->item(id);
1431     Scene_aabb_item* aabb_item = qobject_cast<Scene_aabb_item*>(item);
1432     if(!aabb_item){
1433       continue;
1434     }
1435     aabb_item->invalidateOpenGLBuffers();
1436   }
1437 
1438   switch(plane_item->cutPlaneType())
1439   {
1440   case Scene_aabb_plane_item::CUT_SEGMENTS:
1441     if(ready_to_cut)
1442     {
1443       computeIntersection();
1444     }
1445     break;
1446   default:
1447     if(ready_to_cut)
1448     {
1449       ready_to_cut = false;
1450       plane_item->invalidateOpenGLBuffers();
1451     }
1452   }
1453 }
1454 
1455 
1456 #include "Cut_plugin.moc"
1457