1 #ifndef SCENE_FACEGRAPH_ITEM_K_RING_SELECTION_H
2 #define SCENE_FACEGRAPH_ITEM_K_RING_SELECTION_H
3 #include "Scene_facegraph_item_k_ring_selection_config.h"
4 #include "Scene_surface_mesh_item.h"
5 #include <CGAL/Three/Three.h>
6 #include <CGAL/iterator.h>
7 #include <set>
8 #include <CGAL/Qt/qglviewer.h>
9 #include <QKeyEvent>
10 #include <QMouseEvent>
11 #include <QMainWindow>
12 #include <QObject>
13 #include <CGAL/Three/Viewer_interface.h>
14 
15 #include <map>
16 #include <queue>
17 
18 #include <CGAL/boost/graph/selection.h>
19 #include <CGAL/Polygon_mesh_processing/connected_components.h>
20 #include <CGAL/Polygon_mesh_processing/border.h>
21 #include <CGAL/iterator.h>
22 
23 #include <CGAL/Polygon_2.h>
24 typedef Scene_surface_mesh_item Scene_facegraph_item;
25 typedef EPICK FG_Traits;
26 
27 typedef Scene_facegraph_item::Face_graph FaceGraph;
28 typedef boost::graph_traits<FaceGraph>::vertex_descriptor fg_vertex_descriptor;
29 typedef boost::graph_traits<FaceGraph>::edge_descriptor fg_edge_descriptor;
30 typedef boost::graph_traits<FaceGraph>::face_descriptor fg_face_descriptor;
31 typedef boost::graph_traits<FaceGraph>::halfedge_descriptor fg_halfedge_descriptor;
32 
33 struct FG_is_selected_edge_property_map{
34   typedef boost::property_map<FaceGraph,boost::edge_index_t>::type EImap;
35 
36   std::vector<bool>* is_selected_ptr;
37   EImap* edge_index_map;
FG_is_selected_edge_property_mapFG_is_selected_edge_property_map38   FG_is_selected_edge_property_map()
39     : is_selected_ptr(nullptr), edge_index_map(nullptr) {}
FG_is_selected_edge_property_mapFG_is_selected_edge_property_map40   FG_is_selected_edge_property_map(std::vector<bool>& is_selected, EImap* map)
41     : is_selected_ptr( &is_selected), edge_index_map(map)
42   {}
43 
idFG_is_selected_edge_property_map44   std::size_t id(fg_edge_descriptor ed) {
45     return get(*edge_index_map, ed);
46   }
47 
getFG_is_selected_edge_property_map48   friend bool get(FG_is_selected_edge_property_map map, fg_edge_descriptor ed)
49   {
50     CGAL_assertion(map.is_selected_ptr!=nullptr);
51     return (*map.is_selected_ptr)[map.id(ed)];
52   }
53 
putFG_is_selected_edge_property_map54   friend void put(FG_is_selected_edge_property_map map, fg_edge_descriptor ed, bool b)
55   {
56     CGAL_assertion(map.is_selected_ptr!=nullptr);
57     (*map.is_selected_ptr)[map.id(ed)]=b;
58   }
59 };
60 
getViewerUnderCursor()61 inline CGAL::Three::Viewer_interface* getViewerUnderCursor()
62 {
63   QWidget* widget = QApplication::widgetAt(QCursor::pos());
64   CGAL::Three::Viewer_interface* viewer = qobject_cast<CGAL::Three::Viewer_interface*>(widget);
65   if(!viewer)
66     viewer = CGAL::Three::Three::activeViewer();
67   return viewer;
68 }
69 
70 class SCENE_FACEGRAPH_ITEM_K_RING_SELECTION_EXPORT Scene_facegraph_item_k_ring_selection
71   : public QObject
72 {
73   Q_OBJECT
74 public:
75   struct Active_handle {
76     enum Type{ VERTEX = 0, FACET = 1, EDGE = 2 , CONNECTED_COMPONENT = 3, PATH = 4};
77   };
78 
79   typedef CGAL::Polygon_2<FG_Traits> Polygon_2;
80   typedef std::vector<FG_Traits::Point_2> Polyline_2;
81   typedef std::vector<Polyline_2> Polylines;
82 
83   // Hold mouse keyboard state together
84   struct Mouse_keyboard_state
85   {
Mouse_keyboard_stateMouse_keyboard_state86     Mouse_keyboard_state() : shift_pressing(false), left_button_pressing(false) { }
87     bool shift_pressing, left_button_pressing;
88   };
89 
90   Mouse_keyboard_state  state;
91   QMainWindow* mainwindow;
92   Active_handle::Type    active_handle_type;
93   int                    k_ring;
94   Scene_facegraph_item* poly_item;
95   bool is_active;
96   bool is_current_selection;
97   bool is_highlighting;
98 
Scene_facegraph_item_k_ring_selection()99   Scene_facegraph_item_k_ring_selection() {}
100 
Scene_facegraph_item_k_ring_selection(Scene_facegraph_item * poly_item,QMainWindow * mw,Active_handle::Type aht,int k_ring)101   Scene_facegraph_item_k_ring_selection
102     (Scene_facegraph_item* poly_item, QMainWindow* mw, Active_handle::Type aht, int k_ring)
103       :is_active(false),is_current_selection(true), is_edit_mode(false)
104   {
105     init(poly_item, mw, aht, k_ring);
106   }
107 
setHighLighting(bool b)108   void setHighLighting(bool b)
109   {
110     cut_highlighting = !b;
111   }
setEditMode(bool b)112   void setEditMode(bool b)
113   {
114     is_edit_mode = b;
115     Q_FOREACH(CGAL::QGLViewer* viewer,CGAL::QGLViewer::QGLViewerPool()){
116       //for highlighting
117       viewer->setMouseTracking(true);
118     }
119   }
120 
init(Scene_facegraph_item * poly_item,QMainWindow * mw,Active_handle::Type aht,int k_ring)121   void init(Scene_facegraph_item* poly_item, QMainWindow* mw, Active_handle::Type aht,
122             int k_ring) {
123     this->poly_item = poly_item;
124     this->active_handle_type = aht;
125     this->k_ring = k_ring;
126     polyline = new Polylines(0);
127     polyline->push_back(Polyline_2());
128     mainwindow = mw;
129     is_highlighting = false;
130     is_ready_to_highlight = true;
131     cut_highlighting = false;
132     is_ready_to_paint_select = true;
133     is_lasso_active = false;
134 
135     Q_FOREACH(CGAL::QGLViewer* viewer,CGAL::QGLViewer::QGLViewerPool()){
136       viewer->installEventFilter(this);
137       viewer->setMouseBindingDescription(Qt::Key_D, Qt::ShiftModifier, Qt::LeftButton, "(When in selection plugin) Removes the clicked primitive from the selection. ");
138     }
139     mw->installEventFilter(this);
140     connect(mw, SIGNAL(newViewerCreated(QObject*)),
141             this, SLOT(connectNewViewer(QObject*)));
142     connect(poly_item, SIGNAL(selected_vertex(void*)), this, SLOT(vertex_has_been_selected(void*)));
143     connect(poly_item, SIGNAL(selected_facet(void*)), this, SLOT(facet_has_been_selected(void*)));
144     connect(poly_item, SIGNAL(selected_edge(void*)), this, SLOT(edge_has_been_selected(void*)));
145   }
setCurrentlySelected(bool b)146   void setCurrentlySelected(bool b)
147   {
148     is_current_selection = b;
149   }
set_lasso_mode(bool b)150   void set_lasso_mode(bool b) { is_lasso_active = b; }
151 
152 public Q_SLOTS:
153   // slots are called by signals of polyhedron_item
connectNewViewer(QObject * o)154   void connectNewViewer(QObject* o)
155   {
156     o->installEventFilter(this);
157   }
vertex_has_been_selected(void * void_ptr)158   void vertex_has_been_selected(void* void_ptr)
159   {
160     if((*CGAL::QGLViewer::QGLViewerPool().begin())->property("performing_selection").toBool())
161       return;
162     is_active=true;
163     if(active_handle_type == Active_handle::VERTEX || active_handle_type == Active_handle::PATH)
164     {
165       typedef boost::graph_traits<FaceGraph>::vertices_size_type size_type;
166       size_type h = static_cast<size_type>(reinterpret_cast<std::size_t>(void_ptr));
167       process_selection( static_cast<fg_vertex_descriptor>(h) );
168     }
169     updateIsTreated();
170   }
facet_has_been_selected(void * void_ptr)171   void facet_has_been_selected(void* void_ptr)
172   {
173     if((*CGAL::QGLViewer::QGLViewerPool().begin())->property("performing_selection").toBool())
174       return;
175     is_active=true;
176     if (active_handle_type == Active_handle::FACET
177       || active_handle_type == Active_handle::CONNECTED_COMPONENT)
178     {
179       typedef boost::graph_traits<FaceGraph>::faces_size_type size_type;
180       size_type h = static_cast<size_type>(reinterpret_cast<std::size_t>(void_ptr));
181       process_selection( static_cast<fg_face_descriptor>(h) );
182     }
183     updateIsTreated();
184   }
edge_has_been_selected(void * void_ptr)185   void edge_has_been_selected(void* void_ptr)
186   {
187     if((*CGAL::QGLViewer::QGLViewerPool().begin())->property("performing_selection").toBool())
188       return;
189     is_active=true;
190     if(active_handle_type == Active_handle::EDGE)
191     {
192       typedef boost::graph_traits<FaceGraph>::edges_size_type size_type;
193       size_type h = static_cast<size_type>(reinterpret_cast<std::size_t>(void_ptr));
194       process_selection( static_cast<fg_edge_descriptor>(h) );
195     }
196     updateIsTreated();
197   }
198 
paint_selection()199   void paint_selection()
200   {
201     if(is_ready_to_paint_select)
202     {
203       const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
204       // paint with mouse move event
205       CGAL::QGLViewer* viewer = CGAL::Three::Three::activeViewer();
206       CGAL::qglviewer::Camera* camera = viewer->camera();
207       viewer->makeCurrent();
208       bool found = false;
209       const CGAL::qglviewer::Vec& point = camera->pointUnderPixel(paint_pos, found) - offset;
210       if(found)
211       {
212        CGAL::qglviewer::Vec orig;
213        CGAL::qglviewer::Vec dir;
214        if(camera->type() == CGAL::qglviewer::Camera::PERSPECTIVE)
215        {
216          orig = camera->position() - offset;
217          dir = point - orig;
218        }
219        else
220        {
221          dir = camera->viewDirection();
222          orig = CGAL::qglviewer::Vec(point.x - dir.x,
223                                      point.y - dir.y,
224                                      point.z - dir.z);
225 
226        }
227         poly_item->select(orig.x, orig.y, orig.z, dir.x, dir.y, dir.z);
228       }
229       viewer->doneCurrent();
230       is_ready_to_paint_select = false;
231     }
232   }
233 
lasso_selection()234   void lasso_selection()
235   {
236     CGAL::QGLViewer* viewer = CGAL::Three::Three::activeViewer();
237     const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
238 
239     CGAL::qglviewer::Camera* camera = viewer->camera();
240     const FaceGraph& poly = *poly_item->polyhedron();
241     std::set<fg_face_descriptor> face_sel;
242     boost::property_map<FaceGraph,CGAL::vertex_point_t>::const_type vpmap = get(boost::vertex_point, poly);
243     //select all faces if their screen projection is inside the lasso
244     for(fg_face_descriptor f : faces(poly))
245     {
246       for(fg_vertex_descriptor v : CGAL::vertices_around_face(halfedge(f, poly), poly))
247       {
248         FG_Traits::Point_3 p = get(vpmap, v);
249         CGAL::qglviewer::Vec vp(p.x(), p.y(), p.z());
250         CGAL::qglviewer::Vec vsp = camera->projectedCoordinatesOf(vp+offset);
251         if(is_vertex_selected(vsp))
252         {
253           face_sel.insert(f);
254           break;
255         }
256       }
257     }
258     if(face_sel.empty())
259     {
260       contour_2d.clear();
261       qobject_cast<CGAL::Three::Viewer_interface*>(viewer)->set2DSelectionMode(false);
262       return;
263     }
264     //get border edges of the selected patches
265     std::vector<fg_halfedge_descriptor> boundary_edges;
266     CGAL::Polygon_mesh_processing::border_halfedges(face_sel, poly, std::back_inserter(boundary_edges));
267     std::vector<bool> mark(edges(poly).size(), false);
268     boost::property_map<FaceGraph, boost::edge_index_t>::type edge_index
269       = get(boost::edge_index, poly);
270     FG_is_selected_edge_property_map spmap(mark, &edge_index);
271     for(fg_halfedge_descriptor h : boundary_edges)
272       put(spmap, edge(h, poly), true);
273 
274     boost::vector_property_map<int,
275       boost::property_map<FaceGraph, boost::face_index_t>::type>
276       fccmap(static_cast<unsigned>(num_faces(poly)));
277 
278     //get connected componant from the picked face
279     std::set<fg_face_descriptor> final_sel;
280     //std::vector<Polyhedron::Face_handle> cc;
281     std::size_t nb_cc = CGAL::Polygon_mesh_processing::connected_components(poly
282           , fccmap
283           , CGAL::Polygon_mesh_processing::parameters::edge_is_constrained_map(spmap));
284     std::vector<bool> is_cc_done(nb_cc, false);
285 
286     for(fg_face_descriptor f : face_sel)
287     {
288       int cc_id = get(fccmap, f);
289       if(is_cc_done[cc_id])
290       {
291         continue;
292       }
293       CGAL::Halfedge_around_face_circulator<FaceGraph> hafc(halfedge(f, poly), poly);
294       CGAL::Halfedge_around_face_circulator<FaceGraph> end = hafc;
295       double x(0), y(0), z(0);
296       int total(0);
297       CGAL_For_all(hafc, end)
298       {
299         FG_Traits::Point_3 p = get(vpmap, target(*hafc, poly));
300         x+=p.x(); y+=p.y(); z+=p.z();
301         total++;
302       }
303       if(total == 0)
304         continue;
305       CGAL::qglviewer::Vec center(x/(double)total, y/(double)total, z/(double)total);
306       CGAL::qglviewer::Vec orig;
307       CGAL::qglviewer::Vec dir;
308       if(camera->type() == CGAL::qglviewer::Camera::PERSPECTIVE)
309       {
310         orig = camera->position() - offset;
311         dir = center - orig;
312       }
313       else
314       {
315         dir = camera->viewDirection();
316         orig = CGAL::qglviewer::Vec(center.x - dir.x,
317                                     center.y - dir.y,
318                                     center.z - dir.z);
319       }
320       if(poly_item->intersect_face(orig.x,
321                                    orig.y,
322                                    orig.z,
323                                    dir.x,
324                                    dir.y,
325                                    dir.z,
326                                    f))
327       {
328         is_cc_done[cc_id] = true;
329       }
330     }
331     for(fg_face_descriptor f : faces(poly))
332     {
333       if(is_cc_done[get(fccmap, f)])
334         final_sel.insert(f);
335     }
336     switch(active_handle_type)
337     {
338     case Active_handle::FACET:
339       selected(final_sel);
340       break;
341     case Active_handle::EDGE:
342     {
343       std::set<fg_edge_descriptor> e_sel;
344       for(fg_face_descriptor f : final_sel)
345       {
346         for(fg_halfedge_descriptor h : CGAL::halfedges_around_face(halfedge(f, poly), poly))
347         {
348           FG_Traits::Point_3 p = get(vpmap, target(h, poly));
349           CGAL::qglviewer::Vec vp1(p.x(), p.y(), p.z());
350           CGAL::qglviewer::Vec vsp1 = camera->projectedCoordinatesOf(vp1+offset);
351           p = get(vpmap, target(opposite(h, poly), poly));
352           CGAL::qglviewer::Vec vp2(p.x(), p.y(), p.z());
353           CGAL::qglviewer::Vec vsp2 = camera->projectedCoordinatesOf(vp2+offset);
354           if(is_vertex_selected(vsp1) || is_vertex_selected(vsp2))
355             e_sel.insert(edge(h, poly));
356         }
357       }
358       selected(e_sel);
359       break;
360     }
361     case Active_handle::VERTEX:
362     {
363       std::set<fg_vertex_descriptor> v_sel;
364       for(fg_face_descriptor f : final_sel)
365       {
366         for(fg_vertex_descriptor v : CGAL::vertices_around_face(halfedge(f, poly), poly))
367         {
368           FG_Traits::Point_3 p = get(vpmap, v);
369           CGAL::qglviewer::Vec vp(p.x(), p.y(), p.z());
370           CGAL::qglviewer::Vec vsp = camera->projectedCoordinatesOf(vp+offset);
371           if(is_vertex_selected(vsp))
372             v_sel.insert(v);
373         }
374       }
375       selected(v_sel);
376       break;
377     }
378     default:
379       break;
380     }
381     contour_2d.clear();
382     Q_EMIT endSelection();
383     qobject_cast<CGAL::Three::Viewer_interface*>(viewer)->set2DSelectionMode(false);
384   }
385 
highlight()386   void highlight()
387   {
388     const CGAL::qglviewer::Vec offset = CGAL::Three::Three::mainViewer()->offset();
389     if(is_ready_to_highlight)
390     {
391       // highlight with mouse move event
392       CGAL::QGLViewer* viewer = getViewerUnderCursor();
393       CGAL::qglviewer::Camera* camera = viewer->camera();
394       viewer->makeCurrent();
395       bool found = false;
396       const CGAL::qglviewer::Vec& point = camera->pointUnderPixel(hl_pos, found) - offset;
397       if(found)
398       {
399         CGAL::qglviewer::Vec orig;
400         CGAL::qglviewer::Vec dir;
401         if(camera->type() == CGAL::qglviewer::Camera::PERSPECTIVE)
402         {
403           orig = camera->position() - offset;
404           dir = point - orig;
405         }
406         else
407         {
408           dir = camera->viewDirection();
409           orig = CGAL::qglviewer::Vec(point.x - dir.x,
410                                       point.y - dir.y,
411                                       point.z - dir.z);
412 
413         }
414         is_highlighting = true;
415         poly_item->select(orig.x, orig.y, orig.z, dir.x, dir.y, dir.z);
416         is_highlighting = false;
417       }
418       else
419       {
420         Q_EMIT clearHL();
421       }
422       is_ready_to_highlight = false;
423     }
424   }
425 
426 Q_SIGNALS:
427   void selected(const std::set<fg_vertex_descriptor>&);
428   void selected(const std::set<fg_face_descriptor>&);
429   void selected(const std::set<fg_edge_descriptor>&);
430   void selected_HL(const std::set<fg_vertex_descriptor>&);
431   void selected_HL(const std::set<fg_face_descriptor>&);
432   void selected_HL(const std::set<fg_edge_descriptor>&);
433   void toogle_insert(const bool);
434   void endSelection();
435   void resetIsTreated();
436   void isCurrentlySelected(Scene_facegraph_item_k_ring_selection*);
437   void clearHL();
438 
439 protected:
440 
updateIsTreated()441   void updateIsTreated()
442   {
443     static ushort i = 0;
444     i++;
445     if(i==3)
446     {
447       i = 0;
448       Q_EMIT resetIsTreated();
449     }
450   }
451   template<class HandleType>
process_selection(HandleType clicked)452   void process_selection(HandleType clicked) {
453     //keeps the highlighting on track if the brush_size is not 0
454     int current_ring = 0;
455     if(active_handle_type != Active_handle::PATH && !is_edit_mode)
456       current_ring = k_ring;
457     const std::set<HandleType>& selection = extract_k_ring(clicked, current_ring);
458     if(is_highlighting)
459     {
460       Q_EMIT selected_HL(selection);
461     }
462     else
463       Q_EMIT selected(selection);
464   }
465 
466   template <class Handle>
467   struct Is_selected_from_set{
468     std::set<Handle>& selection;
Is_selected_from_setIs_selected_from_set469     Is_selected_from_set(std::set<Handle>& selection)
470       :selection(selection) {}
getIs_selected_from_set471     friend bool get(Is_selected_from_set<Handle> map, Handle k)
472     {
473       return map.selection.count(k);
474     }
putIs_selected_from_set475     friend void put(Is_selected_from_set<Handle> map, Handle k, bool b)
476     {
477       if (b)
478         map.selection.insert(k);
479       else
480         map.selection.erase(k);
481     }
482   };
483 
484   std::set<fg_vertex_descriptor>
extract_k_ring(fg_vertex_descriptor clicked,unsigned int k)485   extract_k_ring(fg_vertex_descriptor clicked, unsigned int k)
486   {
487     std::set<fg_vertex_descriptor> selection;
488     selection.insert(clicked);
489     if (k>0)
490       CGAL::expand_vertex_selection(CGAL::make_array(clicked),
491                                     *poly_item->polyhedron(),
492                                     k,
493                                     Is_selected_from_set<fg_vertex_descriptor>(selection),
494                                     CGAL::Emptyset_iterator());
495 
496     return selection;
497   }
498 
499   std::set<fg_face_descriptor>
extract_k_ring(fg_face_descriptor clicked,unsigned int k)500   extract_k_ring(fg_face_descriptor clicked, unsigned int k)
501   {
502     std::set<fg_face_descriptor> selection;
503     selection.insert(clicked);
504     if (k>0)
505       CGAL::expand_face_selection(CGAL::make_array(clicked),
506                                   *poly_item->polyhedron(),
507                                   k,
508                                   Is_selected_from_set<fg_face_descriptor>(selection),
509                                   CGAL::Emptyset_iterator());
510 
511     return selection;
512   }
513 
514   std::set<fg_edge_descriptor>
extract_k_ring(fg_edge_descriptor clicked,unsigned int k)515   extract_k_ring(fg_edge_descriptor clicked, unsigned int k)
516   {
517     std::set<fg_edge_descriptor> selection;
518     selection.insert(clicked);
519 
520     if (k>0)
521       CGAL::expand_edge_selection(CGAL::make_array(clicked),
522                                   *poly_item->polyhedron(),
523                                   k,
524                                   Is_selected_from_set<fg_edge_descriptor>(selection),
525                                   CGAL::Emptyset_iterator());
526     return selection;
527   }
528 
529 
eventFilter(QObject * target,QEvent * event)530   bool eventFilter(QObject* target, QEvent *event)
531   {
532     static QImage background;
533     // This filter is both filtering events from 'viewer' and 'main window'
534 
535     // key events
536       if(event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease)  {
537       QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
538       Qt::KeyboardModifiers modifiers = keyEvent->modifiers();
539 
540       state.shift_pressing = modifiers.testFlag(Qt::ShiftModifier);
541     }
542 
543     if(event->type() == QEvent::KeyPress
544             && state.shift_pressing
545             && static_cast<QKeyEvent*>(event)->key()==Qt::Key_D)
546     {
547      Q_EMIT toogle_insert(false);
548     }
549     else if(event->type() == QEvent::KeyRelease
550             && static_cast<QKeyEvent*>(event)->key()==Qt::Key_D)
551     {
552      Q_EMIT toogle_insert(true);
553     }
554     // mouse events
555     if(event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) {
556       QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
557       if(mouse_event->button() == Qt::LeftButton) {
558         state.left_button_pressing = event->type() == QEvent::MouseButtonPress;
559         if(is_edit_mode)
560           Q_EMIT clearHL();
561         if (!state.left_button_pressing)
562         {
563           if (is_active)
564           {
565             Q_EMIT endSelection();
566             is_active=false;
567           }
568           apply_path();
569           lasso_selection();
570         }
571       }
572       //to avoid the contextual menu to mess up the states.
573       else if(mouse_event->button() == Qt::RightButton) {
574         state.left_button_pressing = false;
575         state.shift_pressing = false;
576       }
577     }
578     // use mouse move event for paint-like selection
579     if( (event->type() == QEvent::MouseMove
580          || (event->type() == QEvent::MouseButtonPress
581              && static_cast<QMouseEvent*>(event)->button() == Qt::LeftButton))
582         && (state.shift_pressing && state.left_button_pressing) )
583     {
584       Q_EMIT isCurrentlySelected(this);
585       if(!is_current_selection)
586         return false;
587       if(target == mainwindow)
588       {
589         CGAL::QGLViewer* viewer = CGAL::Three::Three::activeViewer();
590         viewer->setFocus();
591         return false;
592       }
593 
594       if(!is_lasso_active)
595       {
596         is_ready_to_paint_select = true;
597         QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
598         hl_pos = mouse_event->pos();
599         is_ready_to_highlight = !cut_highlighting;
600         QTimer::singleShot(0, this, SLOT(highlight()));
601         paint_pos = mouse_event->pos();
602         if(!is_edit_mode || event->type() == QEvent::MouseButtonPress)
603         {
604           QTimer::singleShot(0,this,SLOT(paint_selection()));
605         }
606       }
607       else
608       {
609         if (event->type() != QEvent::MouseMove)
610         {
611           //Create a QImage of the screen and paint the lasso on top of it
612           CGAL::QGLViewer* viewer = CGAL::Three::Three::activeViewer();
613           background = static_cast<CGAL::Three::Viewer_interface*>(viewer)->grabFramebuffer();
614         }
615         sample_mouse_path(background);
616       }
617     }
618     //if the mouse is moving without left button pressed :
619     // highlight the primitive under cursor
620     else if(event->type() == QEvent::MouseMove && !state.left_button_pressing)
621     {
622       QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
623       CGAL::QGLViewer* viewer = getViewerUnderCursor();
624 
625       is_ready_to_highlight = !cut_highlighting;
626       hl_pos = viewer->mapFromGlobal(mouse_event->globalPos());
627       QTimer::singleShot(0, this, SLOT(highlight()));
628     }//end MouseMove
629     return false;
630   }
631   bool is_edit_mode;
632   bool is_ready_to_highlight;
633   bool is_ready_to_paint_select;
634   bool is_lasso_active;
635   QPoint hl_pos;
636   QPoint paint_pos;
637   Polyline_2 contour_2d;
638   Polylines* polyline;
poly()639   Polyline_2& poly() const  { return polyline->front(); }
640   Polygon_2 lasso;
641   CGAL::Bbox_2 domain_rectangle;
642   bool cut_highlighting;
update_polyline()643   bool update_polyline () const
644   {
645     if (contour_2d.size() < 2 ||
646         (!(poly().empty()) && contour_2d.back () == poly().back()))
647       return false;
648 
649 
650     if (!(poly().empty()) && contour_2d.back () == poly().back())
651       return false;
652 
653     poly().clear();
654 
655     for (unsigned int i = 0; i < contour_2d.size (); ++ i)
656       poly().push_back (contour_2d[i]);
657 
658     return true;
659   }
660 
sample_mouse_path(QImage & background)661   void sample_mouse_path(QImage& background)
662   {
663     CGAL::Three::Viewer_interface* viewer =
664         qobject_cast<CGAL::Three::Viewer_interface*>(CGAL::Three::Three::activeViewer());
665     viewer->makeCurrent();
666     const QPoint& p = viewer->mapFromGlobal(QCursor::pos());
667     contour_2d.push_back (FG_Traits::Point_2 (p.x(), p.y()));
668     if (update_polyline ())
669     {
670       //update draw
671       QPen pen;
672       pen.setColor(QColor(Qt::green));
673       pen.setWidth(3);
674 
675       //Create a QImage of the screen and paint the lasso on top of it
676       QImage temp(background);
677       QPainter *painter = new QPainter(&temp);
678 
679 
680       //painter->begin(&image);
681       painter->setPen(pen);
682       for(std::size_t i=0; i<polyline->size(); ++i)
683       {
684         Polyline_2 poly = (*polyline)[i];
685         if(!poly.empty())
686           for(std::size_t j=0; j<poly.size()-1; ++j)
687           {
688             painter->drawLine(int(poly[j].x()),
689                               int(poly[j].y()),
690                               int(poly[j+1].x()),
691                               int(poly[j+1].y()));
692           }
693       }
694       painter->end();
695       delete painter;
696       viewer->set2DSelectionMode(true);
697       viewer->setStaticImage(temp);
698       viewer->update();
699     }
700   }
701 
apply_path()702   void apply_path()
703   {
704     update_polyline ();
705     domain_rectangle = CGAL::bbox_2 (contour_2d.begin (), contour_2d.end ());
706     lasso = Polygon_2 (contour_2d.begin (), contour_2d.end ());
707   }
708 
is_vertex_selected(CGAL::qglviewer::Vec & p)709   bool is_vertex_selected (CGAL::qglviewer::Vec& p)
710   {
711     if (domain_rectangle.xmin () < p.x &&
712         p.x < domain_rectangle.xmax () &&
713         domain_rectangle.ymin () < p.y &&
714         p.y < domain_rectangle.ymax ())
715       {
716 /*
717  * domain_freeform.has_on_bounded_side() requires the polygon to be simple, which is never the case.
718  * However, it works very well even if the polygon is not simple, so we use this instead to avoid
719  * the cgal_assertion on is_simple().*/
720 
721 
722         if (CGAL::bounded_side_2(lasso.container().begin(),
723                                  lasso.container().end(),
724                                  FG_Traits::Point_2(p.x, p.y),
725                                  lasso.traits_member())  == CGAL::ON_BOUNDED_SIDE)
726           return true;
727       }
728     return false;
729   }
730 };
731 #endif
732