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