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