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