1 #include <QApplication>
2 #include <QUndoCommand>
3 #include <QUndoStack>
4 #include "Scene_polyhedron_selection_item.h"
5 #include <CGAL/Polygon_mesh_processing/compute_normal.h>
6 #include <CGAL/Polygon_mesh_processing/repair.h>
7 #include <CGAL/Polygon_mesh_processing/shape_predicates.h>
8 #include <CGAL/boost/graph/dijkstra_shortest_paths.h>
9 #include <CGAL/boost/graph/helpers.h>
10 #include <CGAL/property_map.h>
11 #include <CGAL/Handle_hash_function.h>
12 #include <CGAL/Unique_hash_map.h>
13 #include <CGAL/statistics_helpers.h>
14 
15 #include <boost/unordered_map.hpp>
16 #include <boost/unordered_set.hpp>
17 #include <boost/range.hpp>
18 #include <CGAL/Three/Triangle_container.h>
19 #include <CGAL/Three/Edge_container.h>
20 #include <CGAL/Three/Point_container.h>
21 #include <CGAL/Three/Three.h>
22 
23 #include <exception>
24 #include <functional>
25 #include <limits>
26 #include <set>
27 #include <utility>
28 #include <vector>
29 #include <functional>
30 
31 #include "triangulate_primitive.h"
32 #include <CGAL/boost/graph/Face_filtered_graph.h>
33 #include <CGAL/Polygon_mesh_processing/measure.h>
34 #include <CGAL/boost/graph/properties.h>
35 
36 using namespace CGAL::Three;
37 typedef Viewer_interface Vi;
38 typedef Triangle_container Tc;
39 typedef Edge_container Ec;
40 typedef Point_container Pc;
41 
42 typedef Scene_surface_mesh_item Scene_face_graph_item;
43 
44 typedef Scene_face_graph_item::Face_graph Face_graph;
45 typedef boost::property_map<Face_graph,CGAL::vertex_point_t>::type VPmap;
46 typedef boost::property_map<Face_graph,CGAL::vertex_point_t>::const_type constVPmap;
47 
48 typedef Scene_face_graph_item::Vertex_selection_map Vertex_selection_map;
49 
50 typedef boost::graph_traits<Face_graph>::vertex_descriptor fg_vertex_descriptor;
51 typedef boost::graph_traits<Face_graph>::face_descriptor fg_face_descriptor;
52 typedef boost::graph_traits<Face_graph>::edge_descriptor fg_edge_descriptor;
53 typedef boost::graph_traits<Face_graph>::halfedge_descriptor fg_halfedge_descriptor;
54 
55 class EulerOperation : public QUndoCommand
56 {
57   std::function<void ()> undo_;
58   Scene_polyhedron_selection_item* item;
59 public:
60   template <typename Undo>
EulerOperation(Undo && undo,Scene_polyhedron_selection_item * item)61   EulerOperation(Undo&& undo, Scene_polyhedron_selection_item* item)
62     :undo_(std::forward<Undo> (undo)),
63       item(item)
64   {}
65 
undo()66   void undo() override
67   {
68     undo_();
69     item->compute_normal_maps();
70     item->invalidateOpenGLBuffers();
71     item->redraw();
72   }
redo()73   void redo() override
74   {}
75 };
76 
77 struct Scene_polyhedron_selection_item_priv{
78 
79   typedef Scene_facegraph_item_k_ring_selection::Active_handle Active_handle;
80   typedef boost::unordered_set<fg_vertex_descriptor
81   , CGAL::Handle_hash_function>    Selection_set_vertex;
82   typedef boost::unordered_set<fg_face_descriptor,
83   CGAL::Handle_hash_function>      Selection_set_facet;
84   typedef boost::unordered_set<fg_edge_descriptor,
85   CGAL::Handle_hash_function>    Selection_set_edge;
86   struct vertex_on_path
87   {
88     fg_vertex_descriptor vertex;
89     bool is_constrained;
90   };
91 
92 
Scene_polyhedron_selection_item_privScene_polyhedron_selection_item_priv93   Scene_polyhedron_selection_item_priv(Scene_polyhedron_selection_item* parent):
94     item(parent)
95   {
96     filtered_graph = nullptr;
97     item->setProperty("classname", QString("surface_mesh_selection"));
98     keep_selection_valid = Scene_polyhedron_selection_item::None;
99   }
100 
101   void initializeBuffers(CGAL::Three::Viewer_interface *viewer) const;
102   void initialize_temp_buffers(CGAL::Three::Viewer_interface *viewer) const;
103   void initialize_HL_buffers(CGAL::Three::Viewer_interface *viewer) const;
104   void computeElements() const;
105   void compute_any_elements(std::vector<float> &p_facets,
106                             std::vector<float> &p_lines, std::vector<float> &p_points,
107                             std::vector<float> &p_normals,
108                             const Selection_set_vertex& p_sel_vertex,
109                             const Selection_set_facet &p_sel_facet,
110                             const Selection_set_edge &p_sel_edges) const;
111   void compute_temp_elements() const;
112   void compute_HL_elements() const;
113   void triangulate_facet(fg_face_descriptor, EPICK::Vector_3 normal,
114                          std::vector<float> &p_facets,std::vector<float> &p_normals) const;
115   void tempInstructions(QString s1, QString s2);
116 
117   void computeAndDisplayPath();
118   void addVertexToPath(fg_vertex_descriptor, vertex_on_path &);
119 
120   QList<vertex_on_path> path;
121   QList<fg_vertex_descriptor> constrained_vertices;
122   bool is_path_selecting;
123   bool poly_need_update;
124   mutable bool are_temp_buffers_filled;
125   //Specifies Selection/edition mode
126   bool first_selected;
127   int operation_mode;
128   QString m_temp_instructs;
129   bool is_treated;
130   fg_vertex_descriptor to_split_vh;
131   fg_face_descriptor to_split_fh;
132   fg_edge_descriptor to_join_ed;
133   Active_handle::Type original_sel_mode;
134   //Only needed for the triangulation
135   Face_graph* poly;
136   CGAL::Unique_hash_map<fg_face_descriptor, EPICK::Vector_3>  face_normals_map;
137   CGAL::Unique_hash_map<fg_vertex_descriptor, EPICK::Vector_3>  vertex_normals_map;
138   boost::associative_property_map< CGAL::Unique_hash_map<fg_face_descriptor, EPICK::Vector_3> >
139     nf_pmap;
140   boost::associative_property_map< CGAL::Unique_hash_map<fg_vertex_descriptor, EPICK::Vector_3> >
141     nv_pmap;
142   Scene_face_graph_item::ManipulatedFrame *manipulated_frame;
143   bool ready_to_move;
144 
vertex_selection_mapScene_polyhedron_selection_item_priv145   Vertex_selection_map vertex_selection_map()
146   {
147     return item->poly_item->vertex_selection_map();
148   }
149 
polyhedronScene_polyhedron_selection_item_priv150   Face_graph* polyhedron() { return poly; }
polyhedronScene_polyhedron_selection_item_priv151   const Face_graph* polyhedron()const { return poly; }
152 
set_num_facesScene_polyhedron_selection_item_priv153   void set_num_faces(const std::size_t n) { num_faces = n; }
154 
155   bool canAddFace(fg_halfedge_descriptor hc, Scene_polyhedron_selection_item::fg_halfedge_descriptor t);
156   bool canAddFaceAndVertex(Scene_polyhedron_selection_item::fg_halfedge_descriptor hc,
157                            Scene_polyhedron_selection_item::fg_halfedge_descriptor t);
158 
159   mutable std::vector<float> positions_facets;
160   mutable std::vector<float> normals;
161   mutable std::vector<float> positions_lines;
162   mutable std::vector<float> positions_points;
163   mutable std::size_t nb_facets;
164   mutable std::size_t nb_points;
165   mutable std::size_t nb_lines;
166 
167   mutable std::vector<float> positions_temp_facets;
168   mutable std::vector<float> positions_fixed_points;
169   mutable std::vector<float> color_fixed_points;
170   mutable std::vector<float> temp_normals;
171   mutable std::vector<float> positions_temp_lines;
172   mutable std::vector<float> positions_temp_points;
173   mutable std::vector<float> positions_HL_facets;
174   mutable std::vector<float> HL_normals;
175   mutable std::vector<float> positions_HL_lines;
176   mutable std::vector<float> positions_HL_points;
177 
178   mutable std::size_t nb_temp_facets;
179   mutable std::size_t nb_temp_points;
180   mutable std::size_t nb_temp_lines;
181   mutable std::size_t nb_fixed_points;
182 
183   mutable bool are_HL_buffers_filled;
184   Scene_polyhedron_selection_item* item;
185   enum TriangleNames{
186     Facets = 0,
187     Temp_facets,
188     HL_facets
189   };
190   enum EdgeNames{
191     Edges = 0,
192     Temp_edges,
193     HL_edges
194   };
195   enum PointNames{
196     Points = 0,
197     Temp_points,
198     HL_points,
199     Fixed_points
200   };
201   QUndoStack stack;
202   CGAL::Face_filtered_graph<SMesh> *filtered_graph;
203 
204   std::size_t num_faces;
205   std::size_t num_vertices;
206   std::size_t num_edges;
207   Scene_polyhedron_selection_item::SelectionTypes keep_selection_valid;
208 };
209 typedef Scene_polyhedron_selection_item_priv Priv;
210 
initializeBuffers(CGAL::Three::Viewer_interface * viewer) const211 void Scene_polyhedron_selection_item_priv::initializeBuffers(CGAL::Three::Viewer_interface *viewer)const
212 {
213   item->getTriangleContainer(Facets)->initializeBuffers(viewer);
214   item->getTriangleContainer(Facets)->setFlatDataSize(nb_facets);
215   item->getEdgeContainer(Edges)->initializeBuffers(viewer);
216   item->getEdgeContainer(Edges)->setFlatDataSize(nb_lines);
217   item->getPointContainer(Points)->initializeBuffers(viewer);
218   item->getPointContainer(Points)->setFlatDataSize(nb_points);
219 
220   positions_facets.resize(0);
221   positions_facets.shrink_to_fit();
222 
223   normals.resize(0);
224   normals.shrink_to_fit();
225 
226   positions_lines.resize(0);
227   positions_lines.shrink_to_fit();
228 
229   positions_points.resize(0);
230   positions_points.shrink_to_fit();
231 }
232 
initialize_temp_buffers(CGAL::Three::Viewer_interface * viewer) const233 void Scene_polyhedron_selection_item_priv::initialize_temp_buffers(CGAL::Three::Viewer_interface *viewer)const
234 {
235   item->getTriangleContainer(Temp_facets)->initializeBuffers(viewer);
236   item->getTriangleContainer(Temp_facets)->setFlatDataSize(nb_temp_facets);
237   item->getEdgeContainer(Temp_edges)->initializeBuffers(viewer);
238   item->getEdgeContainer(Temp_edges)->setFlatDataSize(nb_temp_lines);
239   item->getPointContainer(Temp_points)->initializeBuffers(viewer);
240   item->getPointContainer(Temp_points)->setFlatDataSize(nb_temp_points);
241   item->getPointContainer(Fixed_points)->initializeBuffers(viewer);
242   item->getPointContainer(Fixed_points)->setFlatDataSize(nb_fixed_points);
243   positions_temp_facets.resize(0);
244   std::vector<float>(positions_temp_facets).swap(positions_temp_facets);
245   temp_normals.resize(0);
246   std::vector<float>(temp_normals).swap(temp_normals);
247   positions_temp_lines.resize(0);
248   std::vector<float>(positions_temp_lines).swap(positions_temp_lines);
249   positions_temp_points.resize(0);
250   std::vector<float>(positions_temp_points).swap(positions_temp_points);
251   positions_fixed_points.resize(0);
252   std::vector<float>(positions_fixed_points).swap(positions_fixed_points);
253 
254 }
255 
initialize_HL_buffers(CGAL::Three::Viewer_interface * viewer) const256 void Scene_polyhedron_selection_item_priv::initialize_HL_buffers(CGAL::Three::Viewer_interface *viewer)const
257 {
258   item->getTriangleContainer(HL_facets)->initializeBuffers(viewer);
259   item->getTriangleContainer(HL_facets)->setFlatDataSize(positions_HL_facets.size());
260   item->getEdgeContainer(HL_edges)->initializeBuffers(viewer);
261   item->getEdgeContainer(HL_edges)->setFlatDataSize(positions_HL_lines.size());
262   item->getPointContainer(HL_points)->initializeBuffers(viewer);
263   item->getPointContainer(HL_points)->setFlatDataSize(positions_HL_points.size());
264 }
265 template<typename TypeWithXYZ, typename ContainerWithPushBack>
push_back_xyz(const TypeWithXYZ & t,ContainerWithPushBack & vector)266 void push_back_xyz(const TypeWithXYZ& t,
267                    ContainerWithPushBack& vector)
268 {
269   vector.push_back(t.x());
270   vector.push_back(t.y());
271   vector.push_back(t.z());
272 }
273 
274 typedef EPICK Traits;
275 
276 //Make sure all the facets are triangles
277 typedef Traits::Point_3                    Point_3;
278 typedef Traits::Point_3                    Point;
279 typedef Traits::Vector_3            Vector;
280 
281 void
triangulate_facet(fg_face_descriptor fit,const Vector normal,std::vector<float> & p_facets,std::vector<float> & p_normals) const282 Scene_polyhedron_selection_item_priv::triangulate_facet(fg_face_descriptor fit,const Vector normal,
283                                                    std::vector<float> &p_facets,std::vector<float> &p_normals ) const
284 {
285   const CGAL::qglviewer::Vec off = Three::mainViewer()->offset();
286   EPICK::Vector_3 offset(off.x,off.y,off.z);
287 
288   typedef FacetTriangulator<Face_graph, EPICK, fg_vertex_descriptor> FT;
289   FT triangulation(fit,normal,poly, offset);
290     //iterates on the internal faces to add the vertices to the positions
291     //and the normals to the appropriate vectors
292     for(FT::CDT::Finite_faces_iterator
293         ffit = triangulation.cdt->finite_faces_begin(),
294         end = triangulation.cdt->finite_faces_end();
295         ffit != end; ++ffit)
296     {
297         if(ffit->info().is_external)
298             continue;
299 
300         push_back_xyz(ffit->vertex(0)->point(), p_facets);
301         push_back_xyz(ffit->vertex(1)->point(), p_facets);
302         push_back_xyz(ffit->vertex(2)->point(), p_facets);
303 
304         push_back_xyz(normal, p_normals);
305         push_back_xyz(normal, p_normals);
306         push_back_xyz(normal, p_normals);
307     }
308 }
309 
310 
compute_any_elements(std::vector<float> & p_facets,std::vector<float> & p_lines,std::vector<float> & p_points,std::vector<float> & p_normals,const Selection_set_vertex & p_sel_vertices,const Selection_set_facet & p_sel_facets,const Selection_set_edge & p_sel_edges) const311 void Scene_polyhedron_selection_item_priv::compute_any_elements(std::vector<float>& p_facets, std::vector<float>& p_lines, std::vector<float>& p_points, std::vector<float>& p_normals,
312                                                            const Selection_set_vertex& p_sel_vertices, const Selection_set_facet& p_sel_facets, const Selection_set_edge& p_sel_edges)const
313 {
314     const CGAL::qglviewer::Vec offset = Three::mainViewer()->offset();
315     p_facets.clear();
316     p_lines.clear();
317     p_points.clear();
318     p_normals.clear();
319     //The facet
320 
321     if(!poly)
322       return;
323 
324     VPmap vpm = get(CGAL::vertex_point,*poly);
325     for(Selection_set_facet::iterator
326         it = p_sel_facets.begin(),
327         end = p_sel_facets.end();
328         it != end; it++)
329     {
330       fg_face_descriptor f = (*it);
331       if (f == boost::graph_traits<Face_graph>::null_face())
332         continue;
333       Vector nf = get(nf_pmap, f);
334       if(is_triangle(halfedge(f,*poly),*poly))
335       {
336         p_normals.push_back(nf.x());
337         p_normals.push_back(nf.y());
338         p_normals.push_back(nf.z());
339 
340         p_normals.push_back(nf.x());
341         p_normals.push_back(nf.y());
342         p_normals.push_back(nf.z());
343 
344         p_normals.push_back(nf.x());
345         p_normals.push_back(nf.y());
346         p_normals.push_back(nf.z());
347 
348 
349         for(fg_halfedge_descriptor he : halfedges_around_face(halfedge(f,*polyhedron()), *polyhedron()))
350         {
351           const Point& p = get(vpm,target(he,*poly));
352           p_facets.push_back(p.x()+offset.x);
353           p_facets.push_back(p.y()+offset.y);
354           p_facets.push_back(p.z()+offset.z);
355         }
356       }
357       else if (is_quad(halfedge(f,*poly), *poly))
358       {
359         EPICK::Vector_3 v_offset(offset.x, offset.y, offset.z);
360         Vector nf = get(nf_pmap, f);
361         {
362           //1st half-quad
363           const Point& p0 = get(vpm,target(halfedge(f,*poly),*poly));
364           const Point& p1 = get(vpm,target(next(halfedge(f,*poly),*poly),*poly));
365           const Point& p2 = get(vpm,target(next(next(halfedge(f,*poly),*poly),*poly),*poly));
366 
367           push_back_xyz(p0+v_offset, p_facets);
368           push_back_xyz(p1+v_offset, p_facets);
369           push_back_xyz(p2+v_offset, p_facets);
370 
371           push_back_xyz(nf, p_normals);
372           push_back_xyz(nf, p_normals);
373           push_back_xyz(nf, p_normals);
374         }
375         {
376           //2nd half-quad
377           const Point& p0 = get(vpm, target(next(next(halfedge(f,*poly),*poly),*poly),*poly));
378           const Point& p1 = get(vpm, target(prev(halfedge(f,*poly),*poly),*poly));
379           const Point& p2 = get(vpm, target(halfedge(f,*poly),*poly));
380 
381           push_back_xyz(p0+v_offset, p_facets);
382           push_back_xyz(p1+v_offset, p_facets);
383           push_back_xyz(p2+v_offset, p_facets);
384 
385           push_back_xyz(nf, p_normals);
386           push_back_xyz(nf, p_normals);
387           push_back_xyz(nf, p_normals);
388         }
389       }
390       else
391       {
392         triangulate_facet(f, nf, p_facets, p_normals);
393       }
394     }
395 
396     //The Lines
397     {
398 
399         for(Selection_set_edge::iterator it = p_sel_edges.begin(); it != p_sel_edges.end(); ++it) {
400           const Point& a = get(vpm, target(halfedge(*it,*poly),*poly));
401           const Point& b = get(vpm, target(opposite((halfedge(*it,*poly)),*poly),*poly));
402             p_lines.push_back(a.x()+offset.x);
403             p_lines.push_back(a.y()+offset.y);
404             p_lines.push_back(a.z()+offset.z);
405 
406             p_lines.push_back(b.x()+offset.x);
407             p_lines.push_back(b.y()+offset.y);
408             p_lines.push_back(b.z()+offset.z);
409         }
410 
411     }
412     //The points
413     {
414         for(Selection_set_vertex::iterator
415             it = p_sel_vertices.begin(),
416             end = p_sel_vertices.end();
417             it != end; ++it)
418         {
419           const Point& p = get(vpm, *it);
420             p_points.push_back(p.x()+offset.x);
421             p_points.push_back(p.y()+offset.y);
422             p_points.push_back(p.z()+offset.z);
423         }
424     }
425 }
computeElements() const426 void Scene_polyhedron_selection_item_priv::computeElements()const
427 {
428   QApplication::setOverrideCursor(Qt::WaitCursor);
429   compute_any_elements(positions_facets, positions_lines, positions_points, normals,
430                        item->selected_vertices, item->selected_facets, item->selected_edges);
431 
432   item->getTriangleContainer(Facets)->allocate(
433         Tc::Flat_vertices,
434         positions_facets.data(),
435         static_cast<int>(positions_facets.size()*sizeof(float)));
436 
437   item->getTriangleContainer(Facets)->allocate(
438         Tc::Flat_normals,
439         normals.data(),
440         static_cast<int>(normals.size()*sizeof(float)));
441 
442   item->getPointContainer(Points)->allocate(
443         Pc::Vertices,
444         positions_points.data(),
445         static_cast<int>(positions_points.size()*sizeof(float)));
446 
447   item->getEdgeContainer(Edges)->allocate(
448         Ec::Vertices,
449         positions_lines.data(),
450         static_cast<int>(positions_lines.size()*sizeof(float)));
451 
452   nb_facets = positions_facets.size();
453   nb_lines = positions_lines.size();
454   nb_points = positions_points.size();
455   QApplication::restoreOverrideCursor();
456 }
compute_temp_elements() const457 void Scene_polyhedron_selection_item_priv::compute_temp_elements()const
458 {
459   QApplication::setOverrideCursor(Qt::WaitCursor);
460   compute_any_elements(positions_temp_facets, positions_temp_lines, positions_temp_points, temp_normals,
461                        item->temp_selected_vertices, item->temp_selected_facets, item->temp_selected_edges);
462   //The fixed points
463   {
464     const CGAL::qglviewer::Vec offset = Three::mainViewer()->offset();
465     color_fixed_points.clear();
466     positions_fixed_points.clear();
467     int i=0;
468 
469     constVPmap vpm = get(CGAL::vertex_point,*polyhedron());
470 
471     for(Scene_polyhedron_selection_item::Selection_set_vertex::iterator
472         it = item->fixed_vertices.begin(),
473         end = item->fixed_vertices.end();
474         it != end; ++it)
475     {
476       const Point& p = get(vpm,*it);
477       positions_fixed_points.push_back(p.x()+offset.x);
478       positions_fixed_points.push_back(p.y()+offset.y);
479       positions_fixed_points.push_back(p.z()+offset.z);
480 
481       if(*it == constrained_vertices.first()|| *it == constrained_vertices.last())
482       {
483         color_fixed_points.push_back(0.0);
484         color_fixed_points.push_back(0.0);
485         color_fixed_points.push_back(1.0);
486       }
487       else
488       {
489         color_fixed_points.push_back(1.0);
490         color_fixed_points.push_back(0.0);
491         color_fixed_points.push_back(0.0);
492       }
493       i++;
494     }
495   }
496 
497   item->getTriangleContainer(Temp_facets)->allocate(
498         Tc::Flat_vertices,
499         positions_temp_facets.data(),
500         static_cast<int>(positions_temp_facets.size()*sizeof(float)));
501   item->getTriangleContainer(Temp_facets)->allocate(
502         Tc::Flat_normals,
503         temp_normals.data(),
504         static_cast<int>(temp_normals.size()*sizeof(float)));
505 
506   item->getEdgeContainer(Temp_edges)->allocate(
507         Ec::Vertices,
508         positions_temp_lines.data(),
509         static_cast<int>(positions_temp_lines.size()*sizeof(float)));
510   item->getPointContainer(Temp_points)->allocate(
511         Pc::Vertices,
512         positions_temp_points.data(),
513         static_cast<int>(positions_temp_points.size()*sizeof(float)));
514 
515 item->getPointContainer(Fixed_points)->allocate(
516       Pc::Vertices,
517       positions_fixed_points.data(),
518       static_cast<int>(positions_fixed_points.size()*sizeof(float)));
519 
520   item->getPointContainer(Fixed_points)->allocate(
521         Pc::Colors,
522         color_fixed_points.data(),
523         static_cast<int>(color_fixed_points.size()*sizeof(float)));
524 
525   nb_temp_facets = positions_temp_facets.size();
526   nb_temp_lines = positions_temp_lines.size();
527   nb_temp_points = positions_temp_points.size();
528   nb_fixed_points = positions_fixed_points.size();
529   QApplication::restoreOverrideCursor();
530 }
531 
compute_HL_elements() const532 void Scene_polyhedron_selection_item_priv::compute_HL_elements()const
533 {
534   QApplication::setOverrideCursor(Qt::WaitCursor);
535   compute_any_elements(positions_HL_facets, positions_HL_lines, positions_HL_points, HL_normals,
536                        item->HL_selected_vertices, item->HL_selected_facets, item->HL_selected_edges);
537   item->getTriangleContainer(HL_facets)->allocate(
538         Tc::Flat_vertices,
539         positions_HL_facets.data(),
540         static_cast<int>(positions_HL_facets.size()*sizeof(float)));
541   item->getTriangleContainer(HL_facets)->allocate(
542         Tc::Flat_normals,
543         HL_normals.data(),
544         static_cast<int>(HL_normals.size()*sizeof(float)));
545 
546   item->getEdgeContainer(HL_edges)->allocate(
547         Ec::Vertices,
548         positions_HL_lines.data(),
549         static_cast<int>(positions_HL_lines.size()*sizeof(float)));
550 
551   item->getPointContainer(HL_points)->allocate(
552         Pc::Vertices,
553         positions_HL_points.data(),
554         static_cast<int>(positions_HL_points.size()*sizeof(float)));
555 
556   QApplication::restoreOverrideCursor();
557 }
558 
draw(CGAL::Three::Viewer_interface * viewer) const559 void Scene_polyhedron_selection_item::draw(CGAL::Three::Viewer_interface* viewer) const
560 {
561   GLfloat offset_factor;
562   GLfloat offset_units;
563   if(!isInit(viewer))
564     initGL(viewer);
565   if ( getBuffersFilled() &&
566        ! getBuffersInit(viewer))
567   {
568     initializeBuffers(viewer);
569     setBuffersInit(viewer, true);
570   }
571   if(!getBuffersFilled())
572   {
573     computeElements();
574     initializeBuffers(viewer);
575   }
576 
577   viewer->glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &offset_factor);
578   viewer->glGetFloatv(GL_POLYGON_OFFSET_UNITS, &offset_units);
579   viewer->glPolygonOffset(0.9f, 0.9f);
580 
581   getTriangleContainer(Priv::HL_facets)->setColor(QColor(255,153,51));
582   getTriangleContainer(Priv::HL_facets)->draw(viewer, true);
583 
584   getTriangleContainer(Priv::Temp_facets)->setColor(QColor(0,255,0));
585   getTriangleContainer(Priv::Temp_facets)->draw(viewer, true);
586 
587   getTriangleContainer(Priv::Facets)->setColor(this->color());
588   getTriangleContainer(Priv::Facets)->draw(viewer, true);
589 
590   viewer->glEnable(GL_POLYGON_OFFSET_LINE);
591   viewer->glPolygonOffset(0.3f, 0.3f);
592   drawEdges(viewer);
593   viewer->glDisable(GL_POLYGON_OFFSET_LINE);
594   viewer->glPolygonOffset(offset_factor, offset_units);
595   drawPoints(viewer);
596 }
597 
drawEdges(CGAL::Three::Viewer_interface * viewer) const598 void Scene_polyhedron_selection_item::drawEdges(CGAL::Three::Viewer_interface* viewer) const
599 {
600 
601   if(!isInit(viewer))
602     initGL(viewer);
603   if ( getBuffersFilled() &&
604        ! getBuffersInit(viewer))
605   {
606     initializeBuffers(viewer);
607     setBuffersInit(viewer, true);
608   }
609   if(!getBuffersFilled())
610   {
611     computeElements();
612     initializeBuffers(viewer);
613   }
614 
615   QVector2D vp(viewer->width(), viewer->height());
616   if(viewer->isOpenGL_4_3())
617   {
618 
619     getEdgeContainer(Priv::HL_edges)->setViewport(vp);
620     getEdgeContainer(Priv::HL_edges)->setWidth(3.0f);
621   }
622 
623   getEdgeContainer(Priv::HL_edges)->setColor(QColor(255,153,51));
624   getEdgeContainer(Priv::HL_edges)->draw(viewer, true);
625   if(viewer->isOpenGL_4_3())
626   {
627     getEdgeContainer(Priv::Temp_edges)->setViewport(vp);
628     getEdgeContainer(Priv::Temp_edges)->setWidth(3.0f);
629   }
630 
631   getEdgeContainer(Priv::Temp_edges)->setColor(QColor(0,200,0));
632   getEdgeContainer(Priv::Temp_edges)->draw(viewer, true);
633   if(viewer->isOpenGL_4_3())
634   {
635     getEdgeContainer(Priv::Edges)->setViewport(vp);
636     getEdgeContainer(Priv::Edges)->setWidth(3.0f);
637   }
638   getEdgeContainer(Priv::Edges)->setColor(QColor(255,
639                                                  color().blue()/2,
640                                                  color().green()/2));
641   getEdgeContainer(Priv::Edges)->draw(viewer, true);
642 }
643 
drawPoints(CGAL::Three::Viewer_interface * viewer) const644 void Scene_polyhedron_selection_item::drawPoints(CGAL::Three::Viewer_interface* viewer) const
645 {
646 
647   viewer->setGlPointSize(5.0f);
648 
649   if(!d->are_HL_buffers_filled)
650   {
651     d->compute_HL_elements();
652     d->initialize_HL_buffers(viewer);
653   }
654   getPointContainer(Priv::HL_points)->setColor(QColor(255,153,51));
655   getPointContainer(Priv::HL_points)->draw(viewer, true);
656   getPointContainer(Priv::Temp_points)->setColor(QColor(0,50,0));
657   getPointContainer(Priv::Temp_points)->draw(viewer, true);
658   getPointContainer(Priv::Fixed_points)->draw(viewer, false);
659   getPointContainer(Priv::Points)->setColor(QColor(255,
660                                                    (std::min)(color().blue()+color().red(), 255),
661                                                    (std::min)(color().green()+color().red(), 255)));
662   getPointContainer(Priv::Points)->draw(viewer, true);
663 
664   viewer->setGlPointSize(1.f);
665 }
666 
667 
inverse_selection()668 void Scene_polyhedron_selection_item::inverse_selection()
669 {
670   switch(k_ring_selector.active_handle_type)
671   {
672   case Active_handle::VERTEX:
673   {
674     Selection_set_vertex temp_select = selected_vertices;
675     select_all();
676     Q_FOREACH(fg_vertex_descriptor vh, temp_select)
677     {
678       selected_vertices.erase(vh);
679     }
680     break;
681   }
682   case Active_handle::EDGE:
683   {
684     Selection_set_edge temp_select = selected_edges;
685     select_all();
686     Q_FOREACH(fg_edge_descriptor ed , temp_select)
687       selected_edges.erase(ed);
688     break;
689   }
690   default:
691   {
692     Selection_set_facet temp_select = selected_facets;
693     select_all();
694     Q_FOREACH(fg_face_descriptor fh, temp_select)
695       selected_facets.erase(fh);
696     break;
697   }
698   }
699   invalidateOpenGLBuffers();
700 }
701 
set_num_faces(const std::size_t n)702 void Scene_polyhedron_selection_item::set_num_faces(const std::size_t n)
703 {
704   d->set_num_faces(n);
705 }
706 
set_highlighting(bool b)707 void Scene_polyhedron_selection_item::set_highlighting(bool b)
708 {
709   setProperty("is_highlighting", b);
710   k_ring_selector.setHighLighting(b);
711 }
set_operation_mode(int mode)712 void Scene_polyhedron_selection_item::set_operation_mode(int mode)
713 {
714   k_ring_selector.setEditMode(true);
715   Q_EMIT updateInstructions(QString("SHIFT + left click to apply operation."));
716   switch(mode)
717   {
718   case -2:
719     set_active_handle_type(d->original_sel_mode);
720     Q_EMIT updateInstructions("Select two vertices to create the path between them. (1/2)");
721     break;
722   case -1:
723     //restore original selection_type
724     set_active_handle_type(d->original_sel_mode);
725     clearHL();
726     k_ring_selector.setEditMode(false);
727     break;
728     //Join vertex
729   case 0:
730     Q_EMIT updateInstructions("Select the edge with extremities you want to join.");
731     //set the selection type to Edge
732     set_active_handle_type(static_cast<Active_handle::Type>(2));
733     break;
734     //Split vertex
735   case 1:
736     Q_EMIT updateInstructions("Select the vertex you want to split. (1/3)");
737     //set the selection type to Vertex
738     set_active_handle_type(static_cast<Active_handle::Type>(0));
739     break;
740     //Split edge
741   case 2:
742     Q_EMIT updateInstructions("Select the edge you want to split.");
743     //set the selection type to Edge
744     set_active_handle_type(static_cast<Active_handle::Type>(2));
745     break;
746     //Join face
747   case 3:
748     Q_EMIT updateInstructions("Select the edge separating the faces you want to join."
749                               "Warning: this operation will clear the undo stack.");
750     //set the selection type to Edge
751     set_active_handle_type(static_cast<Active_handle::Type>(2));
752     break;
753     //Split face
754   case 4:
755     Q_EMIT updateInstructions("Select the facet you want to split (degree >= 4). (1/3)");
756     //set the selection type to Facet
757     set_active_handle_type(static_cast<Active_handle::Type>(1));
758     break;
759     //Collapse edge
760   case 5:
761     Q_EMIT updateInstructions("Select the edge you want to collapse.");
762     //set the selection type to Edge
763     set_active_handle_type(static_cast<Active_handle::Type>(2));
764     break;
765     //Flip edge
766   case 6:
767     Q_EMIT updateInstructions("Select the edge you want to flip.");
768     //set the selection type to Edge
769     set_active_handle_type(static_cast<Active_handle::Type>(2));
770     break;
771     //Add center vertex
772   case 7:
773     Q_EMIT updateInstructions("Select a facet.");
774     //set the selection type to Facet
775     set_active_handle_type(static_cast<Active_handle::Type>(1));
776     break;
777     //Remove center vertex
778   case 8:
779     Q_EMIT updateInstructions("Select the vertex you want to remove."
780                               "Warning: This will clear the undo stack.");
781     //set the selection type to vertex
782     set_active_handle_type(static_cast<Active_handle::Type>(0));
783     break;
784     //Add vertex and face to border
785   case 9:
786     Q_EMIT updateInstructions("Select a border edge. (1/2)");
787     //set the selection type to Edge
788     set_active_handle_type(static_cast<Active_handle::Type>(2));
789     break;
790     //Add face to border
791   case 10:
792     Q_EMIT updateInstructions("Select a border edge. (1/2)");
793     //set the selection type to Edge
794     set_active_handle_type(static_cast<Active_handle::Type>(2));
795     break;
796   case 11:
797     Q_EMIT updateInstructions("Select a vertex. (1/2)");
798     //set the selection type to Edge
799     set_active_handle_type(static_cast<Active_handle::Type>(0));
800     break;
801   default:
802     break;
803   }
804   d->operation_mode = mode;
805 }
806 template<typename HandleRange>
treat_classic_selection(const HandleRange & selection)807 bool Scene_polyhedron_selection_item::treat_classic_selection(const HandleRange& selection)
808 {
809   typedef typename HandleRange::value_type HandleType;
810   Selection_traits<HandleType, Scene_polyhedron_selection_item> tr(this);
811   bool any_change = false;
812   if(is_insert) {
813     for(HandleType h : selection)
814         any_change |= tr.container().insert(h).second;
815   }
816   else{
817     for(HandleType h : selection)
818         any_change |= (tr.container().erase(h)!=0);
819   }
820   if(any_change) { invalidateOpenGLBuffers(); Q_EMIT itemChanged(); }
821   return any_change;
822 }
823 
824 struct Index_updator{
825   const SMesh::Halfedge_index& old_;
826   SMesh::Halfedge_index& new_;
Index_updatorIndex_updator827   Index_updator(const SMesh::Halfedge_index& _old,
828                 SMesh::Halfedge_index& _new)
829     :old_(_old), new_(_new){}
830   template<class V, class H, class F>
operator ()Index_updator831   void operator()(const V&, const H& hmap, const F&)
832   {
833     new_ = hmap[old_];
834   }
835 };
836 
treat_selection(const std::set<fg_vertex_descriptor> & selection)837 bool Scene_polyhedron_selection_item::treat_selection(const std::set<fg_vertex_descriptor>& selection)
838 {
839   VPmap vpm = get(CGAL::vertex_point, *polyhedron());
840   if(!d->is_treated)
841   {
842     fg_vertex_descriptor vh = *selection.begin();
843     Selection_traits<fg_vertex_descriptor, Scene_polyhedron_selection_item> tr(this);
844     switch(d->operation_mode)
845     {
846     //classic selection
847     case -2:
848     case -1:
849     {
850       if(!d->is_path_selecting)
851       {
852         return treat_classic_selection(selection);
853       }
854       else
855       {
856         if(is_insert)
857         {
858           selectPath(*selection.begin());
859           invalidateOpenGLBuffers();
860           Q_EMIT itemChanged();
861         }
862       }
863       return false;
864     }
865       //Split vertex
866     case 1:
867     {
868       //save VH
869       d->to_split_vh = vh;
870       temp_selected_vertices.insert(d->to_split_vh);
871       //set to select facet
872       set_active_handle_type(static_cast<Active_handle::Type>(1));
873       invalidateOpenGLBuffers();
874       Q_EMIT updateInstructions("Select first facet. (2/3)");
875       break;
876     }
877       //Split face
878     case 4:
879     {
880       static fg_vertex_descriptor s;
881       static fg_halfedge_descriptor h1,h2;
882       static bool found_h1(false), found_h2(false);
883       if(!d->first_selected)
884       {
885           //Is the vertex on the face ?
886         for(fg_halfedge_descriptor hafc : halfedges_around_face(halfedge(d->to_split_fh,*polyhedron()), *polyhedron()))
887           {
888             if(target(hafc,*polyhedron())==vh)
889             {
890               h1 = hafc;
891               s = vh;
892               found_h1 = true;
893                 break;
894             }
895           }
896           if(!found_h1)
897           {
898             d->tempInstructions("Vertex not selected : The vertex is not on the face.",
899                              "Select the first vertex. (2/3)");
900           }
901           else
902           {
903             d->first_selected = true;
904             temp_selected_vertices.insert(s);
905             invalidateOpenGLBuffers();
906             Q_EMIT updateInstructions("Select the second vertex (3/3)");
907           }
908       }
909       else
910       {
911         bool is_same(false), are_next(false);
912         for(int i=0; i<1; i++) //seems useless but allow the use of break.
913         {
914           //Is the vertex on the face ?
915           for(fg_halfedge_descriptor hafc : halfedges_around_face(halfedge(d->to_split_fh,*polyhedron()), *polyhedron()))
916             if(target(hafc,*polyhedron())==vh)
917           {
918             h2 = hafc;
919             found_h2 = true;
920             break;
921           }
922           if(!found_h2)
923           {
924             break;
925           }
926           //Are they different ?
927           if(h1 == h2)
928           {
929             is_same = true;
930             break;
931           }
932           is_same = false;
933           //Are they directly following each other?
934           if(next(h1, *polyhedron()) == h2 ||
935              next(h2, *polyhedron()) == h1)
936           {
937             are_next = true;
938             break;
939           }
940           are_next = false;
941         }
942         if(!found_h2)
943           d->tempInstructions("Vertex not selected : The vertex is not on the face.",
944                            "Select the second vertex (3/3).");
945         else if(is_same)
946           d->tempInstructions("Vertex not selected : The vertices must be different.",
947                            "Select the second vertex (3/3).");
948         else if(are_next)
949           d->tempInstructions("Vertex not selected : The vertices must not directly follow each other.",
950                            "Select the second vertex (3/3).");
951         else
952         {
953           SMesh* mesh = polyhedron();
954           fg_halfedge_descriptor h;
955           h = CGAL::Euler::split_face(h1,h2, *mesh);
956           d->stack.push(new EulerOperation(//the stack takes ownership of the cmd, so no worries
957           [h, mesh](){
958             CGAL::Euler::join_face(h,*mesh);
959           }, this));
960           d->first_selected = false;
961           temp_selected_vertices.clear();
962           temp_selected_facets.clear();
963           compute_normal_maps();
964           invalidateOpenGLBuffers();
965           //reset selection type to Facet
966           set_active_handle_type(static_cast<Active_handle::Type>(1));
967           d->tempInstructions("Face split.",
968                            "Select a facet (1/3).");
969           polyhedron_item()->resetColors();
970           polyhedron_item()->invalidateOpenGLBuffers();
971         }
972       }
973       break;
974     }
975       //Remove center vertex
976     case 8:
977     {
978       bool has_hole = false;
979       for(fg_halfedge_descriptor hc : halfedges_around_target(vh,*polyhedron()))
980       {
981         if(is_border(hc,*polyhedron()))
982         {
983           has_hole = true;
984           break;
985         }
986       }
987       if(!has_hole)
988       {
989         SMesh* mesh = polyhedron();
990         halfedge_descriptor hd = halfedge(vh,*mesh);
991         Point_3 p = get(vpm, target(hd, *mesh));
992         halfedge_descriptor hhandle = CGAL::Euler::remove_center_vertex(hd,*mesh);
993         halfedge_descriptor new_h;
994         Index_updator iu(hhandle, new_h);
995         mesh->collect_garbage(iu);
996         d->stack.clear();
997         d->stack.push(new EulerOperation(
998                         [new_h, p, mesh, vpm](){
999 
1000           halfedge_descriptor h = CGAL::Euler::add_center_vertex(
1001                 new_h, *mesh);
1002           put(vpm, target(h,*mesh), p);
1003 
1004         }, this));
1005         compute_normal_maps();
1006         polyhedron_item()->invalidateOpenGLBuffers();
1007       }
1008       else
1009       {
1010         d->tempInstructions("Vertex not selected : There must be no hole incident to the selection.",
1011                          "Select the vertex you want to remove."
1012                          "Warning: This will clear the undo stack.");
1013       }
1014       break;
1015     }
1016     case 11:
1017       CGAL::QGLViewer* viewer = Three::mainViewer();
1018       const CGAL::qglviewer::Vec offset = viewer->offset();
1019       if(viewer->manipulatedFrame() != d->manipulated_frame)
1020       {
1021         temp_selected_vertices.insert(vh);
1022         k_ring_selector.setEditMode(false);
1023         const Point_3& p = get(vpm,vh);
1024         d->manipulated_frame->setPosition(p.x()+offset.x, p.y()+offset.y, p.z()+offset.z);
1025         viewer->setManipulatedFrame(d->manipulated_frame);
1026         connect(d->manipulated_frame, SIGNAL(modified()), this, SLOT(updateTick()));
1027         if(property("is_highlighting").toBool())
1028         {
1029           setProperty("need_hl_restore", true);
1030           set_highlighting(false);
1031         }
1032         if(property("need_invalidate_aabb_tree").toBool()){
1033           polyhedron_item()->invalidate_aabb_tree();
1034           setProperty("need_invalidate_aabb_tree", false);
1035         }
1036         invalidateOpenGLBuffers();
1037         Q_EMIT updateInstructions("Ctrl+Right-click to move the point. \nHit Ctrl+Z to leave the selection. (2/2)");
1038       }
1039       else
1040       {
1041         temp_selected_vertices.clear();
1042         temp_selected_vertices.insert(vh);
1043         const Point_3& p = get(vpm,vh);
1044         d->manipulated_frame->setPosition(p.x()+offset.x, p.y()+offset.y, p.z()+offset.z);
1045         if(property("is_highlighting").toBool())
1046         {
1047           setProperty("need_hl_restore", true);
1048           set_highlighting(false);
1049         }
1050         invalidateOpenGLBuffers();
1051       }
1052       break;
1053     }
1054   }
1055   d->is_treated = true;
1056   //Keeps the item from trying to draw primitive that has just been deleted.
1057   clearHL();
1058   return false;
1059 }
1060 
1061 //returns true if halfedge's facet's degree >= degree
1062 /*
1063 std::size_t facet_degree(fg_halfedge_descriptor h, const Face_graph& polyhedron)
1064 {
1065   return degree(h,polyhedron);
1066 }
1067 */
treat_selection(const std::set<fg_edge_descriptor> & selection)1068 bool Scene_polyhedron_selection_item:: treat_selection(const std::set<fg_edge_descriptor>& selection)
1069 {
1070   VPmap vpm = get(CGAL::vertex_point, *polyhedron());
1071   fg_edge_descriptor ed =  *selection.begin();
1072   if(!d->is_treated)
1073   {
1074     Selection_traits<fg_edge_descriptor, Scene_polyhedron_selection_item> tr(this);
1075     switch(d->operation_mode)
1076     {
1077     //classic selection
1078     case -1:
1079     {
1080       return treat_classic_selection(selection);
1081     }
1082       //Join vertex
1083     case 0:
1084       if(boost::distance(CGAL::halfedges_around_face(halfedge(ed, *polyhedron()), *polyhedron())) < 4
1085            ||
1086          boost::distance(CGAL::halfedges_around_face(opposite(halfedge(ed, *polyhedron()),*polyhedron()),*polyhedron()))< 4)
1087         {
1088           d->tempInstructions("Edge not selected: the incident facets must have a degree of at least 4.",
1089                            "Select the edge with extremities you want to join.");
1090         }
1091         else
1092         {
1093           fg_halfedge_descriptor targt = halfedge(ed, *polyhedron());
1094           Point S,T;
1095           S = get(vpm, source(targt, *polyhedron()));
1096           T = get(vpm, target(targt, *polyhedron()));
1097           put(vpm, target(CGAL::Euler::join_vertex(targt,*polyhedron()),*polyhedron()), Point(0.5*(S.x()+T.x()), 0.5*(S.y()+T.y()), 0.5*(S.z()+T.z())));
1098           d->tempInstructions("Vertices joined.",
1099                            "Select the edge with extremities you want to join.");
1100           compute_normal_maps();
1101           invalidateOpenGLBuffers();
1102           polyhedron_item()->invalidateOpenGLBuffers();
1103         }
1104       break;
1105       //Split edge
1106     case 2:
1107     {
1108 
1109       SMesh* mesh = polyhedron();
1110       Point_3 a(get(vpm,target(halfedge(ed, *mesh),*mesh))),
1111           b(get(vpm,target(opposite(halfedge(ed, *mesh),*mesh),*mesh)));
1112       fg_halfedge_descriptor hhandle = CGAL::Euler::split_edge(halfedge(ed, *mesh),*mesh);
1113       d->stack.push(new EulerOperation(
1114                       [hhandle, mesh, vpm](){
1115         Point_3 p(get(vpm,source(hhandle,*mesh)));
1116         halfedge_descriptor h = CGAL::Euler::join_vertex(hhandle, *mesh);
1117         put(vpm, target(h,*mesh), p);
1118       }, this));
1119       Point_3 p((b.x()+a.x())/2.0, (b.y()+a.y())/2.0,(b.z()+a.z())/2.0);
1120 
1121       put(vpm, target(hhandle,*mesh), p);
1122       invalidateOpenGLBuffers();
1123       poly_item->invalidateOpenGLBuffers();
1124       compute_normal_maps();
1125       d->tempInstructions("Edge splitted.",
1126                           "Select the edge you want to split.");
1127       break;
1128     }
1129       //Join face
1130     case 3:
1131         if(out_degree(source(halfedge(ed,*polyhedron()),*polyhedron()),*polyhedron())<3 ||
1132            out_degree(target(halfedge(ed,*polyhedron()),*polyhedron()),*polyhedron())<3)
1133           d->tempInstructions("Faces not joined : the two ends of the edge must have a degree of at least 3.",
1134                            "Select the edge separating the faces you want to join."
1135                            "Warning: this operation will clear the undo stack.");
1136         else
1137         {
1138           SMesh* mesh = polyhedron();
1139           vertex_descriptor v1(source(ed, *mesh)),
1140               v2(target(ed, *mesh));
1141           d->stack.clear();
1142           d->stack.push(new EulerOperation(
1143                           [v1,v2,mesh](){
1144             CGAL::Euler::split_face(
1145                   halfedge(v1, *mesh),
1146                   halfedge(v2, *mesh),
1147                   *mesh);
1148           }, this));
1149           CGAL::Euler::join_face(halfedge(ed, *mesh), *mesh);
1150           compute_normal_maps();
1151           poly_item->invalidateOpenGLBuffers();
1152         }
1153       break;
1154       //Collapse edge
1155     case 5:
1156         if(!is_triangle_mesh(*polyhedron()))
1157         {
1158           d->tempInstructions("Edge not collapsed : the graph must be triangulated.",
1159                            "Select the edge you want to collapse.");
1160         }
1161         else if(!CGAL::Euler::does_satisfy_link_condition(ed, *polyhedron()))
1162         {
1163           d->tempInstructions("Edge not collapsed : link condition not satidfied.",
1164                            "Select the edge you want to collapse.");
1165         }
1166         else
1167         {
1168           fg_halfedge_descriptor targt = halfedge(ed, *polyhedron());
1169           Point S,T;
1170           S = get(vpm, source(targt, *polyhedron()));
1171           T = get(vpm, target(targt, *polyhedron()));
1172 
1173           put(vpm, CGAL::Euler::collapse_edge(ed, *polyhedron()), Point(0.5*(S.x()+T.x()), 0.5*(S.y()+T.y()), 0.5*(S.z()+T.z())));
1174           compute_normal_maps();
1175           polyhedron_item()->invalidateOpenGLBuffers();
1176 
1177           d->tempInstructions("Edge collapsed.",
1178                            "Select the edge you want to collapse.");
1179         }
1180       break;
1181       //Flip edge
1182     case 6:
1183 
1184         //check preconditions
1185       if(boost::distance(CGAL::halfedges_around_face(halfedge(ed, *polyhedron()),*polyhedron())) == 3
1186          &&
1187          boost::distance(CGAL::halfedges_around_face(opposite(halfedge(ed, *polyhedron()),*polyhedron()),*polyhedron())) == 3
1188         && !CGAL::is_border(ed, *polyhedron()))
1189       {
1190         SMesh* mesh = polyhedron();
1191         halfedge_descriptor h = halfedge(ed, *mesh);
1192         CGAL::Euler::flip_edge(h, *mesh);
1193         d->stack.push(new EulerOperation(
1194                         [h, mesh](){
1195           CGAL::Euler::flip_edge(h, *mesh);
1196         }, this));
1197         polyhedron_item()->invalidateOpenGLBuffers();
1198         compute_normal_maps();
1199       }
1200       else
1201       {
1202         d->tempInstructions("Edge not selected : incident facets must be triangles.",
1203                             "Select the edge you want to flip.");
1204       }
1205 
1206       break;
1207       //Add vertex and face to border
1208     case 9:
1209     {
1210       static fg_halfedge_descriptor t;
1211       if(!d->first_selected)
1212       {
1213           bool found = false;
1214           fg_halfedge_descriptor hc = halfedge(ed, *polyhedron());
1215           if(is_border(hc,*polyhedron()))
1216           {
1217             t = hc;
1218             found = true;
1219           }
1220           else if(is_border(opposite(hc,*polyhedron()),*polyhedron()))
1221           {
1222             t = opposite(hc,*polyhedron());
1223             found = true;
1224           }
1225           if(found)
1226           {
1227             d->first_selected = true;
1228             temp_selected_edges.insert(edge(t, *polyhedron()));
1229             temp_selected_vertices.insert(target(t,*polyhedron()));
1230             invalidateOpenGLBuffers();
1231             Q_EMIT updateInstructions("Select second edge. (2/2)");
1232           }
1233           else
1234           {
1235             d->tempInstructions("Edge not selected : no border found.",
1236                              "Select a border edge. (1/2)");
1237           }
1238       }
1239       else
1240       {
1241         fg_halfedge_descriptor hc = halfedge(ed, *polyhedron());
1242         if(d->canAddFaceAndVertex(hc, t))
1243         {
1244           d->first_selected = false;
1245 
1246 
1247           temp_selected_edges.clear();
1248           temp_selected_vertices.clear();
1249           compute_normal_maps();
1250           polyhedron_item()->resetColors();
1251           invalidateOpenGLBuffers();
1252           polyhedron_item()->invalidateOpenGLBuffers();
1253           d->tempInstructions("Face and vertex added.",
1254                            "Select a border edge. (1/2)");
1255         }
1256       }
1257       break;
1258     }
1259       //Add face to border
1260     case 10:
1261     {
1262       static fg_halfedge_descriptor t;
1263       if(!d->first_selected)
1264       {
1265           bool found = false;
1266           fg_halfedge_descriptor hc = halfedge(ed, *polyhedron());
1267           if(is_border(hc,*polyhedron()))
1268           {
1269             t = hc;
1270             found = true;
1271           }
1272           else if(is_border(opposite(hc,*polyhedron()),*polyhedron()))
1273           {
1274             t = opposite(hc,*polyhedron());
1275             found = true;
1276           }
1277           if(found)
1278           {
1279             d->first_selected = true;
1280             temp_selected_edges.insert(edge(t, *polyhedron()));
1281             temp_selected_vertices.insert(target(t,*polyhedron()));
1282             invalidateOpenGLBuffers();
1283             Q_EMIT updateInstructions("Select second edge. (2/2)");
1284             set_active_handle_type(static_cast<Active_handle::Type>(2));
1285           }
1286           else
1287           {
1288             d->tempInstructions("Edge not selected : no border found.",
1289                              "Select a border edge. (1/2)");
1290           }
1291       }
1292       else
1293       {
1294         fg_halfedge_descriptor hc = halfedge(ed, *polyhedron());
1295         if(d->canAddFace(hc, t))
1296         {
1297           d->first_selected = false;
1298           temp_selected_vertices.clear();
1299           temp_selected_edges.clear();
1300           compute_normal_maps();
1301           polyhedron_item()->resetColors();
1302           invalidateOpenGLBuffers();
1303           polyhedron_item()->invalidateOpenGLBuffers();
1304           d->tempInstructions("Face added.",
1305                            "Select a border edge. (1/2)");
1306         }
1307       }
1308       break;
1309     }
1310     }
1311   }
1312   d->is_treated = true;
1313   //Keeps the item from trying to draw primitive that has just been deleted.
1314   clearHL();
1315   return false;
1316 }
1317 
treat_selection(const std::vector<fg_face_descriptor> & selection)1318 bool Scene_polyhedron_selection_item::treat_selection(const std::vector<fg_face_descriptor>& selection)
1319 {
1320   return treat_classic_selection(selection);
1321 }
1322 
treat_selection(const std::set<fg_face_descriptor> & selection)1323 bool Scene_polyhedron_selection_item::treat_selection(const std::set<fg_face_descriptor>& selection)
1324 {
1325   VPmap vpm = get(CGAL::vertex_point,*polyhedron());
1326   if(!d->is_treated)
1327   {
1328     fg_face_descriptor fh = *selection.begin();
1329     Selection_traits<fg_face_descriptor, Scene_polyhedron_selection_item> tr(this);
1330     switch(d->operation_mode)
1331     {
1332     //classic selection
1333     case -1:
1334     {
1335       return treat_classic_selection(selection);
1336     }
1337     //Split vertex
1338     case 1:
1339     {
1340       static fg_halfedge_descriptor h1;
1341       //stores first fh and emit change label
1342       if(!d->first_selected)
1343       {
1344           bool found = false;
1345           //test preco
1346           for(fg_halfedge_descriptor hafc : halfedges_around_face(halfedge(fh,*polyhedron()),*polyhedron()))
1347           {
1348             if(target(hafc,*polyhedron())==d->to_split_vh)
1349             {
1350               h1 = hafc;
1351               found = true;
1352               break;
1353             }
1354           }
1355           if(found)
1356           {
1357             d->first_selected = true;
1358             temp_selected_facets.insert(fh);
1359             invalidateOpenGLBuffers();
1360             Q_EMIT updateInstructions("Select the second facet. (3/3)");
1361           }
1362           else
1363             d->tempInstructions("Facet not selected : no valid halfedge",
1364                              "Select first facet. (2/3)");
1365       }
1366       //call the function with point and facets.
1367       else
1368       {
1369           //get the right halfedges
1370           fg_halfedge_descriptor h2;
1371           bool found = false;
1372           for(fg_halfedge_descriptor hafc : halfedges_around_face(halfedge(fh,*polyhedron()),*polyhedron()))
1373           {
1374             if(target(hafc,*polyhedron())==d->to_split_vh)
1375             {
1376               h2 = hafc;
1377               found = true;
1378               break;
1379             }
1380           }
1381 
1382           if(found &&(h1 != h2))
1383           {
1384             SMesh* mesh = polyhedron();
1385             Point p = get(vpm, target(h1, *mesh));
1386             fg_halfedge_descriptor hhandle = CGAL::Euler::split_vertex(h1,h2,*mesh);
1387             d->stack.push(new EulerOperation(
1388                             [hhandle, mesh, vpm, p](){
1389               halfedge_descriptor h = CGAL::Euler::join_vertex(hhandle, *mesh);
1390               put(vpm, target(h,*mesh), p);
1391             }, this));
1392             temp_selected_facets.clear();
1393             Point_3 p1t = get(vpm, target(h1,*mesh));
1394             Point_3 p1s = get(vpm, target(opposite(h1,*mesh),*mesh));
1395             double x =  p1t.x() + 0.01 * (p1s.x() - p1t.x());
1396             double y =  p1t.y() + 0.01 * (p1s.y() - p1t.y());
1397             double z =  p1t.z() + 0.01 * (p1s.z() - p1t.z());
1398             put(vpm, target(opposite(hhandle,*mesh),*mesh), Point_3(x,y,z));;
1399             d->first_selected = false;
1400             temp_selected_vertices.clear();
1401             compute_normal_maps();
1402             invalidateOpenGLBuffers();
1403             //reset selection mode
1404             set_active_handle_type(static_cast<Active_handle::Type>(0));
1405             poly_item->resetColors();
1406             poly_item->invalidateOpenGLBuffers();
1407             d->tempInstructions("Vertex splitted.", "Select the vertex you want splitted. (1/3)");
1408           }
1409           else if(h1 == h2)
1410           {
1411              d->tempInstructions("Facet not selected : same as the first.", "Select the second facet. (3/3)");
1412           }
1413           else
1414           {
1415             d->tempInstructions("Facet not selected : no valid halfedge.", "Select the second facet. (3/3)");
1416           }
1417       }
1418       break;
1419     }
1420       //Split face
1421     case 4:
1422       if(is_triangle(halfedge(fh,*d->poly), *d->poly))
1423       {
1424         d->tempInstructions("Facet not selected : Facet must not be a triangle.",
1425                          "Select the facet you want to split (degree >= 4). (1/3)");
1426       }
1427       else
1428       {
1429         d->to_split_fh = fh;
1430         temp_selected_facets.insert(d->to_split_fh);
1431         compute_normal_maps();
1432         invalidateOpenGLBuffers();
1433         //set to select vertex
1434         set_active_handle_type(static_cast<Active_handle::Type>(0));
1435         Q_EMIT updateInstructions("Select first vertex. (2/3)");
1436       }
1437       break;
1438       //Add center vertex
1439     case 7:
1440       if(is_border(halfedge(fh,*polyhedron()),*polyhedron()))
1441         {
1442           d->tempInstructions("Facet not selected : Facet must not be null.",
1443                            "Select a Facet. (1/3)");
1444         }
1445         else
1446         {
1447         SMesh* mesh = polyhedron();
1448           double x(0), y(0), z(0);
1449           int total(0);
1450 
1451           for(fg_halfedge_descriptor hafc : halfedges_around_face(halfedge(fh,*mesh),*mesh))
1452           {
1453             fg_vertex_descriptor vd = target(hafc,*mesh);
1454             Point_3& p = get(vpm,vd);
1455             x+= p.x(); y+=p.y(); z+=p.z();
1456             total++;
1457           }
1458           fg_halfedge_descriptor hhandle = CGAL::Euler::add_center_vertex(halfedge(fh,*mesh), *mesh);
1459           d->stack.push(new EulerOperation(
1460                           [hhandle, mesh](){
1461             CGAL::Euler::remove_center_vertex(hhandle, *mesh);
1462           }, this));
1463           if(total !=0)
1464             put(vpm, target(hhandle,*mesh), Point_3(x/(double)total, y/(double)total, z/(double)total));
1465           compute_normal_maps();
1466           polyhedron_item()->resetColors();
1467           poly_item->invalidateOpenGLBuffers();
1468 
1469         }
1470       break;
1471     }
1472   }
1473   d->is_treated = true;
1474   //Keeps the item from trying to draw primitive that has just been deleted.
1475   clearHL();
1476   return false;
1477 }
1478 
tempInstructions(QString s1,QString s2)1479 void Scene_polyhedron_selection_item_priv::tempInstructions(QString s1, QString s2)
1480 {
1481   m_temp_instructs = s2;
1482   Q_EMIT item->updateInstructions(QString("<font color='red'>%1</font>").arg(s1));
1483   QTimer timer;
1484   timer.singleShot(5500, item, SLOT(emitTempInstruct()));
1485 }
emitTempInstruct()1486 void Scene_polyhedron_selection_item::emitTempInstruct()
1487 {
1488   Q_EMIT updateInstructions(QString("<font color='black'>%1</font>").arg(d->m_temp_instructs));
1489 }
1490 
1491 /// An exception used while catching a throw that stops Dijkstra's algorithm
1492 /// once the shortest path to a target has been found.
1493 class Dijkstra_end_exception : public std::exception
1494 {
what() const1495   const char* what() const throw ()
1496   {
1497     return "Dijkstra shortest path: reached the target vertex.";
1498   }
1499 };
1500 
1501 /// Visitor to stop Dijkstra's algorithm once the given target turns 'BLACK',
1502 /// that is when the target has been examined through all its incident edges and
1503 /// the shortest path is thus known.
1504 class Stop_at_target_Dijkstra_visitor : boost::default_dijkstra_visitor
1505 {
1506   fg_vertex_descriptor destination_vd;
1507 
1508 public:
Stop_at_target_Dijkstra_visitor(fg_vertex_descriptor destination_vd)1509   Stop_at_target_Dijkstra_visitor(fg_vertex_descriptor destination_vd)
1510     : destination_vd(destination_vd)
1511   { }
1512 
initialize_vertex(const fg_vertex_descriptor &,const Face_graph &) const1513   void initialize_vertex(const fg_vertex_descriptor& /*s*/, const Face_graph& /*mesh*/) const { }
examine_vertex(const fg_vertex_descriptor &,const Face_graph &) const1514   void examine_vertex(const fg_vertex_descriptor& /*s*/, const Face_graph& /*mesh*/) const { }
examine_edge(const fg_edge_descriptor &,const Face_graph &) const1515   void examine_edge(const fg_edge_descriptor& /*e*/, const Face_graph& /*mesh*/) const { }
edge_relaxed(const fg_edge_descriptor &,const Face_graph &) const1516   void edge_relaxed(const fg_edge_descriptor& /*e*/, const Face_graph& /*mesh*/) const { }
discover_vertex(const fg_vertex_descriptor &,const Face_graph &) const1517   void discover_vertex(const fg_vertex_descriptor& /*s*/, const Face_graph& /*mesh*/) const { }
edge_not_relaxed(const fg_edge_descriptor &,const Face_graph &) const1518   void edge_not_relaxed(const fg_edge_descriptor& /*e*/, const Face_graph& /*mesh*/) const { }
finish_vertex(const fg_vertex_descriptor & vd,const Face_graph &) const1519   void finish_vertex(const fg_vertex_descriptor &vd, const Face_graph& /* mesh*/) const
1520   {
1521     if(vd == destination_vd)
1522       throw Dijkstra_end_exception();
1523   }
1524 };
1525 
computeAndDisplayPath()1526 void Scene_polyhedron_selection_item_priv::computeAndDisplayPath()
1527 {
1528   item->temp_selected_edges.clear();
1529   path.clear();
1530 
1531   typedef boost::unordered_map<fg_vertex_descriptor, fg_vertex_descriptor>     Pred_umap;
1532   typedef boost::associative_property_map<Pred_umap>                     Pred_pmap;
1533 
1534   Pred_umap predecessor;
1535   Pred_pmap pred_pmap(predecessor);
1536 
1537   vertex_on_path vop;
1538   QList<fg_vertex_descriptor>::iterator it;
1539   for(it = constrained_vertices.begin(); it!=constrained_vertices.end()-1; ++it)
1540   {
1541     fg_vertex_descriptor t(*it), s(*(it+1));
1542     Stop_at_target_Dijkstra_visitor vis(t);
1543 
1544     try
1545     {
1546       boost::dijkstra_shortest_paths(*item->polyhedron(), s,
1547                                      boost::predecessor_map(pred_pmap).visitor(vis));
1548     }
1549     catch (const std::exception& e)
1550     {
1551       std::cout << e.what() << std::endl;
1552     }
1553 
1554     // Walk back from target to source and collect vertices along the way
1555     do
1556     {
1557       vop.vertex = t;
1558       if(constrained_vertices.contains(t))
1559       {
1560         vop.is_constrained = true;
1561       }
1562       else
1563         vop.is_constrained = false;
1564       path.append(vop);
1565       t = get(pred_pmap, t);
1566     }
1567     while(t != s);
1568   }
1569 
1570   // Add the last vertex
1571   vop.vertex = constrained_vertices.last();
1572   vop.is_constrained = true;
1573   path.append(vop);
1574 
1575   // Display path
1576   double path_length = 0;
1577   QList<vertex_on_path>::iterator path_it;
1578   for(path_it = path.begin(); path_it!=path.end()-1; ++path_it)
1579   {
1580     std::pair<fg_halfedge_descriptor, bool> h = halfedge((path_it+1)->vertex,path_it->vertex,*item->polyhedron());
1581     if(h.second)
1582     {
1583       VPmap vpm = get(CGAL::vertex_point,*polyhedron());
1584       Point p1(get(vpm, (path_it+1)->vertex)), p2(get(vpm, path_it->vertex));
1585           path_length += CGAL::sqrt(Vector(p1,p2).squared_length());
1586       item->temp_selected_edges.insert(edge(h.first, *item->polyhedron()));
1587     }
1588   }
1589   item->printMessage(QString("New path length: %1").arg(path_length));
1590 }
1591 
addVertexToPath(fg_vertex_descriptor vh,vertex_on_path & first)1592 void Scene_polyhedron_selection_item_priv::addVertexToPath(fg_vertex_descriptor vh, vertex_on_path &first)
1593 {
1594   vertex_on_path source;
1595   source.vertex = vh;
1596   source.is_constrained = true;
1597   path.append(source);
1598   first = source;
1599 }
selectPath(fg_vertex_descriptor vh)1600 void Scene_polyhedron_selection_item::selectPath(fg_vertex_descriptor vh)
1601 {
1602 
1603   bool replace = !temp_selected_edges.empty();
1604   static Scene_polyhedron_selection_item_priv::vertex_on_path first;
1605   if(!d->first_selected)
1606   {
1607     //if the path doesnt exist, add the vertex as the source of the path.
1608     if(!replace)
1609     {
1610       d->addVertexToPath(vh, first);
1611     }
1612     //if the path exists, get the vertex_on_path corresponding to the selected vertex.
1613     else
1614     {
1615       //The first vertex of the path can not be moved, but you can close your path on it to make a loop.
1616       bool alone = true;
1617       QList<Scene_polyhedron_selection_item_priv::vertex_on_path>::iterator it;
1618       for(it = d->path.begin(); it!=d->path.end(); ++it)
1619       {
1620         if(it->vertex == vh&& it!=d->path.begin())
1621           alone = false;
1622       }
1623       if(d->path.begin()->vertex == vh )
1624         if(alone)
1625         {
1626           d->constrained_vertices.append(vh); //if the path loops, the indexOf may be invalid, hence the check.
1627           //Display the new path
1628           d->computeAndDisplayPath();
1629           d->first_selected = false;
1630           d->constrained_vertices.clear();
1631           fixed_vertices.clear();
1632           for(it = d->path.begin(); it!=d->path.end(); ++it)
1633           {
1634             if(it->is_constrained )
1635             {
1636               d->constrained_vertices.append(it->vertex);
1637               fixed_vertices.insert(it->vertex);
1638             }
1639           }
1640 
1641           return;
1642         }
1643       bool found = false;
1644       Q_FOREACH(Scene_polyhedron_selection_item_priv::vertex_on_path vop, d->path)
1645       {
1646         if(vop.vertex == vh)
1647         {
1648           first = vop;
1649           found = true;
1650           break;
1651         }
1652       }
1653       if(!found)//add new end_point;
1654       {
1655         d->constrained_vertices.append(vh);
1656         //Display the new path
1657         d->computeAndDisplayPath();
1658         d->first_selected = false;
1659         d->constrained_vertices.clear();
1660         fixed_vertices.clear();
1661         for(it = d->path.begin(); it!=d->path.end(); ++it)
1662         {
1663           if(it->is_constrained )
1664           {
1665             d->constrained_vertices.append(it->vertex);
1666             fixed_vertices.insert(it->vertex);
1667           }
1668         }
1669 
1670         return;
1671       }
1672     }
1673     temp_selected_vertices.insert(vh);
1674     d->first_selected = true;
1675   }
1676   else
1677   {
1678     if(!replace)
1679     {
1680       d->constrained_vertices.append(vh);
1681       temp_selected_vertices.erase(first.vertex);
1682 
1683       updateInstructions("You can select a vertex on the green path to move it. "
1684                          "If you do so, it will become a red fixed point. "
1685                          "The path will be recomputed to go through that point. "
1686                          "Click on 'Add to selection' to validate the selection.   (2/2)");
1687     }
1688     else
1689     {
1690       bool is_same(false), alone(true);
1691       if( (vh == d->constrained_vertices.first() && first.vertex == d->constrained_vertices.last())
1692           || (vh == d->constrained_vertices.last() && first.vertex == d->constrained_vertices.first()))
1693 
1694       {
1695         is_same = true;
1696       }
1697       if(first.vertex == d->path.begin()->vertex)
1698         alone =false;
1699       bool is_last = true;
1700       //find the previous constrained vertex on path
1701       Scene_polyhedron_selection_item_priv::vertex_on_path closest = d->path.last();
1702       QList<Scene_polyhedron_selection_item_priv::vertex_on_path>::iterator it;
1703       int index = 0;
1704       int closest_index = 0;
1705       //get first's index
1706       for(it = d->path.begin(); it!=d->path.end(); ++it)
1707       {
1708         bool end_of_path_is_prio = true;//makes the end of the path prioritary over the other points when there is a conflict
1709         if(first.vertex == (d->path.end()-1)->vertex)
1710           if(it != d->path.end()-1)
1711             end_of_path_is_prio = false;
1712         //makes the end of the path prioritary over the other points when there is a conflict
1713         if(it->vertex == first.vertex &&
1714            !(it == d->path.begin())&&// makes the beginning of the path impossible to move
1715            end_of_path_is_prio)
1716         {
1717           if(it!=d->path.end()-1 &&! is_same )
1718           {
1719             d->constrained_vertices.removeAll(it->vertex);
1720             if(!alone)
1721               d->constrained_vertices.prepend(it->vertex);
1722           }
1723           d->path.erase(it);
1724           break;
1725         }
1726         if(it->is_constrained)
1727           closest_index++;
1728         index++;
1729       }
1730       //get first constrained vertex following first in path
1731       for(it = d->path.begin() + index; it!=d->path.end(); ++it)
1732       {
1733         if(it->is_constrained )
1734         {
1735           is_last = false;
1736           closest = *it;
1737           break;
1738         }
1739       }
1740       //mark the new vertex as constrained before closest.
1741       temp_selected_vertices.erase(first.vertex);
1742       //check if the vertex is contained several times in the path
1743       if(!is_last)
1744       {
1745         d->constrained_vertices.insert(closest_index, vh);//cannot really use indexOf in case a fixed_point is used several times
1746       }
1747       else
1748         d->constrained_vertices.replace(d->constrained_vertices.size()-1, vh);
1749 
1750 
1751     }
1752     //Display the new path
1753     d->computeAndDisplayPath();
1754     d->first_selected = false;
1755   }
1756   //update constrained_vertices
1757   d->constrained_vertices.clear();
1758   fixed_vertices.clear();
1759   QList<Scene_polyhedron_selection_item_priv::vertex_on_path>::iterator it;
1760   for(it = d->path.begin(); it!=d->path.end(); ++it)
1761   {
1762     if(it->is_constrained )
1763     {
1764       d->constrained_vertices.append(it->vertex);
1765       fixed_vertices.insert(it->vertex);
1766     }
1767   }
1768 }
1769 
1770 
on_Ctrlz_pressed()1771 void Scene_polyhedron_selection_item::on_Ctrlz_pressed()
1772 {
1773   d->path.clear();
1774   d->constrained_vertices.clear();
1775   fixed_vertices.clear();
1776   validateMoveVertex();
1777   d->first_selected = false;
1778   temp_selected_vertices.clear();
1779   temp_selected_edges.clear();
1780   temp_selected_facets.clear();
1781   d->are_temp_buffers_filled = false;
1782   set_operation_mode(d->operation_mode);
1783   Q_EMIT itemChanged();
1784 }
1785 
on_Ctrlu_pressed()1786 void Scene_polyhedron_selection_item::on_Ctrlu_pressed()
1787 {
1788   if(d->stack.canUndo())
1789     d->stack.undo();
1790 }
1791 
common_constructor()1792 void Scene_polyhedron_selection_item::common_constructor()
1793 {
1794   d = new Scene_polyhedron_selection_item_priv(this);
1795   d->original_sel_mode = static_cast<Active_handle::Type>(0);
1796   d->operation_mode = -1;
1797 
1798   d->nb_facets = 0;
1799   d->nb_points = 0;
1800   d->nb_lines = 0;
1801   this->setColor(QColor(87,87,87));
1802   d->first_selected = false;
1803   d->is_treated = false;
1804   d->poly_need_update = false;
1805   d->are_temp_buffers_filled = false;
1806   d->poly = nullptr;
1807   d->ready_to_move = false;
1808   do_process = true;
1809   setProperty("no_picking", true);
1810 
1811   setPointContainer(3,
1812                     new Pc(Vi::PROGRAM_NO_SELECTION, false));
1813   for(int i=2; i>=0; --i)
1814   {
1815     setTriangleContainer(i,
1816                          new Tc(Vi::PROGRAM_WITH_LIGHT, false));
1817     setEdgeContainer(i,
1818                      new Ec(Three::mainViewer()->isOpenGL_4_3()
1819                             ? Vi::PROGRAM_SOLID_WIREFRAME
1820                             : Vi::PROGRAM_NO_SELECTION,
1821                             false));
1822     setPointContainer(i,
1823                       new Pc(Vi::PROGRAM_NO_SELECTION, false));
1824   }
1825 }
1826 
Scene_polyhedron_selection_item()1827 Scene_polyhedron_selection_item::Scene_polyhedron_selection_item()
1828   : Scene_polyhedron_item_decorator(nullptr, false)
1829 {
1830   common_constructor();
1831 }
1832 
Scene_polyhedron_selection_item(Scene_face_graph_item * poly_item,QMainWindow * mw)1833 Scene_polyhedron_selection_item::Scene_polyhedron_selection_item(Scene_face_graph_item* poly_item, QMainWindow* mw)
1834   : Scene_polyhedron_item_decorator(nullptr, false)
1835 {
1836   common_constructor();
1837   QString sf = poly_item->property("source filename").toString();
1838   QRegExp rx("\\.(ts$|off$|obj$|ply$|stl$|surf$|vtk$|vtp$|vtu)");
1839   sf.remove(rx);
1840   if(!sf.isEmpty())
1841     setProperty("defaultSaveDir", sf);
1842 
1843   init(poly_item, mw);
1844   invalidateOpenGLBuffers();
1845   compute_normal_maps();
1846 }
1847 
~Scene_polyhedron_selection_item()1848 Scene_polyhedron_selection_item::~Scene_polyhedron_selection_item()
1849 {
1850   delete d;
1851   Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool()){
1852     CGAL::Three::Viewer_interface* viewer = dynamic_cast<CGAL::Three::Viewer_interface*>(v);
1853     viewer->setBindingSelect();
1854   }
1855 }
1856 
setPathSelection(bool b)1857 void Scene_polyhedron_selection_item::setPathSelection(bool b) {
1858   k_ring_selector.setEditMode(b);
1859   d->is_path_selecting = b;
1860   if(d->is_path_selecting){
1861     int ind = 0;
1862     boost::property_map<Face_graph,CGAL::vertex_selection_t>::type vsm =
1863       get(CGAL::vertex_selection,*polyhedron());
1864     for(fg_vertex_descriptor vd : vertices(*polyhedron())){
1865       put(vsm,vd, ind++);
1866     }
1867   }
1868 }
1869 
update_poly()1870 void Scene_polyhedron_selection_item::update_poly()
1871 {
1872   if(d->poly_need_update)
1873     poly_item->invalidateOpenGLBuffers();
1874 }
1875 
resetIsTreated()1876 void Scene_polyhedron_selection_item::resetIsTreated() { d->is_treated = false;}
1877 
invalidateOpenGLBuffers()1878 void Scene_polyhedron_selection_item::invalidateOpenGLBuffers() {
1879 
1880   // do not use decorator function, which calls changed on poly_item which cause deletion of AABB
1881     //  poly_item->invalidateOpenGLBuffers();
1882       are_buffers_filled = false;
1883       d->are_temp_buffers_filled = false;
1884       setBuffersFilled(false);
1885       getTriangleContainer(Priv::Facets)->reset_vbos(ALL);
1886       getTriangleContainer(Priv::Temp_facets)->reset_vbos(ALL);
1887 
1888       getEdgeContainer(Priv::Edges)->reset_vbos(ALL);
1889       getEdgeContainer(Priv::Temp_edges)->reset_vbos(ALL);
1890 
1891       getPointContainer(Priv::Points)->reset_vbos(ALL);
1892       getPointContainer(Priv::Temp_points)->reset_vbos(ALL);
1893       getPointContainer(Priv::Fixed_points)->reset_vbos(ALL);
1894 
1895       Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
1896       {
1897         CGAL::Three::Viewer_interface* viewer =
1898             static_cast<CGAL::Three::Viewer_interface*>(v);
1899         if(viewer == nullptr)
1900           continue;
1901         setBuffersInit(viewer, false);
1902         viewer->update();
1903       }
1904       d->poly = polyhedron();
1905       compute_bbox();
1906       if(d->filtered_graph)
1907       {
1908         delete d->filtered_graph;
1909         d->filtered_graph = nullptr;
1910       }
1911 }
1912 
add_to_selection()1913 void Scene_polyhedron_selection_item::add_to_selection()
1914 {
1915   Q_FOREACH(fg_edge_descriptor ed, temp_selected_edges)
1916   {
1917     selected_edges.insert(ed);
1918     temp_selected_edges.erase(ed);
1919   }
1920   on_Ctrlz_pressed();
1921   invalidateOpenGLBuffers();
1922   Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
1923     v->update();
1924   d->tempInstructions("Path added to selection.",
1925                    "Select two vertices to create the path between them. (1/2)");
1926 }
1927 
save_handleType()1928 void Scene_polyhedron_selection_item::save_handleType()
1929 {
1930   d->original_sel_mode = get_active_handle_type();
1931 }
compute_normal_maps()1932 void Scene_polyhedron_selection_item::compute_normal_maps()
1933 {
1934 
1935   d->face_normals_map.clear();
1936   d->vertex_normals_map.clear();
1937   d->nf_pmap = boost::associative_property_map< CGAL::Unique_hash_map<fg_face_descriptor, EPICK::Vector_3> >(d->face_normals_map);
1938   d->nv_pmap = boost::associative_property_map< CGAL::Unique_hash_map<fg_vertex_descriptor, EPICK::Vector_3> >(d->vertex_normals_map);
1939   PMP::compute_normals(*d->poly, d->nv_pmap, d->nf_pmap);
1940 }
1941 
updateTick()1942 void Scene_polyhedron_selection_item::updateTick()
1943 {
1944     d->ready_to_move = true;
1945     QTimer::singleShot(0,this,SLOT(moveVertex()));
1946 }
1947 
1948 
moveVertex()1949 void Scene_polyhedron_selection_item::moveVertex()
1950 {
1951   if(d->ready_to_move)
1952   {
1953      const CGAL::qglviewer::Vec offset = Three::mainViewer()->offset();
1954     fg_vertex_descriptor vh = *temp_selected_vertices.begin();
1955 
1956     VPmap vpm = get(CGAL::vertex_point,*polyhedron());
1957     put(vpm, vh, Point_3(d->manipulated_frame->position().x-offset.x,
1958                          d->manipulated_frame->position().y-offset.y,
1959                          d->manipulated_frame->position().z-offset.z));
1960     setProperty("need_invalidate_aabb_tree", true);
1961     invalidateOpenGLBuffers();
1962     poly_item->updateVertex(vh);
1963    // poly_item->invalidateOpenGLBuffers();
1964     d->ready_to_move = false;
1965   }
1966 }
1967 
validateMoveVertex()1968 void Scene_polyhedron_selection_item::validateMoveVertex()
1969 {
1970   temp_selected_vertices.clear();
1971   CGAL::QGLViewer* viewer = Three::mainViewer();
1972   k_ring_selector.setEditMode(true);
1973   viewer->setManipulatedFrame(nullptr);
1974   invalidateOpenGLBuffers();
1975   poly_item->itemChanged();
1976   if(property("need_hl_restore").toBool()){
1977     set_highlighting(true);
1978     setProperty("need_hl_restore", false);
1979   }
1980   if(property("need_invalidate_aabb_tree").toBool()){
1981     polyhedron_item()->invalidate_aabb_tree();
1982     setProperty("need_invalidate_aabb_tree", false);
1983   }
1984   Q_EMIT updateInstructions("Select a vertex. (1/2)");
1985 }
1986 
1987 
canAddFace(fg_halfedge_descriptor hc,fg_halfedge_descriptor t)1988 bool Scene_polyhedron_selection_item_priv::canAddFace(fg_halfedge_descriptor hc, fg_halfedge_descriptor t)
1989 {
1990   bool found(false),  is_border_h(false);
1991 
1992   //if the selected halfedge is not a border, stop and signal it.
1993   if(is_border(hc,*polyhedron()))
1994     is_border_h = true;
1995   else if(is_border(opposite(hc,*polyhedron()),*polyhedron()))
1996   {
1997     hc = opposite(hc,*polyhedron());
1998     is_border_h = true;
1999   }
2000   if(!is_border_h)
2001   {
2002     tempInstructions("Edge not selected : no shared border found.",
2003                      "Select the second edge. (2/2)");
2004     return false;
2005   }
2006   //if the halfedges are the same, stop and signal it.
2007   if(hc == t)
2008   {
2009     tempInstructions("Edge not selected : halfedges must be different.",
2010                      "Select the second edge. (2/2)");
2011     return false;
2012   }
2013   //if the halfedges are adjacent, stop and signal it.
2014   if(next(t, *item->polyhedron()) == hc || next(hc, *item->polyhedron()) == t)
2015   {
2016     tempInstructions("Edge not selected : halfedges must not be adjacent.",
2017                      "Select the second edge. (2/2)");
2018     return false;
2019   }
2020 
2021   //if the halfedges are not on the same border, stop and signal it.
2022   fg_halfedge_descriptor iterator = next(t, *item->polyhedron());
2023   while(iterator != t)
2024   {
2025     if(iterator == hc)
2026     {
2027       found = true;
2028       fg_halfedge_descriptor res =
2029           CGAL::Euler::add_face_to_border(t,hc, *item->polyhedron());
2030       fg_face_descriptor resf = face(res, *item->polyhedron());
2031 
2032       if(CGAL::Polygon_mesh_processing::is_degenerate_triangle_face(resf, *item->polyhedron()))
2033       {
2034         CGAL::Euler::remove_face(res, *item->polyhedron());
2035         tempInstructions("Edge not selected : resulting facet is degenerated.",
2036                          "Select the second edge. (2/2)");
2037         return false;
2038       }
2039       break;
2040     }
2041     iterator = next(iterator, *item->polyhedron());
2042   }
2043   if(!found)
2044   {
2045     tempInstructions("Edge not selected : no shared border found.",
2046                      "Select the second edge. (2/2)");
2047     return false;
2048   }
2049   return true;
2050 }
2051 
canAddFaceAndVertex(fg_halfedge_descriptor hc,fg_halfedge_descriptor t)2052 bool Scene_polyhedron_selection_item_priv::canAddFaceAndVertex(fg_halfedge_descriptor hc, fg_halfedge_descriptor t)
2053 {
2054   bool found(false),  is_border_h(false);
2055 
2056   //if the selected halfedge is not a border, stop and signal it.
2057   if(is_border(hc,*polyhedron()))
2058     is_border_h = true;
2059   else if(is_border(opposite(hc,*polyhedron()),*polyhedron()))
2060   {
2061     hc = opposite(hc,*polyhedron());
2062     is_border_h = true;
2063   }
2064   if(!is_border_h)
2065   {
2066     tempInstructions("Edge not selected : no shared border found.",
2067                      "Select the second edge. (2/2)");
2068     return false;
2069   }
2070   //if the halfedges are the same, stop and signal it.
2071   if(hc == t)
2072   {
2073     tempInstructions("Edge not selected : halfedges must be different.",
2074                      "Select the second edge. (2/2)");
2075     return false;
2076   }
2077 
2078   //if the halfedges are not on the same border, stop and signal it.
2079   fg_halfedge_descriptor iterator = next(t, *item->polyhedron());
2080   while(iterator != t)
2081   {
2082     if(iterator == hc)
2083     {
2084       found = true;
2085       CGAL::Euler::add_vertex_and_face_to_border(t,hc, *item->polyhedron());
2086       break;
2087     }
2088     iterator = next(iterator, *item->polyhedron());
2089   }
2090   if(!found)
2091   {
2092     tempInstructions("Edge not selected : no shared border found.",
2093                      "Select the second edge. (2/2)");
2094     return false;
2095   }
2096   return true;
2097 }
2098 
clearHL()2099 void Scene_polyhedron_selection_item::clearHL()
2100 {
2101   HL_selected_edges.clear();
2102   HL_selected_facets.clear();
2103   HL_selected_vertices.clear();
2104   getTriangleContainer(Priv::HL_facets)->reset_vbos(ALL);
2105   getEdgeContainer(Priv::HL_edges)->reset_vbos(ALL);
2106   getPointContainer(Priv::HL_points)->reset_vbos(ALL);
2107   setBuffersFilled(false);
2108   d->are_HL_buffers_filled = false;
2109   Q_EMIT itemChanged();
2110 }
selected_HL(const std::set<fg_vertex_descriptor> & m)2111 void Scene_polyhedron_selection_item::selected_HL(const std::set<fg_vertex_descriptor>& m)
2112 {
2113   HL_selected_edges.clear();
2114   HL_selected_facets.clear();
2115   HL_selected_vertices.clear();
2116   for(auto it : m)
2117     HL_selected_vertices.insert(it);
2118   getTriangleContainer(Priv::HL_facets)->reset_vbos(ALL);
2119   getEdgeContainer(Priv::HL_edges)->reset_vbos(ALL);
2120   getPointContainer(Priv::HL_points)->reset_vbos(ALL);
2121   setBuffersFilled(false);
2122   d->are_HL_buffers_filled = false;
2123   Q_EMIT itemChanged();
2124 }
2125 
selected_HL(const std::set<fg_face_descriptor> & m)2126 void Scene_polyhedron_selection_item::selected_HL(const std::set<fg_face_descriptor>& m)
2127 {
2128   HL_selected_edges.clear();
2129   HL_selected_facets.clear();
2130   HL_selected_vertices.clear();
2131   for(auto it : m)
2132     HL_selected_facets.insert(it);
2133   getTriangleContainer(Priv::HL_facets)->reset_vbos(ALL);
2134   getEdgeContainer(Priv::HL_edges)->reset_vbos(ALL);
2135   getPointContainer(Priv::HL_points)->reset_vbos(ALL);
2136   setBuffersFilled(false);
2137   d->are_HL_buffers_filled = false;
2138   Q_EMIT itemChanged();
2139 }
2140 
selected_HL(const std::set<fg_edge_descriptor> & m)2141 void Scene_polyhedron_selection_item::selected_HL(const std::set<fg_edge_descriptor>& m)
2142 {
2143   HL_selected_edges.clear();
2144   HL_selected_facets.clear();
2145   HL_selected_vertices.clear();
2146   for(auto it : m)
2147     HL_selected_edges.insert(it);
2148   getTriangleContainer(Priv::HL_facets)->reset_vbos(ALL);
2149   getEdgeContainer(Priv::HL_edges)->reset_vbos(ALL);
2150   getPointContainer(Priv::HL_points)->reset_vbos(ALL);
2151   d->are_HL_buffers_filled = false;
2152   setBuffersFilled(false);
2153   Q_EMIT itemChanged();
2154 }
2155 
reset_numbers()2156 void Scene_polyhedron_selection_item::reset_numbers()
2157 {
2158   d->num_faces = num_faces(*poly_item->polyhedron());
2159   d->num_vertices = num_vertices(*poly_item->polyhedron());
2160   d->num_edges = num_edges(*poly_item->polyhedron());
2161 }
2162 
init(Scene_face_graph_item * poly_item,QMainWindow * mw)2163 void Scene_polyhedron_selection_item::init(Scene_face_graph_item* poly_item, QMainWindow* mw)
2164 {
2165   this->poly_item = poly_item;
2166   d->poly =poly_item->polyhedron();
2167   d->num_faces = num_faces(*poly_item->polyhedron());
2168   d->num_vertices = num_vertices(*poly_item->polyhedron());
2169   d->num_edges = num_edges(*poly_item->polyhedron());
2170   connect(poly_item, SIGNAL(item_is_about_to_be_changed()), this, SLOT(poly_item_changed()));
2171   //parameters type must be of the same name here and there, so they must be hardcoded.
2172   connect(&k_ring_selector, SIGNAL(selected(const std::set<fg_vertex_descriptor>&)), this,
2173     SLOT(selected(const std::set<fg_vertex_descriptor>&)));
2174 
2175   connect(&k_ring_selector, SIGNAL(selected(const std::set<fg_face_descriptor>&)), this,
2176     SLOT(selected(const std::set<fg_face_descriptor>&)));
2177 
2178   connect(&k_ring_selector, SIGNAL(selected(const std::set<fg_edge_descriptor>&)), this,
2179     SLOT(selected(const std::set<fg_edge_descriptor>&)));
2180 
2181   connect(&k_ring_selector, SIGNAL(selected_HL(const std::set<fg_vertex_descriptor>&)), this,
2182           SLOT(selected_HL(const std::set<fg_vertex_descriptor>&)));
2183 
2184   connect(&k_ring_selector, SIGNAL(selected_HL(const std::set<fg_face_descriptor>&)), this,
2185           SLOT(selected_HL(const std::set<fg_face_descriptor>&)));
2186 
2187   connect(&k_ring_selector, SIGNAL(selected_HL(const std::set<fg_edge_descriptor>&)), this,
2188           SLOT(selected_HL(const std::set<fg_edge_descriptor>&)));
2189   connect(&k_ring_selector, SIGNAL(clearHL()), this,
2190           SLOT(clearHL()));
2191   connect(poly_item, SIGNAL(selection_done()), this, SLOT(update_poly()));
2192   connect(&k_ring_selector, SIGNAL(endSelection()), this,SLOT(endSelection()));
2193   connect(&k_ring_selector, SIGNAL(toogle_insert(bool)), this,SLOT(toggle_insert(bool)));
2194   connect(&k_ring_selector,SIGNAL(isCurrentlySelected(Scene_facegraph_item_k_ring_selection*)), this, SIGNAL(isCurrentlySelected(Scene_facegraph_item_k_ring_selection*)));
2195    k_ring_selector.init(poly_item, mw, Active_handle::VERTEX, -1);
2196   connect(&k_ring_selector, SIGNAL(resetIsTreated()), this, SLOT(resetIsTreated()));
2197 
2198   connect(poly_item, &Scene_surface_mesh_item::itemChanged, this, [this](){
2199     std::size_t new_num_faces = num_faces(*this->poly_item->face_graph());
2200     std::size_t new_num_vertices = num_vertices(*this->poly_item->face_graph());
2201     std::size_t new_num_edges = num_edges(*this->poly_item->face_graph());
2202 
2203     if(new_num_faces != d->num_faces
2204        && !d->keep_selection_valid.testFlag(Facet))
2205     {
2206       selected_facets.clear();
2207       d->num_faces = new_num_faces ;
2208     }
2209     if(new_num_vertices!= d->num_vertices
2210        && !d->keep_selection_valid.testFlag(Vertex))
2211     {
2212       selected_vertices.clear();
2213       d->num_vertices = new_num_vertices ;
2214     }
2215     if(new_num_edges!= d->num_edges
2216        && !d->keep_selection_valid.testFlag(Edge))
2217     {
2218       selected_edges.clear();
2219       d->num_edges = new_num_edges ;
2220     }
2221     invalidateOpenGLBuffers();
2222     redraw();
2223   });
2224   d->manipulated_frame = new ManipulatedFrame();
2225   Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
2226     v->installEventFilter(this);
2227   mw->installEventFilter(this);
2228   connect(mw, SIGNAL(newViewerCreated(QObject*)),
2229           this, SLOT(connectNewViewer(QObject*)));
2230 }
2231 
select_all_NT()2232 void Scene_polyhedron_selection_item::select_all_NT()
2233 {
2234   for(fg_face_descriptor fd : faces(*polyhedron())){
2235     if(! is_triangle(halfedge(fd,*polyhedron()), *polyhedron()))
2236     selected_facets.insert(fd);
2237   }
2238   invalidateOpenGLBuffers();
2239   Q_EMIT itemChanged();
2240 }
2241 
selection_changed(bool)2242 void Scene_polyhedron_selection_item::selection_changed(bool)
2243 {
2244   bool do_bind_select = true;
2245   if(qobject_cast<Scene_polyhedron_selection_item*>(
2246        Three::scene()->item(Three::scene()->mainSelectionIndex())))
2247     do_bind_select = false;
2248   if(do_bind_select)
2249     Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool()){
2250       CGAL::Three::Viewer_interface* viewer = dynamic_cast<CGAL::Three::Viewer_interface*>(v);
2251       viewer->setBindingSelect();
2252     }
2253     else
2254     Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool()){
2255       CGAL::Three::Viewer_interface* viewer = dynamic_cast<CGAL::Three::Viewer_interface*>(v);
2256       viewer->setNoBinding();
2257     }
2258 }
2259 
printPrimitiveId(QPoint p,CGAL::Three::Viewer_interface * viewer)2260 void Scene_polyhedron_selection_item::printPrimitiveId(QPoint p, CGAL::Three::Viewer_interface* viewer)
2261 {
2262   d->item->polyhedron_item()->printPrimitiveId(p, viewer);
2263 }
2264 
printVertexIds() const2265 bool Scene_polyhedron_selection_item::printVertexIds() const
2266 {
2267   return d->item->polyhedron_item()->printVertexIds();
2268 }
2269 
printEdgeIds() const2270 bool Scene_polyhedron_selection_item::printEdgeIds() const
2271 {
2272   return d->item->polyhedron_item()->printEdgeIds();
2273 }
2274 
printFaceIds() const2275 bool Scene_polyhedron_selection_item::printFaceIds() const
2276 {
2277   return d->item->polyhedron_item()->printFaceIds();
2278 }
2279 
printAllIds()2280 void Scene_polyhedron_selection_item::printAllIds()
2281 {
2282   d->item->polyhedron_item()->printAllIds();
2283 }
2284 
testDisplayId(double x,double y,double z,CGAL::Three::Viewer_interface * viewer) const2285 bool Scene_polyhedron_selection_item::testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface* viewer)const
2286 {
2287   return d->item->polyhedron_item()->testDisplayId(x, y, z, viewer);
2288 }
2289 
shouldDisplayIds(CGAL::Three::Scene_item * current_item) const2290 bool Scene_polyhedron_selection_item::shouldDisplayIds(CGAL::Three::Scene_item *current_item) const
2291 {
2292   return d->item->polyhedron_item() == current_item;
2293 }
2294 
select_boundary()2295 void Scene_polyhedron_selection_item::select_boundary()
2296 {
2297   Face_graph* fg = polyhedron_item()->face_graph();
2298   for(fg_halfedge_descriptor hd : halfedges(*fg))
2299   {
2300     if(is_border_edge(hd, *fg))
2301     {
2302       selected_edges.insert(edge(hd, *fg));
2303     }
2304   }
2305   invalidateOpenGLBuffers();
2306   redraw();
2307 }
2308 
2309 QString
toolTip() const2310 Scene_polyhedron_selection_item::toolTip() const
2311 {
2312   if(!poly_item || !poly_item->polyhedron())
2313     return QString();
2314 
2315   return QObject::tr("<p>Selection <b>%1</b> (mode: %5, color: %6)</p>"
2316                      "<p>Number of vertices: %2<br />"
2317                      "Number of edges: %3<br />"
2318                      "Number of faces: %4</p>")
2319       .arg(this->name())
2320       .arg(selected_vertices.size())
2321       .arg(selected_edges.size())
2322       .arg(selected_facets.size())
2323       .arg(this->renderingModeName())
2324       .arg(this->color().name());
2325 }
2326 
initializeBuffers(Viewer_interface * v) const2327 void Scene_polyhedron_selection_item::initializeBuffers(Viewer_interface *v) const
2328 {
2329     d->initializeBuffers(v);
2330     d->initialize_temp_buffers(v);
2331     d->initialize_HL_buffers(v);
2332 }
2333 
computeElements() const2334 void Scene_polyhedron_selection_item::computeElements() const
2335 {
2336   if(!are_buffers_filled)
2337   {
2338     d->computeElements();
2339     are_buffers_filled = true;
2340   }
2341   if(!d->are_temp_buffers_filled)
2342   {
2343     d->compute_temp_elements();
2344     d->are_temp_buffers_filled = true;
2345   }
2346   if(!d->are_HL_buffers_filled)
2347   {
2348     d->compute_HL_elements();
2349     d->are_HL_buffers_filled = true;
2350   }
2351   setBuffersFilled(true);
2352 }
2353 
computeStats(int type)2354 QString Scene_polyhedron_selection_item::computeStats(int type)
2355 {
2356   if(!d->filtered_graph)
2357   {
2358     d->filtered_graph = new CGAL::Face_filtered_graph<SMesh>(*d->poly, selected_facets);
2359   }
2360   double minl, maxl, meanl, midl;
2361   unsigned int number_of_null_length_edges;
2362   switch (type)
2363   {
2364   case MIN_LENGTH:
2365   case MAX_LENGTH:
2366   case MID_LENGTH:
2367   case MEAN_LENGTH:
2368   case NB_NULL_LENGTH:
2369     if(selected_edges.size() == 0)
2370       return QString("n/a");
2371     else
2372       edges_length(d->poly, selected_edges, minl, maxl, meanl, midl, number_of_null_length_edges);
2373   }
2374 
2375   double mini, maxi, ave;
2376   switch (type)
2377   {
2378   case MIN_ANGLE:
2379   case MAX_ANGLE:
2380   case MEAN_ANGLE:
2381     if(selected_facets.size() == 0)
2382       return QString("n/a");
2383     else
2384       angles(d->poly, selected_facets, mini, maxi, ave);
2385   }
2386   double min_area, max_area, med_area, mean_area;
2387   switch (type)
2388   {
2389   case MIN_AREA:
2390   case MAX_AREA:
2391   case MEAN_AREA:
2392   case MED_AREA:
2393     if(selected_facets.size() == 0)
2394       return QString("n/a");
2395     else{
2396       if(!is_triangle_mesh(*d->poly))
2397       {
2398         return QString("n/a");
2399       }
2400       faces_area(d->poly, selected_facets, min_area, max_area, mean_area, med_area);
2401     }
2402   }
2403   double min_altitude, min_ar, max_ar, mean_ar;
2404   switch (type)
2405   {
2406   case MIN_ALTITUDE:
2407   case MIN_ASPECT_RATIO:
2408   case MAX_ASPECT_RATIO:
2409   case MEAN_ASPECT_RATIO:
2410     if(selected_facets.size() == 0)
2411       return QString("n/a");
2412     else
2413     {
2414       if(!is_triangle_mesh(*d->poly))
2415       {
2416         return QString("n/a");
2417       }
2418       faces_aspect_ratio(d->poly, selected_facets,min_altitude, min_ar, max_ar, mean_ar);
2419     }
2420   }
2421 
2422   switch(type)
2423   {
2424   case NB_VERTICES:
2425   {
2426     std::set<fg_vertex_descriptor> total_vertices;
2427     for(auto v : selected_vertices)
2428     {
2429       total_vertices.insert(v);
2430     }
2431     for(auto e : selected_edges)
2432     {
2433       total_vertices.insert(target(e, *d->poly));
2434       total_vertices.insert(source(e, *d->poly));
2435     }
2436     for(auto f : selected_facets)
2437     {
2438       for (auto v : CGAL::vertices_around_face(halfedge(f, *d->poly), *d->poly))
2439       {
2440         total_vertices.insert(v);
2441       }
2442     }
2443     return QString::number(total_vertices.size());
2444   }
2445   case NB_FACETS:
2446     return QString::number(selected_facets.size());
2447 
2448   case NB_CONNECTED_COMPOS:
2449   {
2450     // Extract the part n°0 of the partition into a new, independent mesh
2451     if(selected_facets.size() == 0)
2452       return QString("n/a");
2453     boost::vector_property_map<int,
2454         boost::property_map<SMesh, boost::face_index_t>::type>
2455         fccmap(get(boost::face_index, *d->filtered_graph));
2456 
2457     return QString::number(CGAL::Polygon_mesh_processing::connected_components(*d->filtered_graph, fccmap));
2458   }
2459 
2460   case NB_BORDER_EDGES:
2461   {
2462     int i=0;
2463     for(halfedge_descriptor hd : halfedges(*d->poly))
2464     {
2465       if(is_border(hd, *d->poly)
2466          && selected_edges.find(edge(hd, *d->poly)) != selected_edges.end())
2467         ++i;
2468     }
2469     return QString::number(i);
2470   }
2471 
2472   case NB_EDGES:{
2473     std::set<fg_edge_descriptor> total_edges;
2474     for(auto e : selected_edges)
2475     {
2476       total_edges.insert(e);
2477     }
2478     for(auto f : selected_facets)
2479     {
2480       for (auto e : CGAL::edges_around_face(halfedge(f, *d->poly), *d->poly))
2481       {
2482         total_edges.insert(e);
2483       }
2484     }
2485     return QString::number(total_edges.size());
2486   }
2487 
2488   case VOLUME:
2489     return QString("n/a");
2490     break;
2491 
2492   case GENUS:
2493     return QString("n/a");
2494     break;
2495   case NB_DEGENERATED_FACES:
2496   {
2497     if(is_triangle_mesh(*d->poly))
2498     {
2499       if(selected_facets.size() == 0)
2500         return QString("n/a");
2501       return QString::number(nb_degenerate_faces(d->filtered_graph));
2502     }
2503     else
2504       return QString("n/a");
2505   }
2506   case AREA:
2507   {
2508     if(is_triangle_mesh(*d->poly))
2509     {
2510       if(selected_facets.size() == 0)
2511         return QString("n/a");
2512       return QString::number(CGAL::Polygon_mesh_processing::area(*d->filtered_graph));
2513     }
2514     else
2515       return QString("n/a");
2516   }
2517 
2518   case SELFINTER:
2519   {
2520     if(selected_facets.size() == 0)
2521       return QString("n/a");
2522     if(is_triangle_mesh(*d->poly)){
2523       bool self_intersect
2524         = CGAL::Polygon_mesh_processing::does_self_intersect<CGAL::Parallel_if_available_tag>(*(d->poly));
2525       if (self_intersect)
2526         return QString("Yes");
2527       else
2528         return QString("No");
2529     }
2530     return QString("n/a");
2531   }
2532   case MIN_LENGTH:
2533     return QString::number(minl);
2534   case MAX_LENGTH:
2535     return QString::number(maxl);
2536   case MID_LENGTH:
2537     return QString::number(midl);
2538   case MEAN_LENGTH:
2539     return QString::number(meanl);
2540   case NB_NULL_LENGTH:
2541     return QString::number(number_of_null_length_edges);
2542 
2543   case MIN_ANGLE:
2544     return QString::number(mini);
2545   case MAX_ANGLE:
2546     return QString::number(maxi);
2547   case MEAN_ANGLE:
2548     return QString::number(ave);
2549   case HOLES:
2550   {
2551     return QString("n/a");
2552   }
2553 
2554   case MIN_AREA:
2555     return QString::number(min_area);
2556   case MAX_AREA:
2557     return QString::number(max_area);
2558   case MED_AREA:
2559     return QString::number(med_area);
2560   case MEAN_AREA:
2561     return QString::number(mean_area);
2562   case MIN_ALTITUDE:
2563     return QString::number(min_altitude);
2564   case MIN_ASPECT_RATIO:
2565     return QString::number(min_ar);
2566   case MAX_ASPECT_RATIO:
2567     return QString::number(max_ar);
2568   case MEAN_ASPECT_RATIO:
2569     return QString::number(mean_ar);
2570   case IS_PURE_TRIANGLE:
2571     if(selected_facets.size() == 0)
2572       return QString("n/a");
2573     else
2574     {
2575       if(is_triangle_mesh(*d->poly))
2576         return QString("yes");
2577       else
2578         return QString("no");
2579     }
2580   case IS_PURE_QUAD:
2581   {
2582     if(selected_facets.size() == 0)
2583             return QString("n/a");
2584     if (is_quad_mesh(*d->filtered_graph))
2585       return QString("yes");
2586     else
2587       return QString("no");
2588   }
2589 
2590   }//end switch
2591   return QString();
2592 }
2593 
header() const2594 CGAL::Three::Scene_item::Header_data Scene_polyhedron_selection_item::header() const
2595 {
2596   CGAL::Three::Scene_item::Header_data data;
2597   //categories
2598 
2599   data.categories.append(std::pair<QString,int>(QString("Properties"),10));
2600   data.categories.append(std::pair<QString,int>(QString("Faces"),10));
2601   data.categories.append(std::pair<QString,int>(QString("Edges"),7));
2602   data.categories.append(std::pair<QString,int>(QString("Angles"),2));
2603 
2604 
2605   //titles
2606   data.titles.append(QString("#Vertices"));
2607   data.titles.append(QString("#Connected Components"));
2608   data.titles.append(QString("#Border Edges"));
2609   data.titles.append(QString("Pure Triangle"));
2610   data.titles.append(QString("Pure Quad"));
2611   data.titles.append(QString("#Degenerate Faces"));
2612   data.titles.append(QString("Connected Components of the Boundary"));
2613   data.titles.append(QString("Area"));
2614   data.titles.append(QString("Volume"));
2615   data.titles.append(QString("Self-Intersecting"));
2616   data.titles.append(QString("#Faces"));
2617   data.titles.append(QString("Min Area"));
2618   data.titles.append(QString("Max Area"));
2619   data.titles.append(QString("Median Area"));
2620   data.titles.append(QString("Mean Area"));
2621   data.titles.append(QString("Min Altitude"));
2622   data.titles.append(QString("Min Aspect-Ratio"));
2623   data.titles.append(QString("Max Aspect-Ratio"));
2624   data.titles.append(QString("Mean Aspect-Ratio"));
2625   data.titles.append(QString("Genus"));
2626   data.titles.append(QString("#Edges"));
2627   data.titles.append(QString("Minimum Length"));
2628   data.titles.append(QString("Maximum Length"));
2629   data.titles.append(QString("Median Length"));
2630   data.titles.append(QString("Mean Length"));
2631   data.titles.append(QString("#Degenerate Edges"));
2632   data.titles.append(QString("Minimum"));
2633   data.titles.append(QString("Maximum"));
2634   data.titles.append(QString("Average"));
2635   return data;
2636 }
2637 
2638 
updateDisplayedIds(QEvent * e)2639 void Scene_polyhedron_selection_item::updateDisplayedIds(QEvent* e)
2640 {
2641   if(e->type() == QEvent::MouseButtonRelease )
2642   {
2643     QMouseEvent* mouse_event = static_cast<QMouseEvent*>(e);
2644     if((mouse_event->button() == Qt::RightButton || mouse_event->button() == Qt::MiddleButton)
2645        && temp_selected_vertices.size() == 1) {
2646       fg_vertex_descriptor vh = *temp_selected_vertices.begin();
2647       poly_item->updateIds(vh);
2648     }
2649   }
2650 }
2651 
poly_item_changed()2652 void Scene_polyhedron_selection_item::poly_item_changed()
2653 {
2654   if(d->keep_selection_valid != None)
2655   {
2656     Update_indices_visitor visitor(selected_vertices,
2657                                    selected_edges,
2658                                    selected_facets,
2659                                    *polyhedron());
2660     polyhedron()->collect_garbage(visitor);
2661   }
2662   else
2663   {
2664     if(!d->keep_selection_valid.testFlag(Vertex))
2665       remove_erased_handles<fg_vertex_descriptor>();
2666     if(!d->keep_selection_valid.testFlag(Edge))
2667       remove_erased_handles<fg_edge_descriptor>();
2668     if(!d->keep_selection_valid.testFlag(Facet))
2669       remove_erased_handles<fg_face_descriptor>();
2670   }
2671   compute_normal_maps();
2672 }
2673 
setKeepSelectionValid(SelectionTypes type)2674 void Scene_polyhedron_selection_item::setKeepSelectionValid(SelectionTypes type)
2675 {
2676   d->keep_selection_valid = type;
2677 }
2678